bes Updated for version 3.20.13
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
37using std::string ;
38using std::cerr ;
39using std::cout ;
40using std::endl ;
41using std::ostringstream ;
42using std::ostream;
43
44#include "PPTClient.h"
45#include "TcpSocket.h"
46#include "UnixSocket.h"
47#include "PPTProtocolNames.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
57PPTClient::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
69PPTClient::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
79void
80PPTClient::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
107PPTClient::~PPTClient()
108{
109 if( _mySock )
110 {
111 if( _connected )
112 {
113 closeConnection() ;
114 }
115 delete _mySock ;
116 _mySock = 0 ;
117 }
118}
119
120void
121PPTClient::initConnection()
122{
123 try
124 {
125 send(PPT_CLIENT_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 == 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 == PPT_SERVER_AUTHENTICATE )
159 {
160 authenticateWithServer() ;
161 }
162 else if(status != PPT_SERVER_CONNECTION_OK )
163 {
164 string err = "Server reported an invalid connection, \""
165 + status + "\"" ;
166 throw BESInternalError( err, __FILE__, __LINE__ ) ;
167 }
168}
169
170void
171PPTClient::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(PPT_CLIENT_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
220void
221PPTClient::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
252void
253PPTClient::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
std::string get_message() const
get the error message for this exception
Definition: BESError.h:111
exception thrown if internal error encountered
error thrown if there is a user syntax error in the request or any other user error
virtual void dump(std::ostream &strm) const
dumps information about this object
Definition: PPTClient.cc:253
virtual void sendExit()
Send the exit token as an extension.
virtual void send(const std::string &buffer)
sends the buffer to the socket
virtual int readBufferNonBlocking(char *inBuff, const int buff_size)
read a buffer of data from the socket without blocking
virtual void dump(std::ostream &strm) const
dumps information about this object
void get_value(const std::string &s, std::string &val, bool &found)
Retrieve the value of a given key, if set.
Definition: TheBESKeys.cc:340
static TheBESKeys * TheKeys()
Definition: TheBESKeys.cc:71