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