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