bes  Updated for version 3.20.13
PPTServer.cc
1 // PPTServer.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 <unistd.h>
36 #include <string>
37 #include <sstream>
38 #include <cstdlib>
39 
40 #include "PPTServer.h"
41 #include "ServerExitConditions.h"
42 #include "BESInternalError.h"
43 #include "BESInternalFatalError.h"
44 #include "BESSyntaxUserError.h"
45 #include "PPTProtocolNames.h"
46 #include "SocketListener.h"
47 #include "ServerHandler.h"
48 #include "Socket.h"
49 #include "TheBESKeys.h"
50 #include "BESLog.h"
51 #include "BESDebug.h"
52 
53 using std::string;
54 using std::ostringstream;
55 using std::endl;
56 using std::ostream;
57 
58 
59 #if defined HAVE_OPENSSL && defined NOTTHERE
60 #include "SSLServer.h"
61 #endif
62 #define MODULE "ppt"
63 #define prolog string("PPTServer::").append(__func__).append("() - ")
64 
65 #define PPT_SERVER_DEFAULT_TIMEOUT 1
66 
67 PPTServer::PPTServer(ServerHandler *handler, SocketListener *listener, bool isSecure) :
68  PPTConnection(PPT_SERVER_DEFAULT_TIMEOUT), _handler(handler), _listener(listener), _secure(isSecure)
69 {
70  if (!handler) {
71  string err("Null handler passed to PPTServer");
72  throw BESInternalError(err, __FILE__, __LINE__);
73  }
74  if (!listener) {
75  string err("Null listener passed to PPTServer");
76  throw BESInternalError(err, __FILE__, __LINE__);
77  }
78 #if !defined HAVE_OPENSSL && defined NOTTHERE
79  if( _secure )
80  {
81  string err("Server requested to be secure but OpenSSL is not built in");
82  throw BESInternalError( err, __FILE__, __LINE__ );
83  }
84 #endif
85 
86  // get the certificate and key file information
87  if (_secure) {
88  get_secure_files();
89  }
90 }
91 
92 #if 0
93 PPTServer::~PPTServer()
94 {
95 }
96 #endif
97 
98 void PPTServer::get_secure_files()
99 {
100  bool found = false;
101  TheBESKeys::TheKeys()->get_value("BES.ServerCertFile", _cfile, found);
102  if (!found || _cfile.empty()) {
103  string err = "Unable to determine server certificate file.";
104  throw BESSyntaxUserError(err, __FILE__, __LINE__);
105  }
106 
107  found = false;
108  TheBESKeys::TheKeys()->get_value("BES.ServerCertAuthFile", _cafile, found);
109  if (!found || _cafile.empty()) {
110  string err = "Unable to determine server certificate authority file.";
111  throw BESSyntaxUserError(err, __FILE__, __LINE__);
112  }
113 
114  found = false;
115  TheBESKeys::TheKeys()->get_value("BES.ServerKeyFile", _kfile, found);
116  if (!found || _kfile.empty()) {
117  string err = "Unable to determine server key file.";
118  throw BESSyntaxUserError(err, __FILE__, __LINE__);
119  }
120 
121  found = false;
122  string portstr;
123  TheBESKeys::TheKeys()->get_value("BES.ServerSecurePort", portstr, found);
124  if (!found || portstr.empty()) {
125  string err = "Unable to determine secure connection port.";
126  throw BESSyntaxUserError(err, __FILE__, __LINE__);
127  }
128  _securePort = atoi(portstr.c_str());
129  if (!_securePort) {
130  string err = (string) "Unable to determine secure connection port " + "from string " + portstr;
131  throw BESSyntaxUserError(err, __FILE__, __LINE__);
132  }
133 }
134 
141 {
142  _mySock = _listener->accept();
143 
144  if (_mySock) {
145  if (_mySock->allowConnection() == true) {
146  // welcome the client
147  BESDEBUG(MODULE, prolog << "Calling welcomeClient()" << endl);
148  if (welcomeClient() != -1) {
149 
150  incr_num_children();
151  BESDEBUG(MODULE, prolog << "number of children: " << get_num_children() << endl);
152 
153  // now hand it off to the handler
154  _handler->handle(this);
155 
156  // Added this call to close - when the PPTServer class is used by
157  // a server that gets a number of connections on the same port,
158  // one per command, not closing the sockets after a command results
159  // in lots of sockets in the 'CLOSE_WAIT' status.
160  _mySock->close();
161  }
162  }
163  else {
164  BESDEBUG(MODULE, prolog << "allowConnection() is FALSE! Closing Socket. " << endl);
165  _mySock->close();
166  }
167  }
168 }
169 
170 void PPTServer::closeConnection()
171 {
172  if (_mySock) _mySock->close();
173 }
174 
175 int PPTServer::welcomeClient()
176 {
177  const unsigned int ppt_buffer_size = 64;
178  char inBuff[ppt_buffer_size + 1];
179 
180  // Doing a non blocking read in case the connection is being initiated
181  // by a non-bes client. Don't want this to block. pcw - 3/5/07
182  // int bytesRead = _mySock->receive( inBuff, ppt_buffer_size ) ;
183  //
184  // We are receiving handshaking tokens, so the buffer doesn't need to be
185  // all that big. pcw - 05/31/08
186 
187  // The non-blocking read user here was the cause of problems reported in
188  // tickets #823, #1525, #1551, #2023 and #2025. Using a blocking read
189  // fixed the problem. 2/27/14 jhrg.
190  //
191  // int bytesRead = readBufferNonBlocking(inBuff, ppt_buffer_size);
192 
193  int bytesRead = readBuffer(inBuff, ppt_buffer_size);
194 
195  BESDEBUG(MODULE, prolog << "bytesRead: " << bytesRead << endl);
196 
197  // if the read of the initial connection fails or blocks, then return
198  if (bytesRead == -1) {
199  _mySock->close();
200  return -1;
201  }
202 
203  string status(inBuff, bytesRead);
204 
205  if (status != PPT_CLIENT_TESTING_CONNECTION) {
206  /* If cannot negotiate with the client then we don't want to exit
207  * by throwing an exception, we want to return and let the caller
208  * clean up the connection
209  */
210 
211  string err = "PPT cannot negotiate, client started the connection with " + status;
212  send(err);
213  BESDEBUG(MODULE, prolog << "Sent '" << err << "' to PPT client." << endl);
214 
215  // I think it would be better to send back a previously defined
216  // constant like this... but I don't want to break client code.
217  // jhrg 2/27/14
218  // send(PPT_PROTOCOL_UNDEFINED);
219  // BESDEBUG(MODULE, prolog << "Sent " << PPT_PROTOCOL_UNDEFINED << " to PPT client." << endl);
220 
221  _mySock->close();
222  return -1;
223  }
224 
225  if (!_secure) {
226  send(PPT_SERVER_CONNECTION_OK);
227  BESDEBUG(MODULE, prolog << "Sent " << PPT_SERVER_CONNECTION_OK << " to PPT client." << endl);
228  }
229  else {
230  authenticateClient();
231  }
232 
233  return 0;
234 }
235 
236 void PPTServer::authenticateClient()
237 {
238 #if defined HAVE_OPENSSL && defined NOTTHERE
239  BESDEBUG( MODULE, prolog << "Requiring secure connection: port = " << _securePort << endl );
240  // let the client know that it needs to authenticate
241  send(PPT_SERVER_AUTHENTICATE );
242 
243  // wait for the client request for the secure port
244  // We are waiting for a ppt tocken requesting the secure port number.
245  // The buffer doesn't need to be all that big. pcw - 05/31/08
246  const unsigned int ppt_buffer_size = 64;
247  // char *inBuff = new char[ppt_buffer_size]; jhrg 3/5/14
248  char inBuff[ppt_buffer_size];
249  int bytesRead = _mySock->receive( inBuff, ppt_buffer_size );
250  string portRequest( inBuff, bytesRead );
251  // delete [] inBuff; jhrg 3/5/14
252  if( portRequest != PPT_CLIENT_REQUEST_AUTHPORT )
253  throw BESInternalError( string("Secure connection ... expecting request for port client requested ") + portRequest, __FILE__, __LINE__ );
254 
255  // send the secure port number back to the client
256  ostringstream portResponse;
257  portResponse << _securePort << PPT_COMPLETE_DATA_TRANSMISSION;
258  send( portResponse.str() );
259 
260  // create a secure server object and authenticate
261  SSLServer server( _securePort, _cfile, _cafile, _kfile );
262  server.initConnection();
263  server.closeConnection();
264 
265  // if it authenticates, good, if not, an exception is thrown, no need to
266  // do anything else here.
267 #else
268  throw BESInternalError("Authentication requested for this server but OpenSSL is not built into the server", __FILE__, __LINE__);
269 #endif
270 }
271 
278 void PPTServer::dump(ostream &strm) const
279 {
280  strm << BESIndent::LMarg << "PPTServer::dump - (" << (void *) this << ")" << endl;
281  BESIndent::Indent();
282  if (_handler) {
283  strm << BESIndent::LMarg << "server handler:" << endl;
284  BESIndent::Indent();
285  _handler->dump(strm);
286  BESIndent::UnIndent();
287  }
288  else {
289  strm << BESIndent::LMarg << "server handler: null" << endl;
290  }
291  if (_listener) {
292  strm << BESIndent::LMarg << "listener:" << endl;
293  BESIndent::Indent();
294  _listener->dump(strm);
295  BESIndent::UnIndent();
296  }
297  else {
298  strm << BESIndent::LMarg << "listener: null" << endl;
299  }
300  strm << BESIndent::LMarg << "secure? " << _secure << endl;
301  if (_secure) {
302  BESIndent::Indent();
303  strm << BESIndent::LMarg << "cert file: " << _cfile << endl;
304  strm << BESIndent::LMarg << "cert authority file: " << _cafile << endl;
305  strm << BESIndent::LMarg << "key file: " << _kfile << endl;
306  strm << BESIndent::LMarg << "secure port: " << _securePort << endl;
307  BESIndent::UnIndent();
308  }
309  PPTConnection::dump(strm);
310  BESIndent::UnIndent();
311 }
312 
exception thrown if internal error encountered
error thrown if there is a user syntax error in the request or any other user error
virtual int readBuffer(char *inBuff, const unsigned int buff_size)
read a buffer of data from the socket
virtual void send(const std::string &buffer)
sends the buffer to the socket
virtual void dump(std::ostream &strm) const
dumps information about this object
void initConnection() override
Definition: PPTServer.cc:140
void dump(std::ostream &strm) const override
dumps information about this object
Definition: PPTServer.cc:278
virtual void dump(std::ostream &strm) const =0
dump the contents of this object to the specified ostream
virtual void dump(std::ostream &strm) const
dumps information about this object
virtual Socket * accept()
void get_value(const std::string &s, std::string &val, bool &found)
Retrieve the value of a given key, if set.
Definition: TheBESKeys.cc:340
static TheBESKeys * TheKeys()
Definition: TheBESKeys.cc:71