v01
This commit is contained in:
290
thirdparty/ros/ros_comm/utilities/xmlrpcpp/src/XmlRpcServer.cpp
vendored
Normal file
290
thirdparty/ros/ros_comm/utilities/xmlrpcpp/src/XmlRpcServer.cpp
vendored
Normal file
@@ -0,0 +1,290 @@
|
||||
// this file modified by Morgan Quigley on 22 Apr 2008.
|
||||
// added features: server can be opened on port 0 and you can read back
|
||||
// what port the OS gave you
|
||||
|
||||
#include "xmlrpcpp/XmlRpcServer.h"
|
||||
#include "xmlrpcpp/XmlRpcServerConnection.h"
|
||||
#include "xmlrpcpp/XmlRpcServerMethod.h"
|
||||
#include "xmlrpcpp/XmlRpcSocket.h"
|
||||
#include "xmlrpcpp/XmlRpcUtil.h"
|
||||
#include "xmlrpcpp/XmlRpcException.h"
|
||||
|
||||
|
||||
using namespace XmlRpc;
|
||||
|
||||
|
||||
XmlRpcServer::XmlRpcServer()
|
||||
{
|
||||
_introspectionEnabled = false;
|
||||
_listMethods = 0;
|
||||
_methodHelp = 0;
|
||||
_port = 0;
|
||||
}
|
||||
|
||||
|
||||
XmlRpcServer::~XmlRpcServer()
|
||||
{
|
||||
this->shutdown();
|
||||
_methods.clear();
|
||||
delete _listMethods;
|
||||
delete _methodHelp;
|
||||
}
|
||||
|
||||
|
||||
// Add a command to the RPC server
|
||||
void
|
||||
XmlRpcServer::addMethod(XmlRpcServerMethod* method)
|
||||
{
|
||||
_methods[method->name()] = method;
|
||||
}
|
||||
|
||||
// Remove a command from the RPC server
|
||||
void
|
||||
XmlRpcServer::removeMethod(XmlRpcServerMethod* method)
|
||||
{
|
||||
MethodMap::iterator i = _methods.find(method->name());
|
||||
if (i != _methods.end())
|
||||
_methods.erase(i);
|
||||
}
|
||||
|
||||
// Remove a command from the RPC server by name
|
||||
void
|
||||
XmlRpcServer::removeMethod(const std::string& methodName)
|
||||
{
|
||||
MethodMap::iterator i = _methods.find(methodName);
|
||||
if (i != _methods.end())
|
||||
_methods.erase(i);
|
||||
}
|
||||
|
||||
|
||||
// Look up a method by name
|
||||
XmlRpcServerMethod*
|
||||
XmlRpcServer::findMethod(const std::string& name) const
|
||||
{
|
||||
MethodMap::const_iterator i = _methods.find(name);
|
||||
if (i == _methods.end())
|
||||
return 0;
|
||||
return i->second;
|
||||
}
|
||||
|
||||
|
||||
// Create a socket, bind to the specified port, and
|
||||
// set it in listen mode to make it available for clients.
|
||||
bool
|
||||
XmlRpcServer::bindAndListen(int port, int backlog /*= 5*/)
|
||||
{
|
||||
int fd = XmlRpcSocket::socket();
|
||||
if (fd < 0)
|
||||
{
|
||||
XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not create socket (%s).", XmlRpcSocket::getErrorMsg().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
this->setfd(fd);
|
||||
|
||||
// Don't block on reads/writes
|
||||
if ( ! XmlRpcSocket::setNonBlocking(fd))
|
||||
{
|
||||
this->close();
|
||||
XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not set socket to non-blocking input mode (%s).", XmlRpcSocket::getErrorMsg().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allow this port to be re-bound immediately so server re-starts are not delayed
|
||||
if ( ! XmlRpcSocket::setReuseAddr(fd))
|
||||
{
|
||||
this->close();
|
||||
XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not set SO_REUSEADDR socket option (%s).", XmlRpcSocket::getErrorMsg().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Bind to the specified port on the default interface
|
||||
if ( ! XmlRpcSocket::bind(fd, port))
|
||||
{
|
||||
this->close();
|
||||
XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not bind to specified port (%s).", XmlRpcSocket::getErrorMsg().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set in listening mode
|
||||
if ( ! XmlRpcSocket::listen(fd, backlog))
|
||||
{
|
||||
this->close();
|
||||
XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not set socket in listening mode (%s).", XmlRpcSocket::getErrorMsg().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
_port = XmlRpcSocket::get_port(fd);
|
||||
|
||||
XmlRpcUtil::log(2, "XmlRpcServer::bindAndListen: server listening on port %d fd %d", _port, fd);
|
||||
|
||||
// Notify the dispatcher to listen on this source when we are in work()
|
||||
_disp.addSource(this, XmlRpcDispatch::ReadableEvent);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Process client requests for the specified time
|
||||
void
|
||||
XmlRpcServer::work(double msTime)
|
||||
{
|
||||
XmlRpcUtil::log(2, "XmlRpcServer::work: waiting for a connection");
|
||||
_disp.work(msTime);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Handle input on the server socket by accepting the connection
|
||||
// and reading the rpc request.
|
||||
unsigned
|
||||
XmlRpcServer::handleEvent(unsigned)
|
||||
{
|
||||
acceptConnection();
|
||||
return XmlRpcDispatch::ReadableEvent; // Continue to monitor this fd
|
||||
}
|
||||
|
||||
|
||||
// Accept a client connection request and create a connection to
|
||||
// handle method calls from the client.
|
||||
void
|
||||
XmlRpcServer::acceptConnection()
|
||||
{
|
||||
int s = XmlRpcSocket::accept(this->getfd());
|
||||
XmlRpcUtil::log(2, "XmlRpcServer::acceptConnection: socket %d", s);
|
||||
if (s < 0)
|
||||
{
|
||||
//this->close();
|
||||
XmlRpcUtil::error("XmlRpcServer::acceptConnection: Could not accept connection (%s).", XmlRpcSocket::getErrorMsg().c_str());
|
||||
}
|
||||
else if ( ! XmlRpcSocket::setNonBlocking(s))
|
||||
{
|
||||
XmlRpcSocket::close(s);
|
||||
XmlRpcUtil::error("XmlRpcServer::acceptConnection: Could not set socket to non-blocking input mode (%s).", XmlRpcSocket::getErrorMsg().c_str());
|
||||
}
|
||||
else // Notify the dispatcher to listen for input on this source when we are in work()
|
||||
{
|
||||
XmlRpcUtil::log(2, "XmlRpcServer::acceptConnection: creating a connection");
|
||||
_disp.addSource(this->createConnection(s), XmlRpcDispatch::ReadableEvent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Create a new connection object for processing requests from a specific client.
|
||||
XmlRpcServerConnection*
|
||||
XmlRpcServer::createConnection(int s)
|
||||
{
|
||||
// Specify that the connection object be deleted when it is closed
|
||||
return new XmlRpcServerConnection(s, this, true);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
XmlRpcServer::removeConnection(XmlRpcServerConnection* sc)
|
||||
{
|
||||
_disp.removeSource(sc);
|
||||
}
|
||||
|
||||
|
||||
// Stop processing client requests
|
||||
void
|
||||
XmlRpcServer::exit()
|
||||
{
|
||||
_disp.exit();
|
||||
}
|
||||
|
||||
|
||||
// Close the server socket file descriptor and stop monitoring connections
|
||||
void
|
||||
XmlRpcServer::shutdown()
|
||||
{
|
||||
// This closes and destroys all connections as well as closing this socket
|
||||
_disp.clear();
|
||||
}
|
||||
|
||||
|
||||
// Introspection support
|
||||
static const std::string LIST_METHODS("system.listMethods");
|
||||
static const std::string METHOD_HELP("system.methodHelp");
|
||||
static const std::string MULTICALL("system.multicall");
|
||||
|
||||
|
||||
// List all methods available on a server
|
||||
class ListMethods : public XmlRpcServerMethod
|
||||
{
|
||||
public:
|
||||
ListMethods(XmlRpcServer* s) : XmlRpcServerMethod(LIST_METHODS, s) {}
|
||||
|
||||
void execute(XmlRpcValue&, XmlRpcValue& result)
|
||||
{
|
||||
_server->listMethods(result);
|
||||
}
|
||||
|
||||
std::string help() { return std::string("List all methods available on a server as an array of strings"); }
|
||||
};
|
||||
|
||||
|
||||
// Retrieve the help string for a named method
|
||||
class MethodHelp : public XmlRpcServerMethod
|
||||
{
|
||||
public:
|
||||
MethodHelp(XmlRpcServer* s) : XmlRpcServerMethod(METHOD_HELP, s) {}
|
||||
|
||||
void execute(XmlRpcValue& params, XmlRpcValue& result)
|
||||
{
|
||||
if (params[0].getType() != XmlRpcValue::TypeString)
|
||||
throw XmlRpcException(METHOD_HELP + ": Invalid argument type");
|
||||
|
||||
XmlRpcServerMethod* m = _server->findMethod(params[0]);
|
||||
if ( ! m)
|
||||
throw XmlRpcException(METHOD_HELP + ": Unknown method name");
|
||||
|
||||
result = m->help();
|
||||
}
|
||||
|
||||
std::string help() { return std::string("Retrieve the help string for a named method"); }
|
||||
};
|
||||
|
||||
|
||||
// Specify whether introspection is enabled or not. Default is enabled.
|
||||
void
|
||||
XmlRpcServer::enableIntrospection(bool enabled)
|
||||
{
|
||||
if (_introspectionEnabled == enabled)
|
||||
return;
|
||||
|
||||
_introspectionEnabled = enabled;
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
if ( ! _listMethods)
|
||||
{
|
||||
_listMethods = new ListMethods(this);
|
||||
_methodHelp = new MethodHelp(this);
|
||||
} else {
|
||||
addMethod(_listMethods);
|
||||
addMethod(_methodHelp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
removeMethod(LIST_METHODS);
|
||||
removeMethod(METHOD_HELP);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
XmlRpcServer::listMethods(XmlRpcValue& result)
|
||||
{
|
||||
int i = 0;
|
||||
result.setSize(_methods.size()+1);
|
||||
for (MethodMap::iterator it=_methods.begin(); it != _methods.end(); ++it)
|
||||
result[i++] = it->first;
|
||||
|
||||
// Multicall support is built into XmlRpcServerConnection
|
||||
result[i] = MULTICALL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user