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
53using std::string;
54using std::ostringstream;
55using std::endl;
56using 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
67PPTServer::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
93PPTServer::~PPTServer()
94{
95}
96#endif
97
98void 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
170void PPTServer::closeConnection()
171{
172 if (_mySock) _mySock->close();
173}
174
175int 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
236void 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
278void 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 }
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