bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
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
58using namespace std;
59
60#define MODULE "ppt"
61#define prolog string("SocketListener::").append(__func__).append("() - ")
62
63SocketListener::SocketListener() :
64 _accepting(false)
65{
66}
67
68SocketListener::~SocketListener()
69{
70}
71
72void SocketListener::listen(Socket *s)
73{
74 if (_accepting)
75 throw BESInternalError("Already accepting connections, no more sockets can be added", __FILE__, __LINE__);
76
77 if (s && !s->isConnected() && !s->isListening()) {
78 s->listen();
79 _socket_list[s->getSocketDescriptor()] = s;
80 }
81 else {
82 if (!s)
83 throw BESInternalError("null socket passed", __FILE__, __LINE__);
84 else if (s->isConnected())
85 throw BESInternalError("socket already connected, cannot listen", __FILE__, __LINE__);
86 else if (s->isListening())
87 throw BESInternalError("socket already listening", __FILE__, __LINE__);
88 }
89}
90
92Socket *
94{
95 BESDEBUG(MODULE, prolog << "START" << endl);
96
97 fd_set read_fd;
98 FD_ZERO(&read_fd);
99
100 int maxfd = 0;
101 for (Socket_citer i = _socket_list.begin(), e = _socket_list.end(); i != e; i++) {
102 Socket *s_ptr = (*i).second;
103 if (s_ptr->getSocketDescriptor() > maxfd) maxfd = s_ptr->getSocketDescriptor();
104 FD_SET(s_ptr->getSocketDescriptor(), &read_fd);
105 }
106
107 struct timeval timeout;
108 timeout.tv_sec = 120;
109 timeout.tv_usec = 0;
110 int status = select(maxfd + 1, &read_fd, (fd_set*) NULL, (fd_set*) NULL, &timeout);
111 if (status < 0) {
112 // left over and not needed. jhrg 10/14/15
113 // while (select(maxfd + 1, &read_fd, (fd_set*) NULL, (fd_set*) NULL, &timeout) < 0) {
114 switch (errno) {
115 case EAGAIN: // rerun select on interrupted calls, ...
116 BESDEBUG(MODULE, prolog << "select() encountered EAGAIN" << endl);
117 // This case and the one below used to just 'break' so that the select call
118 // above would run again. I modified it to return null so that the caller could
119 // do other things, like process the results of signals.
120 return 0;
121
122 case EINTR:
123 BESDEBUG(MODULE, prolog << "select() encountered EINTR" << endl);
124 return 0;
125
126 default:
127 throw BESInternalError(string("select(): ") + strerror(errno), __FILE__, __LINE__);
128 }
129 }
130
131 BESDEBUG(MODULE, prolog << "select() completed without error." << endl);
132
133 for (Socket_citer i = _socket_list.begin(), e = _socket_list.end(); i != e; i++) {
134 Socket *s_ptr = (*i).second;
135 if (FD_ISSET( s_ptr->getSocketDescriptor(), &read_fd )) {
136 struct sockaddr from;
137 socklen_t len_from = sizeof(from);
138
139 BESDEBUG(MODULE, prolog << "Attempting to accept on "<< s_ptr->getIp() << ":"
140 << s_ptr->getPort() << endl);
141
142 int msgsock;
143 while ((msgsock = ::accept(s_ptr->getSocketDescriptor(), &from, &len_from)) < 0) {
144 if (errno == EINTR) {
145 continue;
146 }
147 else {
148 throw BESInternalError(string("accept: ") + strerror(errno), __FILE__, __LINE__);
149 }
150 }
151
152 BESDEBUG(MODULE, prolog << "END (returning new Socket)" << endl);
153 return s_ptr->newSocket(msgsock, (struct sockaddr *) &from);
154 }
155 }
156
157 BESDEBUG(MODULE, prolog << "END (returning 0)" << endl);
158 return 0;
159}
160
167void SocketListener::dump(ostream &strm) const
168{
169 strm << BESIndent::LMarg << "SocketListener::dump - (" << (void *) this << ")" << endl;
170 BESIndent::Indent();
171 if (_socket_list.size()) {
172 strm << BESIndent::LMarg << "registered sockets:" << endl;
173 Socket_citer i = _socket_list.begin();
174 Socket_citer ie = _socket_list.end();
175 for (; i != ie; i++) {
176 strm << BESIndent::LMarg << "socket: " << (*i).first;
177 Socket *s_ptr = (*i).second;
178 s_ptr->dump(strm);
179 }
180 }
181 else {
182 strm << BESIndent::LMarg << "registered sockets: none" << endl;
183 }
184 BESIndent::UnIndent();
185}
186
exception thrown if internal error encountered
virtual void dump(std::ostream &strm) const
dumps information about this object
virtual Socket * accept()
virtual void dump(std::ostream &strm) const
dump the contents of this object to the specified ostream