bes  Updated for version 3.17.4
PPTClient.cc
1 // PPTClient.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 <string>
34 #include <iostream>
35 #include <sstream>
36 
37 using std::string ;
38 using std::cerr ;
39 using std::cout ;
40 using std::endl ;
41 using std::ostringstream ;
42 
43 #include "PPTClient.h"
44 #include "TcpSocket.h"
45 #include "UnixSocket.h"
46 #include "PPTProtocol.h"
47 #include "BESInternalError.h"
48 #include "BESSyntaxUserError.h"
49 #include "TheBESKeys.h"
50 
51 #include "config.h"
52 #if defined HAVE_OPENSSL && defined NOTTHERE
53 #include "SSLClient.h"
54 #endif
55 
56 PPTClient::PPTClient( const string &hostStr, int portVal, int timeout )
57  : PPTConnection( timeout ),
58  _connected( false ),
59  _host( hostStr )
60 {
61  // connect to the specified host at the specified socket to handle the
62  // secure connection
63  _mySock = new TcpSocket( hostStr, portVal ) ;
64  _mySock->connect() ;
65  _connected = _mySock->isConnected();
66 }
67 
68 PPTClient::PPTClient( const string &unix_socket, int timeout )
69  : PPTConnection( timeout ),
70  _connected( false )
71 {
72  // connect to the specified unix socket to handle the secure connection
73  _mySock = new UnixSocket( unix_socket ) ;
74  _mySock->connect() ;
75  _connected = true ;
76 }
77 
78 void
79 PPTClient::get_secure_files()
80 {
81  bool found = false ;
82  TheBESKeys::TheKeys()->get_value( "BES.ClientCertFile", _cfile, found ) ;
83  if( !found || _cfile.empty() )
84  {
85  string err = "Unable to determine client certificate file." ;
86  throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
87  }
88 
89  found = false ;
90  TheBESKeys::TheKeys()->get_value( "BES.ClientCertAuthFile", _cafile, found);
91  if( !found || _cafile.empty() )
92  {
93  string err = "Unable to determine client certificate authority file." ;
94  throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
95  }
96 
97  found = false ;
98  TheBESKeys::TheKeys()->get_value( "BES.ClientKeyFile", _kfile, found ) ;
99  if( !found || _kfile.empty() )
100  {
101  string err = "Unable to determine client key file." ;
102  throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
103  }
104 }
105 
106 PPTClient::~PPTClient()
107 {
108  if( _mySock )
109  {
110  if( _connected )
111  {
112  closeConnection() ;
113  }
114  delete _mySock ;
115  _mySock = 0 ;
116  }
117 }
118 
119 void
120 PPTClient::initConnection()
121 {
122  try
123  {
124  send( PPTProtocol::PPTCLIENT_TESTING_CONNECTION ) ;
125  }
126  catch( BESInternalError &e )
127  {
128  string msg = "Failed to initialize connection to server\n" ;
129  msg += e.get_message() ;
130  throw BESInternalError( msg, __FILE__, __LINE__ ) ;
131  }
132 
133  // we're just getting tokens, not a big buffer, so don't need that big
134  // of a buffer. pcw 05/31/08
135  const int ppt_buffer_size = 64 ;
136  char *inBuff = new char[ppt_buffer_size+1] ;
137  int bytesRead = readBufferNonBlocking( inBuff, ppt_buffer_size ) ;
138  if( bytesRead < 1 )
139  {
140  delete [] inBuff ;
141  string err = "Could not connect to server, server may be down or busy" ;
142  throw BESInternalError( err, __FILE__, __LINE__) ;
143  }
144 
145  if( bytesRead > ppt_buffer_size )
146  bytesRead = ppt_buffer_size ;
147  inBuff[bytesRead] = '\0' ;
148  string status( inBuff, 0, bytesRead ) ;
149  delete [] inBuff ;
150 
151  if( status == PPTProtocol::PPT_PROTOCOL_UNDEFINED )
152  {
153  string err = "Could not connect to server, server may be down or busy" ;
154  throw BESInternalError( err, __FILE__, __LINE__ ) ;
155  }
156 
157  if( status == PPTProtocol::PPTSERVER_AUTHENTICATE )
158  {
159  authenticateWithServer() ;
160  }
161  else if( status != PPTProtocol::PPTSERVER_CONNECTION_OK )
162  {
163  string err = "Server reported an invalid connection, \""
164  + status + "\"" ;
165  throw BESInternalError( err, __FILE__, __LINE__ ) ;
166  }
167 }
168 
169 void
170 PPTClient::authenticateWithServer()
171 {
172 #if defined HAVE_OPENSSL && defined NOTTHERE
173  // get the certificate and key file information
174  get_secure_files() ;
175 
176  // send request for the authentication port
177  send( PPTProtocol::PPTCLIENT_REQUEST_AUTHPORT ) ;
178 
179  // receive response with port, terminated with TERMINATE token. We are
180  // exchanging a port number and a terminating token. The buffer doesn't
181  // need to be too big. pcw 05/31/08
182  const int ppt_buffer_size = 64 ;
183  char *inBuff = new char[ppt_buffer_size+1] ;
184  int bytesRead = readBufferNonBlocking( inBuff, ppt_buffer_size ) ;
185  if( bytesRead < 1 )
186  {
187  delete [] inBuff ;
188  string err = "Expecting secure port number response" ;
189  throw BESInternalError( err, __FILE__, __LINE__ ) ;
190  }
191 
192  if( bytesRead > ppt_buffer_size )
193  {
194  bytesRead = ppt_buffer_size ;
195  }
196  inBuff[bytesRead] = '\0' ;
197  ostringstream portResponse( inBuff ) ;
198  delete [] inBuff ;
199 
200  int portVal = atoi( portResponse.str().c_str() ) ;
201  if( portVal == 0 )
202  {
203  string err = "Expecting valid secure port number response" ;
204  throw BESInternalError( err, __FILE__, __LINE__ ) ;
205  }
206 
207  // authenticate using SSLClient
208  SSLClient client( _host, portVal, _cfile, _cafile, _kfile ) ;
209  client.initConnection() ;
210  client.closeConnection() ;
211 
212  // If it authenticates, good, if not then an exception is thrown. We
213  // don't need to do anything else here.
214 #else
215  throw BESInternalError( "Server has requested authentication, but OpenSSL is not built into this client", __FILE__, __LINE__ ) ;
216 #endif
217 }
218 
219 void
220 PPTClient::closeConnection()
221 {
222  if( _connected )
223  {
224  if( !_brokenPipe )
225  {
226  try
227  {
228  sendExit() ;
229  }
230  catch( BESInternalError &e )
231  {
232  cerr << "Failed to inform server that the client is exiting, "
233  << "continuing" << endl ;
234  cerr << e.get_message() << endl ;
235  }
236  }
237 
238  _mySock->close() ;
239 
240  _connected = false ;
241  _brokenPipe = false ;
242  }
243 }
244 
251 void
252 PPTClient::dump( ostream &strm ) const
253 {
254  strm << BESIndent::LMarg << "PPTClient::dump - ("
255  << (void *)this << ")" << endl ;
256  BESIndent::Indent() ;
257  strm << BESIndent::LMarg << "connected? " << _connected << endl ;
258  strm << BESIndent::LMarg << "host: " << _host << endl ;
259  PPTConnection::dump( strm ) ;
260  BESIndent::UnIndent() ;
261 }
262 
exception thrown if inernal error encountered
virtual std::string get_message()
get the error message for this exception
Definition: BESError.h:97
error thrown if there is a user syntax error in the request or any other user error ...
virtual void dump(ostream &strm) const
dumps information about this object
virtual void dump(ostream &strm) const
dumps information about this object
Definition: PPTClient.cc:252
void get_value(const string &s, string &val, bool &found)
Retrieve the value of a given key, if set.
Definition: BESKeys.cc:483
static BESKeys * TheKeys()
Definition: TheBESKeys.cc:43