PageRenderTime 44ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/utilities/xmlrpcpp/src/XmlRpcServer.cpp

https://gitlab.com/F34140r/ros_comm
C++ | 289 lines | 198 code | 61 blank | 30 comment | 25 complexity | e8e666574dcd9ef6fbba4e5c6bd55cbd MD5 | raw file
Possible License(s): LGPL-2.1
  1. // this file modified by Morgan Quigley on 22 Apr 2008.
  2. // added features: server can be opened on port 0 and you can read back
  3. // what port the OS gave you
  4. #include "XmlRpcServer.h"
  5. #include "XmlRpcServerConnection.h"
  6. #include "XmlRpcServerMethod.h"
  7. #include "XmlRpcSocket.h"
  8. #include "XmlRpcUtil.h"
  9. #include "XmlRpcException.h"
  10. using namespace XmlRpc;
  11. XmlRpcServer::XmlRpcServer()
  12. {
  13. _introspectionEnabled = false;
  14. _listMethods = 0;
  15. _methodHelp = 0;
  16. }
  17. XmlRpcServer::~XmlRpcServer()
  18. {
  19. this->shutdown();
  20. _methods.clear();
  21. delete _listMethods;
  22. delete _methodHelp;
  23. }
  24. // Add a command to the RPC server
  25. void
  26. XmlRpcServer::addMethod(XmlRpcServerMethod* method)
  27. {
  28. _methods[method->name()] = method;
  29. }
  30. // Remove a command from the RPC server
  31. void
  32. XmlRpcServer::removeMethod(XmlRpcServerMethod* method)
  33. {
  34. MethodMap::iterator i = _methods.find(method->name());
  35. if (i != _methods.end())
  36. _methods.erase(i);
  37. }
  38. // Remove a command from the RPC server by name
  39. void
  40. XmlRpcServer::removeMethod(const std::string& methodName)
  41. {
  42. MethodMap::iterator i = _methods.find(methodName);
  43. if (i != _methods.end())
  44. _methods.erase(i);
  45. }
  46. // Look up a method by name
  47. XmlRpcServerMethod*
  48. XmlRpcServer::findMethod(const std::string& name) const
  49. {
  50. MethodMap::const_iterator i = _methods.find(name);
  51. if (i == _methods.end())
  52. return 0;
  53. return i->second;
  54. }
  55. // Create a socket, bind to the specified port, and
  56. // set it in listen mode to make it available for clients.
  57. bool
  58. XmlRpcServer::bindAndListen(int port, int backlog /*= 5*/)
  59. {
  60. int fd = XmlRpcSocket::socket();
  61. if (fd < 0)
  62. {
  63. XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not create socket (%s).", XmlRpcSocket::getErrorMsg().c_str());
  64. return false;
  65. }
  66. this->setfd(fd);
  67. // Don't block on reads/writes
  68. if ( ! XmlRpcSocket::setNonBlocking(fd))
  69. {
  70. this->close();
  71. XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not set socket to non-blocking input mode (%s).", XmlRpcSocket::getErrorMsg().c_str());
  72. return false;
  73. }
  74. // Allow this port to be re-bound immediately so server re-starts are not delayed
  75. if ( ! XmlRpcSocket::setReuseAddr(fd))
  76. {
  77. this->close();
  78. XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not set SO_REUSEADDR socket option (%s).", XmlRpcSocket::getErrorMsg().c_str());
  79. return false;
  80. }
  81. // Bind to the specified port on the default interface
  82. if ( ! XmlRpcSocket::bind(fd, port))
  83. {
  84. this->close();
  85. XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not bind to specified port (%s).", XmlRpcSocket::getErrorMsg().c_str());
  86. return false;
  87. }
  88. // Set in listening mode
  89. if ( ! XmlRpcSocket::listen(fd, backlog))
  90. {
  91. this->close();
  92. XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not set socket in listening mode (%s).", XmlRpcSocket::getErrorMsg().c_str());
  93. return false;
  94. }
  95. _port = XmlRpcSocket::get_port(fd);
  96. XmlRpcUtil::log(2, "XmlRpcServer::bindAndListen: server listening on port %d fd %d", _port, fd);
  97. // Notify the dispatcher to listen on this source when we are in work()
  98. _disp.addSource(this, XmlRpcDispatch::ReadableEvent);
  99. return true;
  100. }
  101. // Process client requests for the specified time
  102. void
  103. XmlRpcServer::work(double msTime)
  104. {
  105. XmlRpcUtil::log(2, "XmlRpcServer::work: waiting for a connection");
  106. _disp.work(msTime);
  107. }
  108. // Handle input on the server socket by accepting the connection
  109. // and reading the rpc request.
  110. unsigned
  111. XmlRpcServer::handleEvent(unsigned)
  112. {
  113. acceptConnection();
  114. return XmlRpcDispatch::ReadableEvent; // Continue to monitor this fd
  115. }
  116. // Accept a client connection request and create a connection to
  117. // handle method calls from the client.
  118. void
  119. XmlRpcServer::acceptConnection()
  120. {
  121. int s = XmlRpcSocket::accept(this->getfd());
  122. XmlRpcUtil::log(2, "XmlRpcServer::acceptConnection: socket %d", s);
  123. if (s < 0)
  124. {
  125. //this->close();
  126. XmlRpcUtil::error("XmlRpcServer::acceptConnection: Could not accept connection (%s).", XmlRpcSocket::getErrorMsg().c_str());
  127. }
  128. else if ( ! XmlRpcSocket::setNonBlocking(s))
  129. {
  130. XmlRpcSocket::close(s);
  131. XmlRpcUtil::error("XmlRpcServer::acceptConnection: Could not set socket to non-blocking input mode (%s).", XmlRpcSocket::getErrorMsg().c_str());
  132. }
  133. else // Notify the dispatcher to listen for input on this source when we are in work()
  134. {
  135. XmlRpcUtil::log(2, "XmlRpcServer::acceptConnection: creating a connection");
  136. _disp.addSource(this->createConnection(s), XmlRpcDispatch::ReadableEvent);
  137. }
  138. }
  139. // Create a new connection object for processing requests from a specific client.
  140. XmlRpcServerConnection*
  141. XmlRpcServer::createConnection(int s)
  142. {
  143. // Specify that the connection object be deleted when it is closed
  144. return new XmlRpcServerConnection(s, this, true);
  145. }
  146. void
  147. XmlRpcServer::removeConnection(XmlRpcServerConnection* sc)
  148. {
  149. _disp.removeSource(sc);
  150. }
  151. // Stop processing client requests
  152. void
  153. XmlRpcServer::exit()
  154. {
  155. _disp.exit();
  156. }
  157. // Close the server socket file descriptor and stop monitoring connections
  158. void
  159. XmlRpcServer::shutdown()
  160. {
  161. // This closes and destroys all connections as well as closing this socket
  162. _disp.clear();
  163. }
  164. // Introspection support
  165. static const std::string LIST_METHODS("system.listMethods");
  166. static const std::string METHOD_HELP("system.methodHelp");
  167. static const std::string MULTICALL("system.multicall");
  168. // List all methods available on a server
  169. class ListMethods : public XmlRpcServerMethod
  170. {
  171. public:
  172. ListMethods(XmlRpcServer* s) : XmlRpcServerMethod(LIST_METHODS, s) {}
  173. void execute(XmlRpcValue&, XmlRpcValue& result)
  174. {
  175. _server->listMethods(result);
  176. }
  177. std::string help() { return std::string("List all methods available on a server as an array of strings"); }
  178. };
  179. // Retrieve the help string for a named method
  180. class MethodHelp : public XmlRpcServerMethod
  181. {
  182. public:
  183. MethodHelp(XmlRpcServer* s) : XmlRpcServerMethod(METHOD_HELP, s) {}
  184. void execute(XmlRpcValue& params, XmlRpcValue& result)
  185. {
  186. if (params[0].getType() != XmlRpcValue::TypeString)
  187. throw XmlRpcException(METHOD_HELP + ": Invalid argument type");
  188. XmlRpcServerMethod* m = _server->findMethod(params[0]);
  189. if ( ! m)
  190. throw XmlRpcException(METHOD_HELP + ": Unknown method name");
  191. result = m->help();
  192. }
  193. std::string help() { return std::string("Retrieve the help string for a named method"); }
  194. };
  195. // Specify whether introspection is enabled or not. Default is enabled.
  196. void
  197. XmlRpcServer::enableIntrospection(bool enabled)
  198. {
  199. if (_introspectionEnabled == enabled)
  200. return;
  201. _introspectionEnabled = enabled;
  202. if (enabled)
  203. {
  204. if ( ! _listMethods)
  205. {
  206. _listMethods = new ListMethods(this);
  207. _methodHelp = new MethodHelp(this);
  208. } else {
  209. addMethod(_listMethods);
  210. addMethod(_methodHelp);
  211. }
  212. }
  213. else
  214. {
  215. removeMethod(LIST_METHODS);
  216. removeMethod(METHOD_HELP);
  217. }
  218. }
  219. void
  220. XmlRpcServer::listMethods(XmlRpcValue& result)
  221. {
  222. int i = 0;
  223. result.setSize(_methods.size()+1);
  224. for (MethodMap::iterator it=_methods.begin(); it != _methods.end(); ++it)
  225. result[i++] = it->first;
  226. // Multicall support is built into XmlRpcServerConnection
  227. result[i] = MULTICALL;
  228. }