#include <XmlRpcServer.h>
Public Member Functions | |
XmlRpcServer () | |
Create a server object. | |
virtual | ~XmlRpcServer () |
Destructor. | |
void | enableIntrospection (bool enabled=true) |
Specify whether introspection is enabled or not. Default is not enabled. | |
void | addMethod (XmlRpcServerMethod *method) |
Add a command to the RPC server. | |
void | removeMethod (XmlRpcServerMethod *method) |
Remove a command from the RPC server. | |
void | removeMethod (const std::string &methodName) |
Remove a command from the RPC server by name. | |
XmlRpcServerMethod * | findMethod (const std::string &name) const |
Look up a method by name. | |
bool | bindAndListen (int port, int backlog=5) |
Create a socket, bind to the specified port, and set it in listen mode to make it available for clients. | |
int | getPort (void) const |
Get the port number this server is listening on. | |
void | work (double msTime) |
Process client requests for the specified time. | |
void | exit () |
Temporarily stop processing client requests and exit the work() method. | |
void | shutdown () |
Close all connections with clients and the socket file descriptor. | |
void | listMethods (XmlRpcValue &result) |
Introspection support. | |
virtual std::string | executeRequest (std::string const &request) |
Parses the request xml, runs the method, generates the response (header+xml). | |
virtual unsigned | handleEvent (unsigned eventType) |
Handle client connection requests. | |
virtual void | removeConnection (XmlRpcServerConnection *) |
Remove a connection from the dispatcher. | |
Protected Types | |
typedef std::map < std::string, XmlRpcServerMethod * > | MethodMap |
Collection of methods. This could be a set keyed on method name if we wanted... | |
Protected Member Functions | |
virtual void | acceptConnection () |
Accept a client connection request. | |
virtual XmlRpcServerConnection * | createConnection (int socket) |
Create a new connection object for processing requests from a specific client. | |
virtual void | dispatchConnection (XmlRpcServerConnection *sc) |
Hand off a new connection object to a dispatcher. | |
std::string | parseRequest (std::string const &request, XmlRpcValue ¶ms) |
Parse the methodName and parameters from the request. | |
bool | executeMethod (const std::string &methodName, XmlRpcValue ¶ms, XmlRpcValue &result) |
Execute a named method with the specified params. | |
bool | executeMulticall (const std::string &methodName, XmlRpcValue ¶ms, XmlRpcValue &result) |
Execute multiple calls and return the results in an array. | |
std::string | generateResponse (std::string const &resultXml) |
Construct a response from the result XML. | |
std::string | generateFaultResponse (std::string const &msg, int errorCode=-1) |
Construct a fault response. | |
std::string | generateHeader (std::string const &body) |
Return the appropriate headers for the response. | |
Protected Attributes | |
bool | _introspectionEnabled |
Whether the introspection API is supported by this server. | |
XmlRpcDispatch | _disp |
Event dispatcher. | |
MethodMap | _methods |
Registered RPC methods. | |
XmlRpcServerMethod * | _listMethods |
List all registered RPC methods (only available if introspection is enabled). | |
XmlRpcServerMethod * | _methodHelp |
Return help string for a specified method (only available if introspection is enabled). | |
Static Protected Attributes | |
static const char | METHODNAME_TAG [] = "<methodName>" |
static const char | PARAMS_TAG [] = "<params>" |
static const char | PARAMS_ETAG [] = "</params>" |
static const char | PARAM_TAG [] = "<param>" |
static const char | PARAM_ETAG [] = "</param>" |
static const std::string | SYSTEM_MULTICALL |
static const std::string | METHODNAME = "methodName" |
static const std::string | PARAMS = "params" |
static const std::string | FAULTCODE = "faultCode" |
static const std::string | FAULTSTRING = "faultString" |
typedef std::map< std::string, XmlRpcServerMethod* > XmlRpc::XmlRpcServer::MethodMap [protected] |
Collection of methods. This could be a set keyed on method name if we wanted...
XmlRpcServer::XmlRpcServer | ( | ) |
Create a server object.
00031 { 00032 _introspectionEnabled = false; 00033 _listMethods = 0; 00034 _methodHelp = 0; 00035 }
XmlRpcServer::~XmlRpcServer | ( | ) | [virtual] |
Destructor.
00039 { 00040 this->shutdown(); 00041 _methods.clear(); 00042 delete _listMethods; 00043 delete _methodHelp; 00044 }
void XmlRpcServer::enableIntrospection | ( | bool | enabled = true |
) |
Specify whether introspection is enabled or not. Default is not enabled.
00282 { 00283 if (_introspectionEnabled == enabled) 00284 return; 00285 00286 _introspectionEnabled = enabled; 00287 00288 if (enabled) 00289 { 00290 if ( ! _listMethods) 00291 { 00292 _listMethods = new ListMethods(this); 00293 _methodHelp = new MethodHelp(this); 00294 } else { 00295 addMethod(_listMethods); 00296 addMethod(_methodHelp); 00297 } 00298 } 00299 else 00300 { 00301 removeMethod(LIST_METHODS); 00302 removeMethod(METHOD_HELP); 00303 } 00304 }
void XmlRpcServer::addMethod | ( | XmlRpcServerMethod * | method | ) |
void XmlRpcServer::removeMethod | ( | XmlRpcServerMethod * | method | ) |
void XmlRpcServer::removeMethod | ( | const std::string & | methodName | ) |
XmlRpcServerMethod * XmlRpcServer::findMethod | ( | const std::string & | name | ) | const |
bool XmlRpcServer::bindAndListen | ( | int | port, | |
int | backlog = 5 | |||
) |
Create a socket, bind to the specified port, and set it in listen mode to make it available for clients.
port | The port to bind and listen on (zero to choose an arbitrary port) | |
backlog |
00088 { 00089 int fd = XmlRpcSocket::socket(); 00090 if (fd < 0) 00091 { 00092 XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not create socket (%s).", XmlRpcSocket::getErrorMsg().c_str()); 00093 return false; 00094 } 00095 00096 this->setfd(fd); 00097 00098 // Don't block on reads/writes 00099 if ( ! XmlRpcSocket::setNonBlocking(fd)) 00100 { 00101 this->close(); 00102 XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not set socket to non-blocking input mode (%s).", XmlRpcSocket::getErrorMsg().c_str()); 00103 return false; 00104 } 00105 00106 // Allow this port to be re-bound immediately so server re-starts are not delayed 00107 if ( ! XmlRpcSocket::setReuseAddr(fd)) 00108 { 00109 this->close(); 00110 XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not set SO_REUSEADDR socket option (%s).", XmlRpcSocket::getErrorMsg().c_str()); 00111 return false; 00112 } 00113 00114 // Bind to the specified port on the default interface 00115 if ( ! XmlRpcSocket::bind(fd, port)) 00116 { 00117 this->close(); 00118 XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not bind to specified port (%s).", XmlRpcSocket::getErrorMsg().c_str()); 00119 return false; 00120 } 00121 00122 // Set in listening mode 00123 if ( ! XmlRpcSocket::listen(fd, backlog)) 00124 { 00125 this->close(); 00126 XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not set socket in listening mode (%s).", XmlRpcSocket::getErrorMsg().c_str()); 00127 return false; 00128 } 00129 00130 XmlRpcUtil::log(2, "XmlRpcServer::bindAndListen: server listening on port %d fd %d", port, fd); 00131 00132 // Notify the dispatcher to listen on this source when we are in work() 00133 _disp.addSource(this, XmlRpcDispatch::ReadableEvent); 00134 00135 return true; 00136 }
int XmlRpcServer::getPort | ( | void | ) | const |
Get the port number this server is listening on.
00142 { 00143 return XmlRpcSocket::getPort(getfd()); 00144 }
void XmlRpcServer::work | ( | double | msTime | ) |
Process client requests for the specified time.
00151 { 00152 XmlRpcUtil::log(2, "XmlRpcServer::work: waiting for a connection"); 00153 _disp.work(msTime); 00154 }
void XmlRpcServer::exit | ( | ) |
void XmlRpcServer::shutdown | ( | ) |
void XmlRpcServer::listMethods | ( | XmlRpcValue & | result | ) |
Introspection support.
00309 { 00310 int i = 0; 00311 result.setSize(_methods.size()+1); 00312 for (MethodMap::iterator it=_methods.begin(); it != _methods.end(); ++it) 00313 result[i++] = it->first; 00314 00315 // Multicall support is built into XmlRpcServer::executeRequest 00316 result[i] = MULTICALL; 00317 }
std::string XmlRpcServer::executeRequest | ( | std::string const & | request | ) | [virtual] |
Parses the request xml, runs the method, generates the response (header+xml).
Returns a fault response if an error occurs during method execution.
00324 { 00325 XmlRpcValue params, resultValue; 00326 std::string methodName = parseRequest(request, params); 00327 XmlRpcUtil::log(2, "XmlRpcServer::executeRequest: server calling method '%s'", 00328 methodName.c_str()); 00329 00330 std::string response; 00331 try { 00332 00333 if ( ! executeMethod(methodName, params, resultValue) && 00334 ! executeMulticall(methodName, params, resultValue)) 00335 response = generateFaultResponse(methodName + ": unknown method name"); 00336 else 00337 response = generateResponse(resultValue.toXml()); 00338 00339 } catch (const XmlRpcException& fault) { 00340 XmlRpcUtil::log(2, "XmlRpcServer::executeRequest: fault %s.", 00341 fault.getMessage().c_str()); 00342 response = generateFaultResponse(fault.getMessage(), fault.getCode()); 00343 } 00344 00345 return response; 00346 }
unsigned XmlRpcServer::handleEvent | ( | unsigned | eventType | ) | [virtual] |
Handle client connection requests.
Implements XmlRpc::XmlRpcSource.
00162 { 00163 acceptConnection(); 00164 return XmlRpcDispatch::ReadableEvent; // Continue to monitor this fd 00165 }
void XmlRpcServer::removeConnection | ( | XmlRpcServerConnection * | sc | ) | [virtual] |
void XmlRpcServer::acceptConnection | ( | ) | [protected, virtual] |
Accept a client connection request.
00172 { 00173 int s = XmlRpcSocket::accept(this->getfd()); 00174 XmlRpcUtil::log(2, "XmlRpcServer::acceptConnection: socket %d", s); 00175 if (s < 0) 00176 { 00177 //this->close(); 00178 XmlRpcUtil::error("XmlRpcServer::acceptConnection: Could not accept connection (%s).", XmlRpcSocket::getErrorMsg().c_str()); 00179 } 00180 else if ( ! XmlRpcSocket::setNonBlocking(s)) 00181 { 00182 XmlRpcSocket::close(s); 00183 XmlRpcUtil::error("XmlRpcServer::acceptConnection: Could not set socket to non-blocking input mode (%s).", XmlRpcSocket::getErrorMsg().c_str()); 00184 } 00185 else // Notify the dispatcher to listen for input on this source when we are in work() 00186 { 00187 XmlRpcUtil::log(2, "XmlRpcServer::acceptConnection: creating a connection"); 00188 XmlRpcServerConnection* c = this->createConnection(s); 00189 if (c) this->dispatchConnection(c); 00190 } 00191 }
XmlRpcServerConnection * XmlRpcServer::createConnection | ( | int | socket | ) | [protected, virtual] |
Create a new connection object for processing requests from a specific client.
If the client is not authorized to connect, close the socket and return 0.
00197 { 00198 // Specify that the connection object be deleted when it is closed 00199 return new XmlRpcServerConnection(s, this, true); 00200 }
void XmlRpcServer::dispatchConnection | ( | XmlRpcServerConnection * | sc | ) | [protected, virtual] |
Hand off a new connection object to a dispatcher.
00206 { 00207 _disp.addSource(sc, XmlRpcDispatch::ReadableEvent); 00208 }
std::string XmlRpcServer::parseRequest | ( | std::string const & | request, | |
XmlRpcValue & | params | |||
) | [protected] |
Parse the methodName and parameters from the request.
00351 { 00352 int offset = 0; // Number of chars parsed from the request 00353 00354 std::string methodName = XmlRpcUtil::parseTag(METHODNAME_TAG, request, &offset); 00355 00356 if (methodName.size() > 0 && XmlRpcUtil::findTag(PARAMS_TAG, request, &offset)) 00357 { 00358 int nArgs = 0; 00359 while (XmlRpcUtil::nextTagIs(PARAM_TAG, request, &offset)) { 00360 params[nArgs++] = XmlRpcValue(request, &offset); 00361 (void) XmlRpcUtil::nextTagIs(PARAM_ETAG, request, &offset); 00362 } 00363 00364 (void) XmlRpcUtil::nextTagIs(PARAMS_ETAG, request, &offset); 00365 } 00366 00367 return methodName; 00368 }
bool XmlRpcServer::executeMethod | ( | const std::string & | methodName, | |
XmlRpcValue & | params, | |||
XmlRpcValue & | result | |||
) | [protected] |
Execute a named method with the specified params.
00375 { 00376 XmlRpcServerMethod* method = findMethod(methodName); 00377 00378 if ( ! method) return false; 00379 00380 method->execute(params, result); 00381 00382 // Ensure a valid result value 00383 if ( ! result.valid()) 00384 result = std::string(); 00385 00386 return true; 00387 }
bool XmlRpcServer::executeMulticall | ( | const std::string & | methodName, | |
XmlRpcValue & | params, | |||
XmlRpcValue & | result | |||
) | [protected] |
Execute multiple calls and return the results in an array.
System.multicall implementation
00394 { 00395 if (methodName != MULTICALL) return false; 00396 00397 // There ought to be 1 parameter, an array of structs 00398 if (params.size() != 1 || params[0].getType() != XmlRpcValue::TypeArray) 00399 throw XmlRpcException(MULTICALL + ": Invalid argument (expected an array)"); 00400 00401 int nc = params[0].size(); 00402 result.setSize(nc); 00403 00404 for (int i=0; i<nc; ++i) { 00405 00406 if ( ! params[0][i].hasMember(METHODNAME) || 00407 ! params[0][i].hasMember(PARAMS)) { 00408 result[i][FAULTCODE] = -1; 00409 result[i][FAULTSTRING] = MULTICALL + 00410 ": Invalid argument (expected a struct with members methodName and params)"; 00411 continue; 00412 } 00413 00414 const std::string& methodName = params[0][i][METHODNAME]; 00415 XmlRpcValue& methodParams = params[0][i][PARAMS]; 00416 00417 XmlRpcValue resultValue; 00418 resultValue.setSize(1); 00419 try { 00420 if ( ! executeMethod(methodName, methodParams, resultValue[0]) && 00421 ! executeMulticall(methodName, params, resultValue[0])) 00422 { 00423 result[i][FAULTCODE] = -1; 00424 result[i][FAULTSTRING] = methodName + ": unknown method name"; 00425 } 00426 else 00427 result[i] = resultValue; 00428 00429 } catch (const XmlRpcException& fault) { 00430 result[i][FAULTCODE] = fault.getCode(); 00431 result[i][FAULTSTRING] = fault.getMessage(); 00432 } 00433 } 00434 00435 return true; 00436 }
std::string XmlRpcServer::generateResponse | ( | std::string const & | resultXml | ) | [protected] |
Construct a response from the result XML.
00442 { 00443 const char RESPONSE_1[] = 00444 "<?xml version=\"1.0\"?>\r\n" 00445 "<methodResponse><params><param>\r\n\t"; 00446 const char RESPONSE_2[] = 00447 "\r\n</param></params></methodResponse>\r\n"; 00448 00449 std::string body = RESPONSE_1 + resultXml + RESPONSE_2; 00450 std::string header = generateHeader(body); 00451 std::string response = header + body; 00452 00453 XmlRpcUtil::log(5, "XmlRpcServer::generateResponse:\n%s\n", response.c_str()); 00454 return response; 00455 }
std::string XmlRpcServer::generateFaultResponse | ( | std::string const & | msg, | |
int | errorCode = -1 | |||
) | [protected] |
Construct a fault response.
00479 { 00480 const char RESPONSE_1[] = 00481 "<?xml version=\"1.0\"?>\r\n" 00482 "<methodResponse><fault>\r\n\t"; 00483 const char RESPONSE_2[] = 00484 "\r\n</fault></methodResponse>\r\n"; 00485 00486 XmlRpcValue faultStruct; 00487 faultStruct[FAULTCODE] = errorCode; 00488 faultStruct[FAULTSTRING] = errorMsg; 00489 std::string body = RESPONSE_1 + faultStruct.toXml() + RESPONSE_2; 00490 std::string header = generateHeader(body); 00491 00492 return header + body; 00493 }
std::string XmlRpcServer::generateHeader | ( | std::string const & | body | ) | [protected] |
Return the appropriate headers for the response.
00461 { 00462 std::string header = 00463 "HTTP/1.1 200 OK\r\n" 00464 "Server: "; 00465 header += XMLRPC_VERSION; 00466 header += "\r\n" 00467 "Content-Type: text/xml\r\n" 00468 "Content-length: "; 00469 00470 char buffLen[40]; 00471 sprintf(buffLen,"%d\r\n\r\n", body.size()); 00472 00473 return header + buffLen; 00474 }
const char XmlRpcServer::METHODNAME_TAG = "<methodName>" [static, protected] |
const char XmlRpcServer::PARAMS_TAG = "<params>" [static, protected] |
const char XmlRpcServer::PARAMS_ETAG = "</params>" [static, protected] |
const char XmlRpcServer::PARAM_TAG = "<param>" [static, protected] |
const char XmlRpcServer::PARAM_ETAG = "</param>" [static, protected] |
const std::string XmlRpc::XmlRpcServer::SYSTEM_MULTICALL [static, protected] |
const std::string XmlRpcServer::METHODNAME = "methodName" [static, protected] |
const std::string XmlRpcServer::PARAMS = "params" [static, protected] |
const std::string XmlRpcServer::FAULTCODE = "faultCode" [static, protected] |
const std::string XmlRpcServer::FAULTSTRING = "faultString" [static, protected] |
bool XmlRpc::XmlRpcServer::_introspectionEnabled [protected] |
Whether the introspection API is supported by this server.
XmlRpcDispatch XmlRpc::XmlRpcServer::_disp [protected] |
Event dispatcher.
MethodMap XmlRpc::XmlRpcServer::_methods [protected] |
Registered RPC methods.
XmlRpcServerMethod* XmlRpc::XmlRpcServer::_listMethods [protected] |
List all registered RPC methods (only available if introspection is enabled).
XmlRpcServerMethod* XmlRpc::XmlRpcServer::_methodHelp [protected] |
Return help string for a specified method (only available if introspection is enabled).