PPTServer.cc

Go to the documentation of this file.
00001 // PPTServer.cc
00002 
00003 // This file is part of bes, A C++ back-end server implementation framework
00004 // for the OPeNDAP Data Access Protocol.
00005 
00006 // Copyright (c) 2004-2009 University Corporation for Atmospheric Research
00007 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
00008 //
00009 // This library is free software; you can redistribute it and/or
00010 // modify it under the terms of the GNU Lesser General Public
00011 // License as published by the Free Software Foundation; either
00012 // version 2.1 of the License, or (at your option) any later version.
00013 //
00014 // This library is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017 // Lesser General Public License for more details.
00018 //
00019 // You should have received a copy of the GNU Lesser General Public
00020 // License along with this library; if not, write to the Free Software
00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 //
00023 // You can contact University Corporation for Atmospheric Research at
00024 // 3080 Center Green Drive, Boulder, CO 80301
00025 
00026 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005
00027 // Please read the full copyright statement in the file COPYRIGHT_UCAR.
00028 //
00029 // Authors:
00030 //      pwest       Patrick West <pwest@ucar.edu>
00031 //      jgarcia     Jose Garcia <jgarcia@ucar.edu>
00032 
00033 #include <config.h>
00034 
00035 #include <string>
00036 #include <sstream>
00037 #include <cstdlib>
00038 
00039 using std::string ;
00040 using std::ostringstream ;
00041 
00042 #include "PPTServer.h"
00043 #include "BESInternalError.h"
00044 #include "BESSyntaxUserError.h"
00045 #include "PPTProtocol.h"
00046 #include "SocketListener.h"
00047 #include "ServerHandler.h"
00048 #include "Socket.h"
00049 #include "TheBESKeys.h"
00050 #include "BESDebug.h"
00051 
00052 #include "config.h"
00053 #ifdef HAVE_OPENSSL
00054 #include "SSLServer.h"
00055 #endif
00056 
00057 #define PPT_SERVER_DEFAULT_TIMEOUT 1
00058 
00059 PPTServer::PPTServer( ServerHandler *handler,
00060                       SocketListener *listener,
00061                       bool isSecure )
00062     : PPTConnection( PPT_SERVER_DEFAULT_TIMEOUT),
00063       _handler( handler ),
00064       _listener( listener ),
00065       _secure( isSecure )
00066 {
00067     if( !handler )
00068     {
00069         string err( "Null handler passed to PPTServer" ) ;
00070         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00071     }
00072     if( !listener )
00073     {
00074         string err( "Null listener passed to PPTServer" ) ;
00075         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00076     }
00077 #ifndef HAVE_OPENSSL
00078     if( _secure )
00079     {
00080         string err("Server requested to be secure but OpenSSL is not built in");
00081         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00082     }
00083 #endif
00084 
00085     // get the certificate and key file information
00086     if( _secure )
00087     {
00088         get_secure_files() ;
00089     }
00090 }
00091 
00092 PPTServer::~PPTServer()
00093 {
00094 }
00095 
00096 void
00097 PPTServer::get_secure_files()
00098 {
00099     bool found = false ;
00100     TheBESKeys::TheKeys()->get_value( "BES.ServerCertFile", _cfile, found ) ;
00101     if( !found || _cfile.empty() )
00102     {
00103         string err = "Unable to determine server certificate file." ;
00104         throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00105     }
00106 
00107     found = false ;
00108     TheBESKeys::TheKeys()->get_value( "BES.ServerCertAuthFile", _cafile, found);
00109     if( !found || _cafile.empty() )
00110     {
00111         string err = "Unable to determine server certificate authority file." ;
00112         throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00113     }
00114 
00115     found = false ;
00116     TheBESKeys::TheKeys()->get_value( "BES.ServerKeyFile", _kfile, found ) ;
00117     if( !found || _kfile.empty() )
00118     {
00119         string err = "Unable to determine server key file." ;
00120         throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00121     }
00122 
00123     found = false ;
00124     string portstr ;
00125     TheBESKeys::TheKeys()->get_value( "BES.ServerSecurePort", portstr, found ) ;
00126     if( !found || portstr.empty() )
00127     {
00128         string err = "Unable to determine secure connection port." ;
00129         throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00130     }
00131     _securePort = atoi( portstr.c_str() ) ;
00132     if( !_securePort )
00133     {
00134         string err = (string)"Unable to determine secure connection port "
00135                      + "from string " + portstr ;
00136         throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00137     }
00138 }
00139 
00145 void
00146 PPTServer::initConnection()
00147 {
00148     for(;;)
00149     {
00150         _mySock = _listener->accept() ;
00151         if( _mySock )
00152         {
00153             if( _mySock->allowConnection() == true )
00154             {
00155                 // welcome the client
00156                 if( welcomeClient( ) != -1 )
00157                 {
00158                     // now hand it off to the handler
00159                     _handler->handle( this ) ;
00160                 }
00161             }
00162             else
00163             {
00164                _mySock->close();
00165             }
00166         }
00167     }
00168 }
00169 
00170 void
00171 PPTServer::closeConnection()
00172 {
00173     if( _mySock ) _mySock->close() ;
00174 }
00175 
00176 int
00177 PPTServer::welcomeClient()
00178 {
00179     // Doing a non blocking read in case the connection is being initiated
00180     // by a non-bes client. Don't want this to block. pcw - 3/5/07
00181     // int bytesRead = _mySock->receive( inBuff, ppt_buffer_size ) ;
00182     //
00183     // We are receiving handshaking tokens, so the buffer doesn't need to be
00184     // all that big. pcw - 05/31/08
00185     unsigned int ppt_buffer_size = 64 ;
00186     char *inBuff = new char[ppt_buffer_size+1] ;
00187     int bytesRead = readBufferNonBlocking( inBuff, ppt_buffer_size ) ;
00188 
00189     // if the read of the initial connection fails or blocks, then return
00190     if( bytesRead == -1 )
00191     {
00192         _mySock->close() ;
00193         delete [] inBuff ;
00194         return -1 ;
00195     }
00196 
00197     string status( inBuff, bytesRead ) ;
00198     delete [] inBuff ;
00199 
00200     if( status != PPTProtocol::PPTCLIENT_TESTING_CONNECTION )
00201     {
00202         /* If cannot negotiate with the client then we don't want to exit
00203          * by throwing an exception, we want to return and let the caller
00204          * clean up the connection
00205          */
00206         string err( "PPT cannot negotiate, " ) ;
00207         err += " client started the connection with " + status ;
00208         BESDEBUG( "ppt", err << endl ) ;
00209         //throw BESInternalError( err, __FILE__, __LINE__ ) ;
00210         send( err ) ;
00211         _mySock->close() ;
00212         return -1 ;
00213     }
00214 
00215     if( !_secure )
00216     {
00217         send( PPTProtocol::PPTSERVER_CONNECTION_OK ) ;
00218     }
00219     else
00220     {
00221         authenticateClient() ;
00222     }
00223 
00224     return  0 ;
00225 }
00226 
00227 void
00228 PPTServer::authenticateClient()
00229 {
00230 #ifdef HAVE_OPENSSL
00231     BESDEBUG( "ppt", "requiring secure connection: port = "
00232                      << _securePort << endl ) ;
00233     // let the client know that it needs to authenticate
00234     send( PPTProtocol::PPTSERVER_AUTHENTICATE ) ;
00235 
00236     // wait for the client request for the secure port
00237     // We are waiting for a ppt tocken requesting the secure port number.
00238     // The buffer doesn't need to be all that big. pcw - 05/31/08
00239     unsigned int ppt_buffer_size = 64 ;
00240     char *inBuff = new char[ppt_buffer_size] ;
00241     int bytesRead = _mySock->receive( inBuff, ppt_buffer_size ) ;
00242     string portRequest( inBuff, bytesRead ) ;
00243     delete [] inBuff ;
00244     if( portRequest != PPTProtocol::PPTCLIENT_REQUEST_AUTHPORT )
00245     {
00246         string err( "Secure connection ... expecting request for port" ) ;
00247         err += " client requested " + portRequest ;
00248         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00249     }
00250 
00251     // send the secure port number back to the client
00252     ostringstream portResponse ;
00253     portResponse << _securePort << PPTProtocol::PPT_COMPLETE_DATA_TRANSMITION ;
00254     send( portResponse.str() ) ;
00255 
00256     // create a secure server object and authenticate
00257     SSLServer server( _securePort, _cfile, _cafile, _kfile ) ;
00258     server.initConnection() ;
00259     server.closeConnection() ;
00260 
00261     // if it authenticates, good, if not, an exception is thrown, no need to
00262     // do anything else here.
00263 #else
00264     string err = (string)"Authentication requested for this server "
00265                  + "but OpenSSL is not built into the server" ;
00266     throw BESInternalError( err, __FILE__, __LINE__ ) ;
00267 #endif
00268 }
00269 
00276 void
00277 PPTServer::dump( ostream &strm ) const
00278 {
00279     strm << BESIndent::LMarg << "PPTServer::dump - ("
00280                              << (void *)this << ")" << endl ;
00281     BESIndent::Indent() ;
00282     if( _handler )
00283     {
00284         strm << BESIndent::LMarg << "server handler:" << endl ;
00285         BESIndent::Indent() ;
00286         _handler->dump( strm ) ;
00287         BESIndent::UnIndent() ;
00288     }
00289     else
00290     {
00291         strm << BESIndent::LMarg << "server handler: null" << endl ;
00292     }
00293     if( _listener )
00294     {
00295         strm << BESIndent::LMarg << "listener:" << endl ;
00296         BESIndent::Indent() ;
00297         _listener->dump( strm ) ;
00298         BESIndent::UnIndent() ;
00299     }
00300     else
00301     {
00302         strm << BESIndent::LMarg << "listener: null" << endl ;
00303     }
00304     strm << BESIndent::LMarg << "secure? " << _secure << endl ;
00305     if( _secure )
00306     {
00307         BESIndent::Indent() ;
00308         strm << BESIndent::LMarg << "cert file: " << _cfile << endl ;
00309         strm << BESIndent::LMarg << "cert authority file: " << _cafile << endl ;
00310         strm << BESIndent::LMarg << "key file: " << _kfile << endl ;
00311         strm << BESIndent::LMarg << "secure port: " << _securePort << endl ;
00312         BESIndent::UnIndent() ;
00313     }
00314     PPTConnection::dump( strm ) ;
00315     BESIndent::UnIndent() ;
00316 }
00317 

Generated on Wed May 12 09:53:08 2010 for OPeNDAP Hyrax Back End Server (BES) by  doxygen 1.4.7