bes  Updated for version 3.17.0
SocketListener.cc
1 // SocketListener.cc
2 
3 // This file is part of bes, A C++ back-end server implementation framework
4 // for the OPeNDAP Data Access Protocol.
5 
6 // Copyright (c) 2004-2009 University Corporation for Atmospheric Research
7 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 //
23 // You can contact University Corporation for Atmospheric Research at
24 // 3080 Center Green Drive, Boulder, CO 80301
25 
26 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005
27 // Please read the full copyright statement in the file COPYRIGHT_UCAR.
28 //
29 // Authors:
30 // pwest Patrick West <pwest@ucar.edu>
31 // jgarcia Jose Garcia <jgarcia@ucar.edu>
32 
33 #include <ctype.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 
37 // Added for CentOS 6 jhrg
38 #include <sys/wait.h>
39 
40 // Added for OSX 10.9 jhrg
41 #include <sys/select.h>
42 
43 #include <cstring>
44 #include <cerrno>
45 
46 #include "SocketListener.h"
47 #include "BESInternalError.h"
48 #include "Socket.h"
49 #include "SocketConfig.h"
50 #include "BESDebug.h"
51 
52 //extern volatile int bes_num_children; // defined in PPTServer.cc jhrg 3/5/14
53 //extern string bes_exit_message(int cpid, int stat);
54 
55 SocketListener::SocketListener() :
56  _accepting(false)
57 {
58 }
59 
60 SocketListener::~SocketListener()
61 {
62 }
63 
64 void SocketListener::listen(Socket *s)
65 {
66  if (_accepting)
67  throw BESInternalError("Already accepting connections, no more sockets can be added", __FILE__, __LINE__);
68 
69  if (s && !s->isConnected() && !s->isListening()) {
70  s->listen();
71  _socket_list[s->getSocketDescriptor()] = s;
72  }
73  else {
74  if (!s)
75  throw BESInternalError("null socket passed", __FILE__, __LINE__);
76  else if (s->isConnected())
77  throw BESInternalError("socket already connected, cannot listen", __FILE__, __LINE__);
78  else if (s->isListening())
79  throw BESInternalError("socket already listening", __FILE__, __LINE__);
80  }
81 }
82 
84 Socket *
86 {
87  BESDEBUG("ppt", "SocketListener::accept() - START" << endl);
88 
89  fd_set read_fd;
90  FD_ZERO(&read_fd);
91 
92  int maxfd = 0;
93  for (Socket_citer i = _socket_list.begin(), e = _socket_list.end(); i != e; i++) {
94  Socket *s_ptr = (*i).second;
95  if (s_ptr->getSocketDescriptor() > maxfd) maxfd = s_ptr->getSocketDescriptor();
96  FD_SET(s_ptr->getSocketDescriptor(), &read_fd);
97  }
98 
99  struct timeval timeout;
100  timeout.tv_sec = 120;
101  timeout.tv_usec = 0;
102  int status = select(maxfd + 1, &read_fd, (fd_set*) NULL, (fd_set*) NULL, &timeout);
103  if (status < 0) {
104  // left over and not needed. jhrg 10/14/15
105  // while (select(maxfd + 1, &read_fd, (fd_set*) NULL, (fd_set*) NULL, &timeout) < 0) {
106  switch (errno) {
107  case EAGAIN: // rerun select on interrupted calls, ...
108  BESDEBUG("ppt2", "SocketListener::accept() - select encountered EAGAIN" << endl);
109  // This case and the one below used to just 'break' so that the select call
110  // above would run again. I modified it to return null so that the caller could
111  // do other things, like process the results of signals.
112  return 0;
113 
114  case EINTR:
115  BESDEBUG("ppt2", "SocketListener::accept() - select encountered EINTR" << endl);
116  return 0;
117 
118  default:
119  throw BESInternalError(string("select: ") + strerror(errno), __FILE__, __LINE__);
120  }
121  }
122 
123  BESDEBUG("ppt", "SocketListener::accept() - select() completed without error." << endl);
124 
125  for (Socket_citer i = _socket_list.begin(), e = _socket_list.end(); i != e; i++) {
126  Socket *s_ptr = (*i).second;
127  if (FD_ISSET( s_ptr->getSocketDescriptor(), &read_fd )) {
128  struct sockaddr from;
129  socklen_t len_from = sizeof(from);
130 
131  BESDEBUG("ppt", "SocketListener::accept() - Attempting to accept on "<< s_ptr->getIp() << ":"
132  << s_ptr->getPort() << endl);
133 
134  int msgsock;
135  while ((msgsock = ::accept(s_ptr->getSocketDescriptor(), &from, &len_from)) < 0) {
136  if (errno == EINTR) {
137  continue;
138  }
139  else {
140  throw BESInternalError(string("accept: ") + strerror(errno), __FILE__, __LINE__);
141  }
142  }
143 
144  BESDEBUG("ppt", "SocketListener::accept() - END (returning new Socket)" << endl);
145  return s_ptr->newSocket(msgsock, (struct sockaddr *) &from);
146  }
147  }
148 
149  BESDEBUG("ppt", "SocketListener::accept() - END (returning 0)" << endl);
150  return 0;
151 }
152 
159 void SocketListener::dump(ostream &strm) const
160 {
161  strm << BESIndent::LMarg << "SocketListener::dump - (" << (void *) this << ")" << endl;
162  BESIndent::Indent();
163  if (_socket_list.size()) {
164  strm << BESIndent::LMarg << "registered sockets:" << endl;
165  Socket_citer i = _socket_list.begin();
166  Socket_citer ie = _socket_list.end();
167  for (; i != ie; i++) {
168  strm << BESIndent::LMarg << "socket: " << (*i).first;
169  Socket *s_ptr = (*i).second;
170  s_ptr->dump(strm);
171  }
172  }
173  else {
174  strm << BESIndent::LMarg << "registered sockets: none" << endl;
175  }
176  BESIndent::UnIndent();
177 }
178 
Definition: Socket.h:42
exception thrown if inernal error encountered
virtual void dump(ostream &strm) const
dumps information about this object
Definition: Socket.cc:134
virtual Socket * accept()
virtual void dump(ostream &strm) const
dumps information about this object