Go to the documentation of this file.00001
00002
00003
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 }
00022
00023
00024 XmlRpcServer::~XmlRpcServer()
00025 {
00026 this->shutdown();
00027 _methods.clear();
00028 delete _listMethods;
00029 delete _methodHelp;
00030 }
00031
00032
00033
00034 void
00035 XmlRpcServer::addMethod(XmlRpcServerMethod* method)
00036 {
00037 _methods[method->name()] = method;
00038 }
00039
00040
00041 void
00042 XmlRpcServer::removeMethod(XmlRpcServerMethod* method)
00043 {
00044 MethodMap::iterator i = _methods.find(method->name());
00045 if (i != _methods.end())
00046 _methods.erase(i);
00047 }
00048
00049
00050 void
00051 XmlRpcServer::removeMethod(const std::string& methodName)
00052 {
00053 MethodMap::iterator i = _methods.find(methodName);
00054 if (i != _methods.end())
00055 _methods.erase(i);
00056 }
00057
00058
00059
00060 XmlRpcServerMethod*
00061 XmlRpcServer::findMethod(const std::string& name) const
00062 {
00063 MethodMap::const_iterator i = _methods.find(name);
00064 if (i == _methods.end())
00065 return 0;
00066 return i->second;
00067 }
00068
00069
00070
00071
00072 bool
00073 XmlRpcServer::bindAndListen(int port, int backlog )
00074 {
00075 int fd = XmlRpcSocket::socket();
00076 if (fd < 0)
00077 {
00078 XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not create socket (%s).", XmlRpcSocket::getErrorMsg().c_str());
00079 return false;
00080 }
00081
00082 this->setfd(fd);
00083
00084
00085 if ( ! XmlRpcSocket::setNonBlocking(fd))
00086 {
00087 this->close();
00088 XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not set socket to non-blocking input mode (%s).", XmlRpcSocket::getErrorMsg().c_str());
00089 return false;
00090 }
00091
00092
00093 if ( ! XmlRpcSocket::setReuseAddr(fd))
00094 {
00095 this->close();
00096 XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not set SO_REUSEADDR socket option (%s).", XmlRpcSocket::getErrorMsg().c_str());
00097 return false;
00098 }
00099
00100
00101 if ( ! XmlRpcSocket::bind(fd, port))
00102 {
00103 this->close();
00104 XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not bind to specified port (%s).", XmlRpcSocket::getErrorMsg().c_str());
00105 return false;
00106 }
00107
00108
00109 if ( ! XmlRpcSocket::listen(fd, backlog))
00110 {
00111 this->close();
00112 XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not set socket in listening mode (%s).", XmlRpcSocket::getErrorMsg().c_str());
00113 return false;
00114 }
00115
00116 _port = XmlRpcSocket::get_port(fd);
00117
00118 XmlRpcUtil::log(2, "XmlRpcServer::bindAndListen: server listening on port %d fd %d", _port, fd);
00119
00120
00121 _disp.addSource(this, XmlRpcDispatch::ReadableEvent);
00122
00123 return true;
00124 }
00125
00126
00127
00128 void
00129 XmlRpcServer::work(double msTime)
00130 {
00131 XmlRpcUtil::log(2, "XmlRpcServer::work: waiting for a connection");
00132 _disp.work(msTime);
00133 }
00134
00135
00136
00137
00138
00139 unsigned
00140 XmlRpcServer::handleEvent(unsigned)
00141 {
00142 acceptConnection();
00143 return XmlRpcDispatch::ReadableEvent;
00144 }
00145
00146
00147
00148
00149 void
00150 XmlRpcServer::acceptConnection()
00151 {
00152 int s = XmlRpcSocket::accept(this->getfd());
00153 XmlRpcUtil::log(2, "XmlRpcServer::acceptConnection: socket %d", s);
00154 if (s < 0)
00155 {
00156
00157 XmlRpcUtil::error("XmlRpcServer::acceptConnection: Could not accept connection (%s).", XmlRpcSocket::getErrorMsg().c_str());
00158 }
00159 else if ( ! XmlRpcSocket::setNonBlocking(s))
00160 {
00161 XmlRpcSocket::close(s);
00162 XmlRpcUtil::error("XmlRpcServer::acceptConnection: Could not set socket to non-blocking input mode (%s).", XmlRpcSocket::getErrorMsg().c_str());
00163 }
00164 else
00165 {
00166 XmlRpcUtil::log(2, "XmlRpcServer::acceptConnection: creating a connection");
00167 _disp.addSource(this->createConnection(s), XmlRpcDispatch::ReadableEvent);
00168 }
00169 }
00170
00171
00172
00173 XmlRpcServerConnection*
00174 XmlRpcServer::createConnection(int s)
00175 {
00176
00177 return new XmlRpcServerConnection(s, this, true);
00178 }
00179
00180
00181 void
00182 XmlRpcServer::removeConnection(XmlRpcServerConnection* sc)
00183 {
00184 _disp.removeSource(sc);
00185 }
00186
00187
00188
00189 void
00190 XmlRpcServer::exit()
00191 {
00192 _disp.exit();
00193 }
00194
00195
00196
00197 void
00198 XmlRpcServer::shutdown()
00199 {
00200
00201 _disp.clear();
00202 }
00203
00204
00205
00206 static const std::string LIST_METHODS("system.listMethods");
00207 static const std::string METHOD_HELP("system.methodHelp");
00208 static const std::string MULTICALL("system.multicall");
00209
00210
00211
00212 class ListMethods : public XmlRpcServerMethod
00213 {
00214 public:
00215 ListMethods(XmlRpcServer* s) : XmlRpcServerMethod(LIST_METHODS, s) {}
00216
00217 void execute(XmlRpcValue&, XmlRpcValue& result)
00218 {
00219 _server->listMethods(result);
00220 }
00221
00222 std::string help() { return std::string("List all methods available on a server as an array of strings"); }
00223 };
00224
00225
00226
00227 class MethodHelp : public XmlRpcServerMethod
00228 {
00229 public:
00230 MethodHelp(XmlRpcServer* s) : XmlRpcServerMethod(METHOD_HELP, s) {}
00231
00232 void execute(XmlRpcValue& params, XmlRpcValue& result)
00233 {
00234 if (params[0].getType() != XmlRpcValue::TypeString)
00235 throw XmlRpcException(METHOD_HELP + ": Invalid argument type");
00236
00237 XmlRpcServerMethod* m = _server->findMethod(params[0]);
00238 if ( ! m)
00239 throw XmlRpcException(METHOD_HELP + ": Unknown method name");
00240
00241 result = m->help();
00242 }
00243
00244 std::string help() { return std::string("Retrieve the help string for a named method"); }
00245 };
00246
00247
00248
00249 void
00250 XmlRpcServer::enableIntrospection(bool enabled)
00251 {
00252 if (_introspectionEnabled == enabled)
00253 return;
00254
00255 _introspectionEnabled = enabled;
00256
00257 if (enabled)
00258 {
00259 if ( ! _listMethods)
00260 {
00261 _listMethods = new ListMethods(this);
00262 _methodHelp = new MethodHelp(this);
00263 } else {
00264 addMethod(_listMethods);
00265 addMethod(_methodHelp);
00266 }
00267 }
00268 else
00269 {
00270 removeMethod(LIST_METHODS);
00271 removeMethod(METHOD_HELP);
00272 }
00273 }
00274
00275
00276 void
00277 XmlRpcServer::listMethods(XmlRpcValue& result)
00278 {
00279 int i = 0;
00280 result.setSize(_methods.size()+1);
00281 for (MethodMap::iterator it=_methods.begin(); it != _methods.end(); ++it)
00282 result[i++] = it->first;
00283
00284
00285 result[i] = MULTICALL;
00286 }
00287
00288
00289