bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
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
92void 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(MODULE, prolog << "Calling welcomeClient()" << endl);
142 if (welcomeClient() != -1) {
143
144 incr_num_children();
145 BESDEBUG(MODULE, prolog << "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(MODULE, prolog << "allowConnection() is FALSE! Closing Socket. " << endl);
159 _mySock->close();
160 }
161 }
162}
163
164void PPTServer::closeConnection()
165{
166 if (_mySock) _mySock->close();
167}
168
169int 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(MODULE, prolog << "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 != PPT_CLIENT_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(MODULE, prolog << "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(PPT_PROTOCOL_UNDEFINED);
213 // BESDEBUG(MODULE, prolog << "Sent " << PPT_PROTOCOL_UNDEFINED << " to PPT client." << endl);
214
215 _mySock->close();
216 return -1;
217 }
218
219 if (!_secure) {
220 send(PPT_SERVER_CONNECTION_OK);
221 BESDEBUG(MODULE, prolog << "Sent " << PPT_SERVER_CONNECTION_OK << " to PPT client." << endl);
222 }
223 else {
224 authenticateClient();
225 }
226
227 return 0;
228}
229
230void PPTServer::authenticateClient()
231{
232#if defined HAVE_OPENSSL && defined NOTTHERE
233 BESDEBUG( MODULE, prolog << "Requiring secure connection: port = " << _securePort << endl );
234 // let the client know that it needs to authenticate
235 send(PPT_SERVER_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 != PPT_CLIENT_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 << PPT_COMPLETE_DATA_TRANSMISSION;
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
272void 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 }
304 BESIndent::UnIndent();
305}
306
exception thrown if internal error encountered
void send(const std::string &buffer) override
sends the buffer to the socket
virtual int readBuffer(char *inBuff, const unsigned int buff_size)
read a buffer of data from the socket
void dump(std::ostream &strm) const override
dumps information about this object
void initConnection() override
Definition PPTServer.cc:134
void dump(std::ostream &strm) const override
dumps information about this object
Definition PPTServer.cc:272
void get_value(const std::string &s, std::string &val, bool &found)
Retrieve the value of a given key, if set.
static TheBESKeys * TheKeys()
Access to the singleton.
Definition TheBESKeys.cc:85