bes  Updated for version 3.20.6
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 "config.h"
34 
35 #include <string>
36 #include <ctype.h>
37 #include <cstring>
38 #include <cerrno>
39 
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 
43 // Added for CentOS 6 jhrg
44 #include <sys/wait.h>
45 
46 // Added for OSX 10.9 jhrg
47 #include <sys/select.h>
48 
49 #include "SocketListener.h"
50 #include "BESInternalError.h"
51 #include "Socket.h"
52 #include "SocketConfig.h"
53 #include "BESDebug.h"
54 
55 //extern volatile int bes_num_children; // defined in PPTServer.cc jhrg 3/5/14
56 //extern string bes_exit_message(int cpid, int stat);
57 
58 using namespace std;
59 
60 SocketListener::SocketListener() :
61  _accepting(false)
62 {
63 }
64 
65 SocketListener::~SocketListener()
66 {
67 }
68 
69 void SocketListener::listen(Socket *s)
70 {
71  if (_accepting)
72  throw BESInternalError("Already accepting connections, no more sockets can be added", __FILE__, __LINE__);
73 
74  if (s && !s->isConnected() && !s->isListening()) {
75  s->listen();
76  _socket_list[s->getSocketDescriptor()] = s;
77  }
78  else {
79  if (!s)
80  throw BESInternalError("null socket passed", __FILE__, __LINE__);
81  else if (s->isConnected())
82  throw BESInternalError("socket already connected, cannot listen", __FILE__, __LINE__);
83  else if (s->isListening())
84  throw BESInternalError("socket already listening", __FILE__, __LINE__);
85  }
86 }
87 
89 Socket *
91 {
92  BESDEBUG("ppt", "SocketListener::accept() - START" << endl);
93 
94  fd_set read_fd;
95  FD_ZERO(&read_fd);
96 
97  int maxfd = 0;
98  for (Socket_citer i = _socket_list.begin(), e = _socket_list.end(); i != e; i++) {
99  Socket *s_ptr = (*i).second;
100  if (s_ptr->getSocketDescriptor() > maxfd) maxfd = s_ptr->getSocketDescriptor();
101  FD_SET(s_ptr->getSocketDescriptor(), &read_fd);
102  }
103 
104  struct timeval timeout;
105  timeout.tv_sec = 120;
106  timeout.tv_usec = 0;
107  int status = select(maxfd + 1, &read_fd, (fd_set*) NULL, (fd_set*) NULL, &timeout);
108  if (status < 0) {
109  // left over and not needed. jhrg 10/14/15
110  // while (select(maxfd + 1, &read_fd, (fd_set*) NULL, (fd_set*) NULL, &timeout) < 0) {
111  switch (errno) {
112  case EAGAIN: // rerun select on interrupted calls, ...
113  BESDEBUG("ppt2", "SocketListener::accept() - select encountered EAGAIN" << endl);
114  // This case and the one below used to just 'break' so that the select call
115  // above would run again. I modified it to return null so that the caller could
116  // do other things, like process the results of signals.
117  return 0;
118 
119  case EINTR:
120  BESDEBUG("ppt2", "SocketListener::accept() - select encountered EINTR" << endl);
121  return 0;
122 
123  default:
124  throw BESInternalError(string("select: ") + strerror(errno), __FILE__, __LINE__);
125  }
126  }
127 
128  BESDEBUG("ppt", "SocketListener::accept() - select() completed without error." << endl);
129 
130  for (Socket_citer i = _socket_list.begin(), e = _socket_list.end(); i != e; i++) {
131  Socket *s_ptr = (*i).second;
132  if (FD_ISSET( s_ptr->getSocketDescriptor(), &read_fd )) {
133  struct sockaddr from;
134  socklen_t len_from = sizeof(from);
135 
136  BESDEBUG("ppt", "SocketListener::accept() - Attempting to accept on "<< s_ptr->getIp() << ":"
137  << s_ptr->getPort() << endl);
138 
139  int msgsock;
140  while ((msgsock = ::accept(s_ptr->getSocketDescriptor(), &from, &len_from)) < 0) {
141  if (errno == EINTR) {
142  continue;
143  }
144  else {
145  throw BESInternalError(string("accept: ") + strerror(errno), __FILE__, __LINE__);
146  }
147  }
148 
149  BESDEBUG("ppt", "SocketListener::accept() - END (returning new Socket)" << endl);
150  return s_ptr->newSocket(msgsock, (struct sockaddr *) &from);
151  }
152  }
153 
154  BESDEBUG("ppt", "SocketListener::accept() - END (returning 0)" << endl);
155  return 0;
156 }
157 
164 void SocketListener::dump(ostream &strm) const
165 {
166  strm << BESIndent::LMarg << "SocketListener::dump - (" << (void *) this << ")" << endl;
167  BESIndent::Indent();
168  if (_socket_list.size()) {
169  strm << BESIndent::LMarg << "registered sockets:" << endl;
170  Socket_citer i = _socket_list.begin();
171  Socket_citer ie = _socket_list.end();
172  for (; i != ie; i++) {
173  strm << BESIndent::LMarg << "socket: " << (*i).first;
174  Socket *s_ptr = (*i).second;
175  s_ptr->dump(strm);
176  }
177  }
178  else {
179  strm << BESIndent::LMarg << "registered sockets: none" << endl;
180  }
181  BESIndent::UnIndent();
182 }
183 
Socket
Definition: Socket.h:42
Socket::dump
virtual void dump(std::ostream &strm) const
dumps information about this object
Definition: Socket.cc:137
SocketListener::dump
virtual void dump(std::ostream &strm) const
dumps information about this object
Definition: SocketListener.cc:164
SocketListener::accept
virtual Socket * accept()
Definition: SocketListener.cc:90
BESInternalError
exception thrown if internal error encountered
Definition: BESInternalError.h:43