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