OPeNDAP Hyrax Back End Server (BES) Updated for version 3.8.3

PPTClient.cc

Go to the documentation of this file.
00001 // PPTClient.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 <string>
00034 #include <iostream>
00035 #include <sstream>
00036 
00037 using std::string ;
00038 using std::cerr ;
00039 using std::cout ;
00040 using std::endl ;
00041 using std::ostringstream ;
00042 
00043 #include "PPTClient.h"
00044 #include "TcpSocket.h"
00045 #include "UnixSocket.h"
00046 #include "PPTProtocol.h"
00047 #include "BESInternalError.h"
00048 #include "BESSyntaxUserError.h"
00049 #include "TheBESKeys.h"
00050 
00051 #include "config.h"
00052 #ifdef HAVE_OPENSSL
00053 #include "SSLClient.h"
00054 #endif
00055 
00056 PPTClient::PPTClient( const string &hostStr, int portVal, int timeout )
00057     : PPTConnection( timeout ),
00058       _connected( false ),
00059       _host( hostStr )
00060 {
00061     // connect to the specified host at the specified socket to handle the
00062     // secure connection
00063     _mySock = new TcpSocket( hostStr, portVal ) ;
00064     _mySock->connect() ;
00065     _connected = _mySock->isConnected();
00066 }
00067     
00068 PPTClient::PPTClient( const string &unix_socket, int timeout )
00069     : PPTConnection( timeout ),
00070       _connected( false )
00071 {
00072     // connect to the specified unix socket to handle the secure connection
00073     _mySock = new UnixSocket( unix_socket ) ;
00074     _mySock->connect() ;
00075     _connected = true ;
00076 }
00077 
00078 void
00079 PPTClient::get_secure_files()
00080 {
00081     bool found = false ;
00082     TheBESKeys::TheKeys()->get_value( "BES.ClientCertFile", _cfile, found ) ;
00083     if( !found || _cfile.empty() )
00084     {
00085         string err = "Unable to determine client certificate file." ;
00086         throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00087     }
00088 
00089     found = false ;
00090     TheBESKeys::TheKeys()->get_value( "BES.ClientCertAuthFile", _cafile, found);
00091     if( !found || _cafile.empty() )
00092     {
00093         string err = "Unable to determine client certificate authority file." ;
00094         throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00095     }
00096 
00097     found = false ;
00098     TheBESKeys::TheKeys()->get_value( "BES.ClientKeyFile", _kfile, found ) ;
00099     if( !found || _kfile.empty() )
00100     {
00101         string err = "Unable to determine client key file." ;
00102         throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00103     }
00104 }
00105 
00106 PPTClient::~PPTClient()
00107 {
00108     if( _mySock )
00109     {
00110         if( _connected )
00111         {
00112             closeConnection() ;
00113         }
00114         delete _mySock ;
00115         _mySock = 0 ;
00116     }
00117 }
00118 
00119 void
00120 PPTClient::initConnection()
00121 {
00122     try
00123     {
00124         send( PPTProtocol::PPTCLIENT_TESTING_CONNECTION ) ;
00125     }
00126     catch( BESInternalError &e )
00127     {
00128         string msg = "Failed to initialize connection to server\n" ;
00129         msg += e.get_message() ;
00130         throw BESInternalError( msg, __FILE__, __LINE__ ) ;
00131     }
00132 
00133     // we're just getting tokens, not a big buffer, so don't need that big
00134     // of a buffer. pcw 05/31/08
00135     unsigned int ppt_buffer_size = 64 ;
00136     char *inBuff = new char[ppt_buffer_size+1] ;
00137     int bytesRead = readBufferNonBlocking( inBuff, ppt_buffer_size ) ;
00138     if( bytesRead < 1 )
00139     {
00140         delete [] inBuff ;
00141         string err = "Could not connect to server, server may be down or busy" ;
00142         throw BESInternalError( err, __FILE__, __LINE__) ;
00143     }
00144 
00145     if( bytesRead > ppt_buffer_size )
00146         bytesRead = ppt_buffer_size ;
00147     inBuff[bytesRead] = '\0' ;
00148     string status( inBuff, 0, bytesRead ) ;
00149     delete [] inBuff ;
00150 
00151     if( status == PPTProtocol::PPT_PROTOCOL_UNDEFINED )
00152     {
00153         string err = "Could not connect to server, server may be down or busy" ;
00154         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00155     }
00156 
00157     if( status == PPTProtocol::PPTSERVER_AUTHENTICATE )
00158     {
00159         authenticateWithServer() ;
00160     }
00161     else if( status != PPTProtocol::PPTSERVER_CONNECTION_OK )
00162     {
00163         string err = "Server reported an invalid connection, \""
00164                      + status + "\"" ;
00165         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00166     }
00167 }
00168 
00169 void
00170 PPTClient::authenticateWithServer()
00171 {
00172 #ifdef HAVE_OPENSSL
00173     // get the certificate and key file information
00174     get_secure_files() ;
00175 
00176     // send request for the authentication port
00177     send( PPTProtocol::PPTCLIENT_REQUEST_AUTHPORT ) ;
00178 
00179     // receive response with port, terminated with TERMINATE token. We are
00180     // exchanging a port number and a terminating token. The buffer doesn't
00181     // need to be too big. pcw 05/31/08
00182     unsigned int ppt_buffer_size = 64 ;
00183     char *inBuff = new char[ppt_buffer_size+1] ;
00184     int bytesRead = readBufferNonBlocking( inBuff, ppt_buffer_size ) ;
00185     if( bytesRead < 1 )
00186     {
00187         delete [] inBuff ;
00188         string err = "Expecting secure port number response" ;
00189         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00190     }
00191 
00192     if( bytesRead > ppt_buffer_size )
00193     {
00194         bytesRead = ppt_buffer_size ;
00195     }
00196     inBuff[bytesRead] = '\0' ;
00197     ostringstream portResponse( inBuff ) ;
00198     delete [] inBuff ;
00199 
00200     int portVal = atoi( portResponse.str().c_str() ) ;
00201     if( portVal == 0 )
00202     {
00203         string err = "Expecting valid secure port number response" ;
00204         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00205     }
00206 
00207     // authenticate using SSLClient
00208     SSLClient client( _host, portVal, _cfile, _cafile, _kfile ) ;
00209     client.initConnection() ;
00210     client.closeConnection() ;
00211 
00212     // If it authenticates, good, if not then an exception is thrown. We
00213     // don't need to do anything else here.
00214 #else
00215     throw BESInternalError( "Server has requested authentication, but OpenSSL is not built into this client", __FILE__, __LINE__ ) ;
00216 #endif
00217 }
00218 
00219 void
00220 PPTClient::closeConnection()
00221 {
00222     if( _connected )
00223     {
00224         if( !_brokenPipe )
00225         {
00226             try
00227             {
00228                 sendExit() ;
00229             }
00230             catch( BESInternalError e )
00231             {
00232                 cerr << "Failed to inform server that the client is exiting, "
00233                      << "continuing" << endl ;
00234                 cerr << e.get_message() << endl ;
00235             }
00236         }
00237 
00238         _mySock->close() ;
00239 
00240         _connected = false ;
00241         _brokenPipe = false ;
00242     }
00243 }
00244 
00251 void
00252 PPTClient::dump( ostream &strm ) const
00253 {
00254     strm << BESIndent::LMarg << "PPTClient::dump - ("
00255                              << (void *)this << ")" << endl ;
00256     BESIndent::Indent() ;
00257     strm << BESIndent::LMarg << "connected? " << _connected << endl ;
00258     strm << BESIndent::LMarg << "host: " << _host << endl ;
00259     PPTConnection::dump( strm ) ;
00260     BESIndent::UnIndent() ;
00261 }
00262