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,2005 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 <string>
00034 #include <sstream>
00035 
00036 using std::string ;
00037 using std::ostringstream ;
00038 
00039 #include "PPTServer.h"
00040 #include "PPTException.h"
00041 #include "PPTProtocol.h"
00042 #include "SocketListener.h"
00043 #include "ServerHandler.h"
00044 #include "Socket.h"
00045 #include "TheBESKeys.h"
00046 #include "BESDebug.h"
00047 
00048 #include "config.h"
00049 #ifdef HAVE_OPENSSL
00050 #include "SSLServer.h"
00051 #endif
00052 
00053 #define PPT_SERVER_DEFAULT_TIMEOUT 1
00054 
00055 PPTServer::PPTServer( ServerHandler *handler,
00056                       SocketListener *listener,
00057                       bool isSecure )
00058     : PPTConnection( PPT_SERVER_DEFAULT_TIMEOUT),
00059       _handler( handler ),
00060       _listener( listener ),
00061       _secure( isSecure )
00062 {
00063     if( !handler )
00064     {
00065         string err( "Null handler passed to PPTServer" ) ;
00066         throw PPTException( err, __FILE__, __LINE__ ) ;
00067     }
00068     if( !listener )
00069     {
00070         string err( "Null listener passed to PPTServer" ) ;
00071         throw PPTException( err, __FILE__, __LINE__ ) ;
00072     }
00073 #ifndef HAVE_OPENSSL
00074     if( _secure )
00075     {
00076         string err("Server requested to be secure but OpenSSL is not built in");
00077         throw PPTException( err, __FILE__, __LINE__ ) ;
00078     }
00079 #endif
00080 
00081     // get the certificate and key file information
00082     if( _secure )
00083     {
00084         get_secure_files() ;
00085     }
00086 }
00087 
00088 PPTServer::~PPTServer()
00089 {
00090 }
00091 
00092 void
00093 PPTServer::get_secure_files()
00094 {
00095     bool found = false ;
00096     _cfile = TheBESKeys::TheKeys()->get_key( "BES.ServerCertFile", found ) ;
00097     if( !found || _cfile.empty() )
00098     {
00099         throw PPTException( "Unable to determine server certificate file.",
00100                             __FILE__, __LINE__ ) ;
00101     }
00102 
00103     _kfile = TheBESKeys::TheKeys()->get_key( "BES.ServerKeyFile", found ) ;
00104     if( !found || _kfile.empty() )
00105     {
00106         throw PPTException( "Unable to determine server key file.",
00107                             __FILE__, __LINE__ ) ;
00108     }
00109 
00110     string portstr = TheBESKeys::TheKeys()->get_key( "BES.ServerSecurePort",
00111                                                      found ) ;
00112     if( !found || portstr.empty() )
00113     {
00114         throw PPTException( "Unable to determine secure connection port.",
00115                             __FILE__, __LINE__ ) ;
00116     }
00117     _securePort = atoi( portstr.c_str() ) ;
00118     if( !_securePort )
00119     {
00120         string err = (string)"Unable to determine secure connection port "
00121                      + "from string " + portstr ;
00122         throw PPTException( err, __FILE__, __LINE__ ) ;
00123     }
00124 }
00125 
00126 
00132 void
00133 PPTServer::initConnection()
00134 {
00135     for(;;)
00136     {
00137         _mySock = _listener->accept() ;
00138         if( _mySock )
00139         {
00140             // welcome the client
00141             if( welcomeClient( ) != -1 )
00142             {
00143                 // now hand it off to the handler
00144                 _handler->handle( this ) ;
00145             }
00146         }
00147     }
00148 }
00149 
00150 void
00151 PPTServer::closeConnection()
00152 {
00153     if( _mySock ) _mySock->close() ;
00154 }
00155 
00156 int
00157 PPTServer::welcomeClient()
00158 {
00159     char *inBuff = new char[PPT_PROTOCOL_BUFFER_SIZE] ;
00160     /* Doing a non blocking read in case the connection is being initiated
00161      * by a non-bes client. Don't want this to block. pcw - 3/5/07
00162     int bytesRead = _mySock->receive( inBuff, PPT_PROTOCOL_BUFFER_SIZE ) ;
00163      */
00164     int bytesRead = readBufferNonBlocking( inBuff ) ;
00165 
00166     // if the read of the initial connection fails or blocks, then return
00167     if( bytesRead == -1 )
00168     {
00169         _mySock->close() ;
00170         return -1 ;
00171     }
00172 
00173     string status( inBuff, bytesRead ) ;
00174     delete [] inBuff ;
00175     if( status != PPTProtocol::PPTCLIENT_TESTING_CONNECTION )
00176     {
00177         /* If can not negotiate with the client then we don't want to exit
00178          * by throwing an exception, we want to return and let the caller
00179          * clean up the connection
00180          */
00181         string err( "PPT Can not negotiate, " ) ;
00182         err += " client started the connection with " + status ;
00183         BESDEBUG( err )
00184         //throw PPTException( err, __FILE__, __LINE__ ) ;
00185         _mySock->send( err, 0, err.length() ) ;
00186         _mySock->close() ;
00187         return -1 ;
00188     }
00189 
00190     if( !_secure )
00191     {
00192         int len = PPTProtocol::PPTSERVER_CONNECTION_OK.length() ;
00193         _mySock->send( PPTProtocol::PPTSERVER_CONNECTION_OK, 0, len ) ;
00194     }
00195     else
00196     {
00197         authenticateClient() ;
00198     }
00199 
00200     return  0 ;
00201 }
00202 
00203 void
00204 PPTServer::authenticateClient()
00205 {
00206 #ifdef HAVE_OPENSSL
00207     BESDEBUG( "requiring secure connection: port = " << _securePort << endl )
00208     // let the client know that it needs to authenticate
00209     int len = PPTProtocol::PPTSERVER_AUTHENTICATE.length() ;
00210     _mySock->send( PPTProtocol::PPTSERVER_AUTHENTICATE, 0, len ) ;
00211 
00212     // wait for the client request for the secure port
00213     char *inBuff = new char[PPT_PROTOCOL_BUFFER_SIZE] ;
00214     int bytesRead = _mySock->receive( inBuff, PPT_PROTOCOL_BUFFER_SIZE ) ;
00215     string portRequest( inBuff, bytesRead ) ;
00216     delete [] inBuff ;
00217     if( portRequest != PPTProtocol::PPTCLIENT_REQUEST_AUTHPORT )
00218     {
00219         string err( "Secure connection ... expecting request for port" ) ;
00220         err += " client requested " + portRequest ;
00221         throw PPTException( err, __FILE__, __LINE__ ) ;
00222     }
00223 
00224     // send the secure port number back to the client
00225     ostringstream portResponse ;
00226     portResponse << _securePort << PPTProtocol::PPT_COMPLETE_DATA_TRANSMITION ;
00227     len = portResponse.str().length() ;
00228     _mySock->send( portResponse.str(), 0, len ) ;
00229 
00230     // create a secure server object and authenticate
00231     SSLServer server( _securePort, _cfile, _kfile ) ;
00232     server.initConnection() ;
00233     server.closeConnection() ;
00234 
00235     // if it authenticates, good, if not, an exception is thrown, no need to
00236     // do anything else here.
00237 #else
00238     throw PPTException( "Authentication requrested for this server but OpenSSL is not built into the server", __FILE__, __LINE__ ) ;
00239 #endif
00240 }
00241 
00248 void
00249 PPTServer::dump( ostream &strm ) const
00250 {
00251     strm << BESIndent::LMarg << "PPTServer::dump - ("
00252                              << (void *)this << ")" << endl ;
00253     BESIndent::Indent() ;
00254     if( _handler )
00255     {
00256         strm << BESIndent::LMarg << "server handler:" << endl ;
00257         BESIndent::Indent() ;
00258         _handler->dump( strm ) ;
00259         BESIndent::UnIndent() ;
00260     }
00261     else
00262     {
00263         strm << BESIndent::LMarg << "server handler: null" << endl ;
00264     }
00265     ServerHandler *             _handler ;
00266     if( _listener )
00267     {
00268         strm << BESIndent::LMarg << "listener:" << endl ;
00269         BESIndent::Indent() ;
00270         _listener->dump( strm ) ;
00271         BESIndent::UnIndent() ;
00272     }
00273     else
00274     {
00275         strm << BESIndent::LMarg << "listener: null" << endl ;
00276     }
00277     strm << BESIndent::LMarg << "secure? " << _secure << endl ;
00278     PPTConnection::dump( strm ) ;
00279     BESIndent::UnIndent() ;
00280 }
00281 

Generated on Wed Aug 29 03:24:05 2007 for OPeNDAP Back End Server (BES) by  doxygen 1.5.2