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

Generated on Sat Aug 22 06:06:27 2009 for OPeNDAP Hyrax Back End Server (BES) by  doxygen 1.6.0