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