BOSS 8.0.0
BESIII Offline Software System
Loading...
Searching...
No Matches
XmlRpcClient.cpp
Go to the documentation of this file.
1
2#include "XmlRpcClient.h"
3
4#include "XmlRpc.h"
5#include "XmlRpcSocket.h"
6
7#include <cstring>
8#include <iostream>
9#include <stdio.h>
10#include <stdlib.h>
11
12using namespace XmlRpc;
13
14// Static data
15const char XmlRpcClient::REQUEST_BEGIN[] = "<?xml version=\"1.0\"?>\r\n"
16 "<methodCall><methodName>";
17const char XmlRpcClient::REQUEST_END_METHODNAME[] = "</methodName>\r\n";
18const char XmlRpcClient::PARAMS_TAG[] = "<params>";
19const char XmlRpcClient::PARAMS_ETAG[] = "</params>";
20const char XmlRpcClient::PARAM_TAG[] = "<param>";
21const char XmlRpcClient::PARAM_ETAG[] = "</param>";
22const char XmlRpcClient::REQUEST_END[] = "</methodCall>\r\n";
23// const char XmlRpcClient::METHODRESPONSE_TAG[] = "<methodResponse";//yzhang add
24const char XmlRpcClient::METHODRESPONSE_TAG[] = "<methodResponse>"; // yzhang delete
25const char XmlRpcClient::FAULT_TAG[] = "<fault>";
26
27XmlRpcClient::XmlRpcClient( const char* host, int port, const char* uri /*=0*/ ) {
28 XmlRpcUtil::log( 1, "XmlRpcClient new client: host %s, port %d.", host, port );
29
30 _host = host;
31 _port = port;
32 if ( uri ) _uri = uri;
33 else _uri = "/RPC2";
35 _executing = false;
36 _eof = false;
37
38 // Default to keeping the connection open until an explicit close is done
40}
41
43
44// Close the owned fd
46 XmlRpcUtil::log( 4, "XmlRpcClient::close: fd %d.", getfd() );
48 _disp.exit();
49 _disp.removeSource( this );
51}
52
53// Clear the referenced flag even if exceptions or errors occur.
55 ClearFlagOnExit( bool& flag ) : _flag( flag ) {}
56 ~ClearFlagOnExit() { _flag = false; }
57 bool& _flag;
58};
59
60// Execute the named procedure on the remote server.
61// Params should be an array of the arguments for the method.
62// Returns true if the request was sent and a result received (although the result
63// might be a fault).
64bool XmlRpcClient::execute( const char* method, XmlRpcValue const& params,
65 XmlRpcValue& result ) {
66 XmlRpcUtil::log( 1, "XmlRpcClient::execute: method %s (_connectionState %d).", method,
68 // std::cout<< "_connectionState "<<_connectionState << std::endl;//yzhang debug
69 // This is not a thread-safe operation, if you want to do multithreading, use separate
70 // clients for each thread. If you want to protect yourself from multiple threads
71 // accessing the same client, replace this code with a real mutex.
72 if ( _executing ) return false;
73
74 _executing = true;
76
77 _sendAttempts = 0;
78 _isFault = false;
79
80 if ( !setupConnection() ) return false;
81
82 if ( !generateRequest( method, params ) ) return false;
83 result.clear();
84 double msTime = 5.; // Process until exit is called //yzhang change
85 // double msTime = -1.0; // Process until exit is called //yzhang delete
86 _disp.work( msTime );
87
88 if ( _connectionState != IDLE ) // yzhang add
89 // if (_connectionState != IDLE || ! parseResponse(result))//yzhang delete
90 return false; // yzhang delete
91
92 XmlRpcUtil::log( 1, "XmlRpcClient::execute: method %s completed.", method );
93 _response = "";
94 return true;
95}
96
97// XmlRpcSource interface implementation
98// Handle server responses. Called by the event dispatcher during execute.
99unsigned XmlRpcClient::handleEvent( unsigned eventType ) {
100 if ( eventType == XmlRpcDispatch::Exception )
101 {
104 "Error in XmlRpcClient::handleEvent: could not connect to server (%s).",
105 XmlRpcSocket::getErrorMsg().c_str() );
106 else
107 XmlRpcUtil::error( "Error in XmlRpcClient::handleEvent (state %d): %s.",
109 return 0;
110 }
111
113 if ( !writeRequest() ) return 0;
114
116 if ( !readHeader() ) return 0;
117
119 if ( !readResponse() ) return 0;
120
121 // This should probably always ask for Exception events too
124}
125
126// Create the socket connection to the server if necessary
128 // If an error occurred last time through, or if the server closed the connection, close our
129 // end
131
132 _eof = false;
134 if ( !doConnect() ) return false;
135
136 // Prepare to write the request
138 _bytesWritten = 0;
139
140 // Notify the dispatcher to listen on this source (calls handleEvent when the socket is
141 // writable)
142 _disp.removeSource( this ); // Make sure nothing is left over
144
145 return true;
146}
147
148// Connect to the xmlrpc server
150 int fd = XmlRpcSocket::socket();
151 if ( fd < 0 )
152 {
153 XmlRpcUtil::error( "Error in XmlRpcClient::doConnect: Could not create socket (%s).",
154 XmlRpcSocket::getErrorMsg().c_str() );
155 return false;
156 }
157
158 XmlRpcUtil::log( 3, "XmlRpcClient::doConnect: fd %d.", fd );
159 this->setfd( fd );
160
161 // Don't block on connect/reads/writes
162 if ( !XmlRpcSocket::setNonBlocking( fd ) )
163 {
164 this->close();
166 "Error in XmlRpcClient::doConnect: Could not set socket to non-blocking IO mode (%s).",
167 XmlRpcSocket::getErrorMsg().c_str() );
168 return false;
169 }
170
171 if ( !XmlRpcSocket::connect( fd, _host, _port ) )
172 {
173 this->close();
174 XmlRpcUtil::error( "Error in XmlRpcClient::doConnect: Could not connect to server (%s).",
175 XmlRpcSocket::getErrorMsg().c_str() );
176 return false;
177 }
178
179 return true;
180}
181
182// Encode the request to call the specified method with the specified parameters into xml
183bool XmlRpcClient::generateRequest( const char* methodName, XmlRpcValue const& params ) {
184 std::string body = REQUEST_BEGIN;
185 body += methodName;
187
188 // If params is an array, each element is a separate parameter
189 if ( params.valid() )
190 {
191 body += PARAMS_TAG;
192 if ( params.getType() == XmlRpcValue::TypeArray )
193 {
194 for ( int i = 0; i < params.size(); ++i )
195 {
196 body += PARAM_TAG;
197 body += params[i].toXml();
198 body += PARAM_ETAG;
199 }
200 }
201 else
202 {
203 body += PARAM_TAG;
204 body += params.toXml();
205 body += PARAM_ETAG;
206 }
207
208 body += PARAMS_ETAG;
209 }
210 body += REQUEST_END;
211
212 std::string header = generateHeader( body );
214 "XmlRpcClient::generateRequest: header is %d bytes, content-length is %d.",
215 header.length(), body.length() );
216
217 _request = header + body;
218 return true;
219}
220
221// Prepend http headers
222std::string XmlRpcClient::generateHeader( std::string const& body ) {
223 std::string header = "POST " + _uri +
224 " HTTP/1.1\r\n"
225 "User-Agent: ";
226 header += XMLRPC_VERSION;
227 header += "\r\nHost: ";
228 header += _host;
229
230 char buff[40];
231 sprintf( buff, ":%d\r\n", _port );
232
233 header += buff;
234 header += "Content-Type: text/xml\r\nContent-length: ";
235
236 sprintf( buff, "%d\r\n\r\n", body.size() );
237
238 return header + buff;
239}
240
242 if ( _bytesWritten == 0 )
243 XmlRpcUtil::log( 5, "XmlRpcClient::writeRequest (attempt %d):\n%s\n", _sendAttempts + 1,
244 _request.c_str() );
245
246 // Try to write the request
248 {
249 XmlRpcUtil::error( "Error in XmlRpcClient::writeRequest: write error (%s).",
250 XmlRpcSocket::getErrorMsg().c_str() );
251 return false;
252 }
253
254 XmlRpcUtil::log( 3, "XmlRpcClient::writeRequest: wrote %d of %d bytes.", _bytesWritten,
255 _request.length() );
256
257 // Wait for the result
258 if ( _bytesWritten == int( _request.length() ) )
259 {
260 _header = "";
261 _response = "";
263 }
264 return true;
265}
266
267// Read the header from the response
269 // Read available data
270 if ( !XmlRpcSocket::nbRead( this->getfd(), _header, &_eof ) ||
271 ( _eof && _header.length() == 0 ) )
272 {
273
274 // If we haven't read any data yet and this is a keep-alive connection, the server may
275 // have timed out, so we try one more time.
276 if ( getKeepOpen() && _header.length() == 0 && _sendAttempts++ == 0 )
277 {
278 XmlRpcUtil::log( 4, "XmlRpcClient::readHeader: re-trying connection" );
281 _eof = false;
282 return setupConnection();
283 }
284
286 "Error in XmlRpcClient::readHeader: error while reading header (%s) on fd %d.",
287 XmlRpcSocket::getErrorMsg().c_str(), getfd() );
288 return false;
289 }
290
291 XmlRpcUtil::log( 4, "XmlRpcClient::readHeader: client has read %d bytes", _header.length() );
292
293 char* hp = (char*)_header.c_str(); // Start of header
294 char* ep = hp + _header.length(); // End of string
295 char* bp = 0; // Start of body
296 char* lp = 0; // Start of content-length value
297
298 for ( char* cp = hp; ( bp == 0 ) && ( cp < ep ); ++cp )
299 {
300 if ( ( ep - cp > 16 ) && ( strncasecmp( cp, "Content-length: ", 16 ) == 0 ) ) lp = cp + 16;
301 else if ( ( ep - cp > 4 ) && ( strncmp( cp, "\r\n\r\n", 4 ) == 0 ) ) bp = cp + 4;
302 else if ( ( ep - cp > 2 ) && ( strncmp( cp, "\n\n", 2 ) == 0 ) ) bp = cp + 2;
303 }
304
305 // If we haven't gotten the entire header yet, return (keep reading)
306 if ( bp == 0 )
307 {
308 if ( _eof ) // EOF in the middle of a response is an error
309 {
310 XmlRpcUtil::error( "Error in XmlRpcClient::readHeader: EOF while reading header" );
311 return false; // Close the connection
312 }
313
314 return true; // Keep reading
315 }
316
317 // Decode content length
318 if ( lp == 0 )
319 {
320 XmlRpcUtil::error( "Error XmlRpcClient::readHeader: No Content-length specified" );
321 return false; // We could try to figure it out by parsing as we read, but for now...
322 }
323
324 _contentLength = atoi( lp );
325 if ( _contentLength <= 0 )
326 {
328 "Error in XmlRpcClient::readHeader: Invalid Content-length specified (%d).",
330 return false;
331 }
332
333 XmlRpcUtil::log( 4, "client read content length: %d", _contentLength );
334
335 // Otherwise copy non-header data to response buffer and set state to read response.
336 _response = bp;
337 _header = ""; // should parse out any interesting bits from the header (connection, etc)...
339 return true; // Continue monitoring this source
340}
341
343 // If we dont have the entire response yet, read available data
344 if ( int( _response.length() ) < _contentLength )
345 {
346 if ( !XmlRpcSocket::nbRead( this->getfd(), _response, &_eof ) )
347 {
348 XmlRpcUtil::error( "Error in XmlRpcClient::readResponse: read error (%s).",
349 XmlRpcSocket::getErrorMsg().c_str() );
350 return false;
351 }
352
353 // If we haven't gotten the entire _response yet, return (keep reading)
354 if ( int( _response.length() ) < _contentLength )
355 {
356 if ( _eof )
357 {
358 XmlRpcUtil::error( "Error in XmlRpcClient::readResponse: EOF while reading response" );
359 return false;
360 }
361 return true;
362 }
363 }
364
365 // Otherwise, parse and return the result
366 XmlRpcUtil::log( 3, "XmlRpcClient::readResponse (read %d bytes)", _response.length() );
367 XmlRpcUtil::log( 5, "response:\n%s", _response.c_str() );
368
370
371 return false; // Stop monitoring this source (causes return from work)
372}
373
374// Convert the response xml into a result value
376 // Parse response xml into result
377 int offset = 0;
379 {
380 XmlRpcUtil::error( "Error in XmlRpcClient::parseResponse: Invalid response - no "
381 "methodResponse. Response:\n%s",
382 _response.c_str() );
383 return false;
384 }
385
386 // Expect either <params><param>... or <fault>...
387 if ( ( XmlRpcUtil::nextTagIs( PARAMS_TAG, _response, &offset ) &&
389 // || XmlRpcUtil::nextTagIs(FAULT_TAG,_response,&offset) //yzhang delete
390 && ( _isFault = true ) )
391 {
392 if ( !result.fromXml( _response, &offset ) )
393 {
395 "Error in XmlRpcClient::parseResponse: Invalid response value. Response:\n%s",
396 _response.c_str() );
397 _response = "";
398 return false;
399 }
400 }
401 else
402 {
403 XmlRpcUtil::error( "Error in XmlRpcClient::parseResponse: Invalid response - no param or "
404 "fault tag. Response:\n%s",
405 _response.c_str() );
406 _response = "";
407 return false;
408 }
409
410 _response = "";
411 return result.valid();
412}
sprintf(cut, "kal_costheta0_em>-0.93&&kal_costheta0_em<0.93&&kal_pxy0_em>=0.05+%d*0.1&&kal_" "pxy0_em<0.15+%d*0.1&&NGch>=2", j, j)
static const char PARAM_ETAG[]
static const char PARAMS_ETAG[]
static const char REQUEST_END[]
XmlRpcClient(const char *host, int port, const char *uri=0)
bool execute(const char *method, XmlRpcValue const &params, XmlRpcValue &result)
XmlRpcDispatch _disp
virtual bool doConnect()
virtual std::string generateHeader(std::string const &body)
virtual void close()
Close the connection.
static const char REQUEST_END_METHODNAME[]
ClientConnectionState _connectionState
virtual bool parseResponse(XmlRpcValue &result)
static const char REQUEST_BEGIN[]
static const char PARAM_TAG[]
virtual bool setupConnection()
virtual bool writeRequest()
virtual bool readResponse()
virtual ~XmlRpcClient()
Destructor.
virtual bool readHeader()
static const char METHODRESPONSE_TAG[]
static const char FAULT_TAG[]
static const char PARAMS_TAG[]
virtual bool generateRequest(const char *method, XmlRpcValue const &params)
virtual unsigned handleEvent(unsigned eventType)
@ ReadableEvent
data available to read
@ WritableEvent
connected/data can be written without blocking
static int socket()
Creates a stream (TCP) socket. Returns -1 on failure.
static bool nbWrite(int socket, std::string &s, int *bytesSoFar)
Write text to the specified socket. Returns false on error.
static bool connect(int socket, std::string &host, int port)
Connect a socket to a server (from a client).
static bool setNonBlocking(int socket)
Sets a stream (TCP) socket to perform non-blocking IO. Returns false on failure.
static bool nbRead(int socket, std::string &s, bool *eof)
Read text from the specified socket. Returns false on error.
static std::string getErrorMsg()
Returns message corresponding to last error.
virtual void close()
int getfd() const
Return the file descriptor being monitored.
void setKeepOpen(bool b=true)
Specify whether the file descriptor should be kept open if it is no longer monitored.
bool getKeepOpen() const
Return whether the file descriptor should be kept open if it is no longer monitored.
void setfd(int fd)
Specify the file descriptor to monitor.
static bool nextTagIs(const char *tag, std::string const &xml, int *offset)
static void error(const char *fmt,...)
Dump error messages somewhere.
static bool findTag(const char *tag, std::string const &xml, int *offset)
Returns true if the tag is found and updates offset to the char after the tag.
static void log(int level, const char *fmt,...)
Dump messages somewhere.
RPC method arguments and results are represented by Values.
Definition XmlRpcValue.h:22
int size() const
Return the size for string, base64, array, and struct values.
void clear()
Erase the current value.
Definition XmlRpcValue.h:75
bool fromXml(std::string const &valueXml, int *offset)
Decode xml. Destroys any existing value.
bool valid() const
Return true if the value has been set to something.
std::string toXml() const
Encode the Value in xml.
Type const & getType() const
Return the type of the value stored.
const char XMLRPC_VERSION[]
Version identifier.
double int * ep
Definition qcdloop1.h:82
ClearFlagOnExit(bool &flag)