XmlRpcServer.cpp
Go to the documentation of this file.
00001 // this file modified by Morgan Quigley on 22 Apr 2008.
00002 // added features: server can be opened on port 0 and you can read back
00003 // what port the OS gave you
00004 
00005 #include "XmlRpcServer.h"
00006 #include "XmlRpcServerConnection.h"
00007 #include "XmlRpcServerMethod.h"
00008 #include "XmlRpcSocket.h"
00009 #include "XmlRpcUtil.h"
00010 #include "XmlRpcException.h"
00011 
00012 
00013 using namespace XmlRpc;
00014 
00015 
00016 XmlRpcServer::XmlRpcServer()
00017 {
00018   _introspectionEnabled = false;
00019   _listMethods = 0;
00020   _methodHelp = 0;
00021   _port = 0;
00022 }
00023 
00024 
00025 XmlRpcServer::~XmlRpcServer()
00026 {
00027   this->shutdown();
00028   _methods.clear();
00029   delete _listMethods;
00030   delete _methodHelp;
00031 }
00032 
00033 
00034 // Add a command to the RPC server
00035 void 
00036 XmlRpcServer::addMethod(XmlRpcServerMethod* method)
00037 {
00038   _methods[method->name()] = method;
00039 }
00040 
00041 // Remove a command from the RPC server
00042 void 
00043 XmlRpcServer::removeMethod(XmlRpcServerMethod* method)
00044 {
00045   MethodMap::iterator i = _methods.find(method->name());
00046   if (i != _methods.end())
00047     _methods.erase(i);
00048 }
00049 
00050 // Remove a command from the RPC server by name
00051 void 
00052 XmlRpcServer::removeMethod(const std::string& methodName)
00053 {
00054   MethodMap::iterator i = _methods.find(methodName);
00055   if (i != _methods.end())
00056     _methods.erase(i);
00057 }
00058 
00059 
00060 // Look up a method by name
00061 XmlRpcServerMethod* 
00062 XmlRpcServer::findMethod(const std::string& name) const
00063 {
00064   MethodMap::const_iterator i = _methods.find(name);
00065   if (i == _methods.end())
00066     return 0;
00067   return i->second;
00068 }
00069 
00070 
00071 // Create a socket, bind to the specified port, and
00072 // set it in listen mode to make it available for clients.
00073 bool 
00074 XmlRpcServer::bindAndListen(int port, int backlog /*= 5*/)
00075 {
00076   int fd = XmlRpcSocket::socket();
00077   if (fd < 0)
00078   {
00079     XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not create socket (%s).", XmlRpcSocket::getErrorMsg().c_str());
00080     return false;
00081   }
00082 
00083   this->setfd(fd);
00084 
00085   // Don't block on reads/writes
00086   if ( ! XmlRpcSocket::setNonBlocking(fd))
00087   {
00088     this->close();
00089     XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not set socket to non-blocking input mode (%s).", XmlRpcSocket::getErrorMsg().c_str());
00090     return false;
00091   }
00092 
00093   // Allow this port to be re-bound immediately so server re-starts are not delayed
00094   if ( ! XmlRpcSocket::setReuseAddr(fd))
00095   {
00096     this->close();
00097     XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not set SO_REUSEADDR socket option (%s).", XmlRpcSocket::getErrorMsg().c_str());
00098     return false;
00099   }
00100 
00101   // Bind to the specified port on the default interface
00102   if ( ! XmlRpcSocket::bind(fd, port))
00103   {
00104     this->close();
00105     XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not bind to specified port (%s).", XmlRpcSocket::getErrorMsg().c_str());
00106     return false;
00107   }
00108 
00109   // Set in listening mode
00110   if ( ! XmlRpcSocket::listen(fd, backlog))
00111   {
00112     this->close();
00113     XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not set socket in listening mode (%s).", XmlRpcSocket::getErrorMsg().c_str());
00114     return false;
00115   }
00116 
00117   _port = XmlRpcSocket::get_port(fd);
00118 
00119   XmlRpcUtil::log(2, "XmlRpcServer::bindAndListen: server listening on port %d fd %d", _port, fd);
00120 
00121   // Notify the dispatcher to listen on this source when we are in work()
00122   _disp.addSource(this, XmlRpcDispatch::ReadableEvent);
00123 
00124   return true;
00125 }
00126 
00127 
00128 // Process client requests for the specified time
00129 void 
00130 XmlRpcServer::work(double msTime)
00131 {
00132   XmlRpcUtil::log(2, "XmlRpcServer::work: waiting for a connection");
00133   _disp.work(msTime);
00134 }
00135 
00136 
00137 
00138 // Handle input on the server socket by accepting the connection
00139 // and reading the rpc request.
00140 unsigned
00141 XmlRpcServer::handleEvent(unsigned)
00142 {
00143   acceptConnection();
00144   return XmlRpcDispatch::ReadableEvent;         // Continue to monitor this fd
00145 }
00146 
00147 
00148 // Accept a client connection request and create a connection to
00149 // handle method calls from the client.
00150 void
00151 XmlRpcServer::acceptConnection()
00152 {
00153   int s = XmlRpcSocket::accept(this->getfd());
00154   XmlRpcUtil::log(2, "XmlRpcServer::acceptConnection: socket %d", s);
00155   if (s < 0)
00156   {
00157     //this->close();
00158     XmlRpcUtil::error("XmlRpcServer::acceptConnection: Could not accept connection (%s).", XmlRpcSocket::getErrorMsg().c_str());
00159   }
00160   else if ( ! XmlRpcSocket::setNonBlocking(s))
00161   {
00162     XmlRpcSocket::close(s);
00163     XmlRpcUtil::error("XmlRpcServer::acceptConnection: Could not set socket to non-blocking input mode (%s).", XmlRpcSocket::getErrorMsg().c_str());
00164   }
00165   else  // Notify the dispatcher to listen for input on this source when we are in work()
00166   {
00167     XmlRpcUtil::log(2, "XmlRpcServer::acceptConnection: creating a connection");
00168     _disp.addSource(this->createConnection(s), XmlRpcDispatch::ReadableEvent);
00169   }
00170 }
00171 
00172 
00173 // Create a new connection object for processing requests from a specific client.
00174 XmlRpcServerConnection*
00175 XmlRpcServer::createConnection(int s)
00176 {
00177   // Specify that the connection object be deleted when it is closed
00178   return new XmlRpcServerConnection(s, this, true);
00179 }
00180 
00181 
00182 void 
00183 XmlRpcServer::removeConnection(XmlRpcServerConnection* sc)
00184 {
00185   _disp.removeSource(sc);
00186 }
00187 
00188 
00189 // Stop processing client requests
00190 void 
00191 XmlRpcServer::exit()
00192 {
00193   _disp.exit();
00194 }
00195 
00196 
00197 // Close the server socket file descriptor and stop monitoring connections
00198 void 
00199 XmlRpcServer::shutdown()
00200 {
00201   // This closes and destroys all connections as well as closing this socket
00202   _disp.clear();
00203 }
00204 
00205 
00206 // Introspection support
00207 static const std::string LIST_METHODS("system.listMethods");
00208 static const std::string METHOD_HELP("system.methodHelp");
00209 static const std::string MULTICALL("system.multicall");
00210 
00211 
00212 // List all methods available on a server
00213 class ListMethods : public XmlRpcServerMethod
00214 {
00215 public:
00216   ListMethods(XmlRpcServer* s) : XmlRpcServerMethod(LIST_METHODS, s) {}
00217 
00218   void execute(XmlRpcValue&, XmlRpcValue& result)
00219   {
00220     _server->listMethods(result);
00221   }
00222 
00223   std::string help() { return std::string("List all methods available on a server as an array of strings"); }
00224 };
00225 
00226 
00227 // Retrieve the help string for a named method
00228 class MethodHelp : public XmlRpcServerMethod
00229 {
00230 public:
00231   MethodHelp(XmlRpcServer* s) : XmlRpcServerMethod(METHOD_HELP, s) {}
00232 
00233   void execute(XmlRpcValue& params, XmlRpcValue& result)
00234   {
00235     if (params[0].getType() != XmlRpcValue::TypeString)
00236       throw XmlRpcException(METHOD_HELP + ": Invalid argument type");
00237 
00238     XmlRpcServerMethod* m = _server->findMethod(params[0]);
00239     if ( ! m)
00240       throw XmlRpcException(METHOD_HELP + ": Unknown method name");
00241 
00242     result = m->help();
00243   }
00244 
00245   std::string help() { return std::string("Retrieve the help string for a named method"); }
00246 };
00247 
00248     
00249 // Specify whether introspection is enabled or not. Default is enabled.
00250 void 
00251 XmlRpcServer::enableIntrospection(bool enabled)
00252 {
00253   if (_introspectionEnabled == enabled)
00254     return;
00255 
00256   _introspectionEnabled = enabled;
00257 
00258   if (enabled)
00259   {
00260     if ( ! _listMethods)
00261     {
00262       _listMethods = new ListMethods(this);
00263       _methodHelp = new MethodHelp(this);
00264     } else {
00265       addMethod(_listMethods);
00266       addMethod(_methodHelp);
00267     }
00268   }
00269   else
00270   {
00271     removeMethod(LIST_METHODS);
00272     removeMethod(METHOD_HELP);
00273   }
00274 }
00275 
00276 
00277 void
00278 XmlRpcServer::listMethods(XmlRpcValue& result)
00279 {
00280   int i = 0;
00281   result.setSize(_methods.size()+1);
00282   for (MethodMap::iterator it=_methods.begin(); it != _methods.end(); ++it)
00283     result[i++] = it->first;
00284 
00285   // Multicall support is built into XmlRpcServerConnection
00286   result[i] = MULTICALL;
00287 }
00288 
00289 
00290 


xmlrpcpp
Author(s): Chris Morley, Konstantin Pilipchuk, Morgan Quigley
autogenerated on Tue Mar 7 2017 03:44:43