BOSS 8.0.0
BESIII Offline Software System
Loading...
Searching...
No Matches
XmlRpcServerConnection.cpp
Go to the documentation of this file.
1
3
4#include "XmlRpc.h"
5#include "XmlRpcSocket.h"
6#ifndef MAKEDEPEND
7# include <stdio.h>
8# include <stdlib.h>
9#endif
10#include <cstring>
11
12using namespace XmlRpc;
13
14// Static data
15const char XmlRpcServerConnection::METHODNAME_TAG[] = "<methodName>";
16const char XmlRpcServerConnection::PARAMS_TAG[] = "<params>";
17const char XmlRpcServerConnection::PARAMS_ETAG[] = "</params>";
18const char XmlRpcServerConnection::PARAM_TAG[] = "<param>";
19const char XmlRpcServerConnection::PARAM_ETAG[] = "</param>";
20
21const std::string XmlRpcServerConnection::SYSTEM_MULTICALL = "system.multicall";
22const std::string XmlRpcServerConnection::METHODNAME = "methodName";
23const std::string XmlRpcServerConnection::PARAMS = "params";
24
25const std::string XmlRpcServerConnection::FAULTCODE = "faultCode";
26const std::string XmlRpcServerConnection::FAULTSTRING = "faultString";
27
28// The server delegates handling client requests to a serverConnection object.
30 bool deleteOnClose /*= false*/ )
31 : XmlRpcSource( fd, deleteOnClose ) {
32 XmlRpcUtil::log( 2, "XmlRpcServerConnection: new socket %d.", fd );
33 _server = server;
35 _keepAlive = true;
36}
37
39 XmlRpcUtil::log( 4, "XmlRpcServerConnection dtor." );
40 _server->removeConnection( this );
41}
42
43// Handle input on the server socket by accepting the connection
44// and reading the rpc request. Return true to continue to monitor
45// the socket for events, false to remove it from the dispatcher.
46unsigned XmlRpcServerConnection::handleEvent( unsigned /*eventType*/ ) {
48 if ( !readHeader() ) return 0;
49
51 if ( !readRequest() ) return 0;
52
54 if ( !writeResponse() ) return 0;
55
58}
59
61 // Read available data
62 bool eof;
63 if ( !XmlRpcSocket::nbRead( this->getfd(), _header, &eof ) )
64 {
65 // Its only an error if we already have read some data
66 if ( _header.length() > 0 )
68 "XmlRpcServerConnection::readHeader: error while reading header (%s).",
69 XmlRpcSocket::getErrorMsg().c_str() );
70 return false;
71 }
72
73 XmlRpcUtil::log( 4, "XmlRpcServerConnection::readHeader: read %d bytes.", _header.length() );
74 char* hp = (char*)_header.c_str(); // Start of header
75 char* ep = hp + _header.length(); // End of string
76 char* bp = 0; // Start of body
77 char* lp = 0; // Start of content-length value
78 char* kp = 0; // Start of connection value
79
80 for ( char* cp = hp; ( bp == 0 ) && ( cp < ep ); ++cp )
81 {
82 if ( ( ep - cp > 16 ) && ( strncasecmp( cp, "Content-length: ", 16 ) == 0 ) ) lp = cp + 16;
83 else if ( ( ep - cp > 12 ) && ( strncasecmp( cp, "Connection: ", 12 ) == 0 ) )
84 kp = cp + 12;
85 else if ( ( ep - cp > 4 ) && ( strncmp( cp, "\r\n\r\n", 4 ) == 0 ) ) bp = cp + 4;
86 else if ( ( ep - cp > 2 ) && ( strncmp( cp, "\n\n", 2 ) == 0 ) ) bp = cp + 2;
87 }
88
89 // If we haven't gotten the entire header yet, return (keep reading)
90 if ( bp == 0 )
91 {
92 // EOF in the middle of a request is an error, otherwise its ok
93 if ( eof )
94 {
95 XmlRpcUtil::log( 4, "XmlRpcServerConnection::readHeader: EOF" );
96 if ( _header.length() > 0 )
97 XmlRpcUtil::error( "XmlRpcServerConnection::readHeader: EOF while reading header" );
98 return false; // Either way we close the connection
99 }
100
101 return true; // Keep reading
102 }
103
104 // Decode content length
105 if ( lp == 0 )
106 {
107 XmlRpcUtil::error( "XmlRpcServerConnection::readHeader: No Content-length specified" );
108 return false; // We could try to figure it out by parsing as we read, but for now...
109 }
110
111 _contentLength = atoi( lp );
112 if ( _contentLength <= 0 )
113 {
115 "XmlRpcServerConnection::readHeader: Invalid Content-length specified (%d).",
117 return false;
118 }
119
120 XmlRpcUtil::log( 3, "XmlRpcServerConnection::readHeader: specified content length is %d.",
122
123 // Otherwise copy non-header data to request buffer and set state to read request.
124 _request = bp;
125
126 // Parse out any interesting bits from the header (HTTP version, connection)
127 _keepAlive = true;
128 if ( _header.find( "HTTP/1.0" ) != std::string::npos )
129 {
130 if ( kp == 0 || strncasecmp( kp, "keep-alive", 10 ) != 0 )
131 _keepAlive = false; // Default for HTTP 1.0 is to close the connection
132 }
133 else
134 {
135 if ( kp != 0 && strncasecmp( kp, "close", 5 ) == 0 ) _keepAlive = false;
136 }
137 XmlRpcUtil::log( 3, "KeepAlive: %d", _keepAlive );
138
139 _header = "";
141 return true; // Continue monitoring this source
142}
143
145 // If we dont have the entire request yet, read available data
146 if ( int( _request.length() ) < _contentLength )
147 {
148 bool eof;
149 if ( !XmlRpcSocket::nbRead( this->getfd(), _request, &eof ) )
150 {
151 XmlRpcUtil::error( "XmlRpcServerConnection::readRequest: read error (%s).",
152 XmlRpcSocket::getErrorMsg().c_str() );
153 return false;
154 }
155
156 // If we haven't gotten the entire request yet, return (keep reading)
157 if ( int( _request.length() ) < _contentLength )
158 {
159 if ( eof )
160 {
161 XmlRpcUtil::error( "XmlRpcServerConnection::readRequest: EOF while reading request" );
162 return false; // Either way we close the connection
163 }
164 return true;
165 }
166 }
167
168 // Otherwise, parse and dispatch the request
169 XmlRpcUtil::log( 3, "XmlRpcServerConnection::readRequest read %d bytes.",
170 _request.length() );
171 // XmlRpcUtil::log(5, "XmlRpcServerConnection::readRequest:\n%s\n", _request.c_str());
172
174
175 return true; // Continue monitoring this source
176}
177
179 if ( _response.length() == 0 )
180 {
182 _bytesWritten = 0;
183 if ( _response.length() == 0 )
184 {
185 XmlRpcUtil::error( "XmlRpcServerConnection::writeResponse: empty response." );
186 return false;
187 }
188 }
189
190 // Try to write the response
192 {
193 XmlRpcUtil::error( "XmlRpcServerConnection::writeResponse: write error (%s).",
194 XmlRpcSocket::getErrorMsg().c_str() );
195 return false;
196 }
197 XmlRpcUtil::log( 3, "XmlRpcServerConnection::writeResponse: wrote %d of %d bytes.",
198 _bytesWritten, _response.length() );
199
200 // Prepare to read the next request
201 if ( _bytesWritten == int( _response.length() ) )
202 {
203 _header = "";
204 _request = "";
205 _response = "";
207 }
208
209 return _keepAlive; // Continue monitoring this source if true
210}
211
212// Run the method, generate _response string
214 XmlRpcValue params, resultValue;
215 std::string methodName = parseRequest( params );
216 XmlRpcUtil::log( 2, "XmlRpcServerConnection::executeRequest: server calling method '%s'",
217 methodName.c_str() );
218
219 try
220 {
221
222 if ( !executeMethod( methodName, params, resultValue ) &&
223 !executeMulticall( methodName, params, resultValue ) )
224 generateFaultResponse( methodName + ": unknown method name" );
225 else generateResponse( resultValue.toXml() );
226
227 } catch ( const XmlRpcException& fault )
228 {
229 XmlRpcUtil::log( 2, "XmlRpcServerConnection::executeRequest: fault %s.",
230 fault.getMessage().c_str() );
231 generateFaultResponse( fault.getMessage(), fault.getCode() );
232 }
233}
234
235// Parse the method name and the argument values from the request.
237 int offset = 0; // Number of chars parsed from the request
238
239 std::string methodName = XmlRpcUtil::parseTag( METHODNAME_TAG, _request, &offset );
240
241 if ( methodName.size() > 0 && XmlRpcUtil::findTag( PARAMS_TAG, _request, &offset ) )
242 {
243 int nArgs = 0;
244 while ( XmlRpcUtil::nextTagIs( PARAM_TAG, _request, &offset ) )
245 {
246 params[nArgs++] = XmlRpcValue( _request, &offset );
247 (void)XmlRpcUtil::nextTagIs( PARAM_ETAG, _request, &offset );
248 }
249
250 (void)XmlRpcUtil::nextTagIs( PARAMS_ETAG, _request, &offset );
251 }
252
253 return methodName;
254}
255
256// Execute a named method with the specified params.
257bool XmlRpcServerConnection::executeMethod( const std::string& methodName, XmlRpcValue& params,
258 XmlRpcValue& result ) {
259 XmlRpcServerMethod* method = _server->findMethod( methodName );
260
261 if ( !method ) return false;
262
263 method->execute( params, result );
264
265 // Ensure a valid result value
266 if ( !result.valid() ) result = std::string();
267
268 return true;
269}
270
271// Execute multiple calls and return the results in an array.
272bool XmlRpcServerConnection::executeMulticall( const std::string& methodName,
273 XmlRpcValue& params, XmlRpcValue& result ) {
274 if ( methodName != SYSTEM_MULTICALL ) return false;
275
276 // There ought to be 1 parameter, an array of structs
277 if ( params.size() != 1 || params[0].getType() != XmlRpcValue::TypeArray )
278 throw XmlRpcException( SYSTEM_MULTICALL + ": Invalid argument (expected an array)" );
279
280 int nc = params[0].size();
281 result.setSize( nc );
282
283 for ( int i = 0; i < nc; ++i )
284 {
285
286 if ( !params[0][i].hasMember( METHODNAME ) || !params[0][i].hasMember( PARAMS ) )
287 {
288 result[i][FAULTCODE] = -1;
289 result[i][FAULTSTRING] =
291 ": Invalid argument (expected a struct with members methodName and params)";
292 continue;
293 }
294
295 const std::string& methodName = params[0][i][METHODNAME];
296 XmlRpcValue& methodParams = params[0][i][PARAMS];
297
298 XmlRpcValue resultValue;
299 resultValue.setSize( 1 );
300 try
301 {
302 if ( !executeMethod( methodName, methodParams, resultValue[0] ) &&
303 !executeMulticall( methodName, params, resultValue[0] ) )
304 {
305 result[i][FAULTCODE] = -1;
306 result[i][FAULTSTRING] = methodName + ": unknown method name";
307 }
308 else result[i] = resultValue;
309
310 } catch ( const XmlRpcException& fault )
311 {
312 result[i][FAULTCODE] = fault.getCode();
313 result[i][FAULTSTRING] = fault.getMessage();
314 }
315 }
316
317 return true;
318}
319
320// Create a response from results xml
321void XmlRpcServerConnection::generateResponse( std::string const& resultXml ) {
322 const char RESPONSE_1[] = "<?xml version=\"1.0\"?>\r\n"
323 "<methodResponse><params><param>\r\n\t";
324 const char RESPONSE_2[] = "\r\n</param></params></methodResponse>\r\n";
325
326 std::string body = RESPONSE_1 + resultXml + RESPONSE_2;
327 std::string header = generateHeader( body );
328
329 _response = header + body;
330 XmlRpcUtil::log( 5, "XmlRpcServerConnection::generateResponse:\n%s\n", _response.c_str() );
331}
332
333// Prepend http headers
334std::string XmlRpcServerConnection::generateHeader( std::string const& body ) {
335 std::string header = "HTTP/1.1 200 OK\r\n"
336 "Server: ";
337 header += XMLRPC_VERSION;
338 header += "\r\n"
339 "Content-Type: text/xml\r\n"
340 "Content-length: ";
341
342 char buffLen[40];
343 sprintf( buffLen, "%d\r\n\r\n", body.size() );
344
345 return header + buffLen;
346}
347
348void XmlRpcServerConnection::generateFaultResponse( std::string const& errorMsg,
349 int errorCode ) {
350 const char RESPONSE_1[] = "<?xml version=\"1.0\"?>\r\n"
351 "<methodResponse><fault>\r\n\t";
352 const char RESPONSE_2[] = "\r\n</fault></methodResponse>\r\n";
353
354 XmlRpcValue faultStruct;
355 faultStruct[FAULTCODE] = errorCode;
356 faultStruct[FAULTSTRING] = errorMsg;
357 std::string body = RESPONSE_1 + faultStruct.toXml() + RESPONSE_2;
358 std::string header = generateHeader( body );
359
360 _response = header + body;
361}
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)
@ ReadableEvent
data available to read
@ WritableEvent
connected/data can be written without blocking
int getCode() const
Return the error code.
const std::string & getMessage() const
Return the error message.
bool executeMethod(const std::string &methodName, XmlRpcValue &params, XmlRpcValue &result)
std::string parseRequest(XmlRpcValue &params)
void generateFaultResponse(std::string const &msg, int errorCode=-1)
void generateResponse(std::string const &resultXml)
static const std::string METHODNAME
std::string generateHeader(std::string const &body)
static const std::string FAULTSTRING
XmlRpcServerConnection(int fd, XmlRpcServer *server, bool deleteOnClose=false)
Constructor.
bool executeMulticall(const std::string &methodName, XmlRpcValue &params, XmlRpcValue &result)
virtual unsigned handleEvent(unsigned eventType)
static const std::string SYSTEM_MULTICALL
Abstract class representing a single RPC method.
virtual void execute(XmlRpcValue &params, XmlRpcValue &result)=0
Execute the method. Subclasses must provide a definition for this method.
A class to handle XML RPC requests.
static bool nbWrite(int socket, std::string &s, int *bytesSoFar)
Write text to the specified socket. Returns false on error.
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.
int getfd() const
Return the file descriptor being monitored.
XmlRpcSource(int fd=-1, bool deleteOnClose=false)
static bool nextTagIs(const char *tag, std::string const &xml, int *offset)
static std::string parseTag(const char *tag, std::string const &xml, int *offset)
Returns contents between <tag> and </tag>, updates offset to char after </tag>.
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.
bool valid() const
Return true if the value has been set to something.
std::string toXml() const
Encode the Value in xml.
void setSize(int size)
Specify the size for array values. Array values will grow beyond this size if needed.
Type const & getType() const
Return the type of the value stored.
const char XMLRPC_VERSION[]
Version identifier.
double int * ep
Definition qcdloop1.h:82