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 _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
00035 void
00036 XmlRpcServer::addMethod(XmlRpcServerMethod* method)
00037 {
00038 _methods[method->name()] = method;
00039 }
00040
00041
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
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
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
00072
00073 bool
00074 XmlRpcServer::bindAndListen(int port, int backlog )
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
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
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
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
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
00122 _disp.addSource(this, XmlRpcDispatch::ReadableEvent);
00123
00124 return true;
00125 }
00126
00127
00128
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
00139
00140 unsigned
00141 XmlRpcServer::handleEvent(unsigned)
00142 {
00143 acceptConnection();
00144 return XmlRpcDispatch::ReadableEvent;
00145 }
00146
00147
00148
00149
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
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
00166 {
00167 XmlRpcUtil::log(2, "XmlRpcServer::acceptConnection: creating a connection");
00168 _disp.addSource(this->createConnection(s), XmlRpcDispatch::ReadableEvent);
00169 }
00170 }
00171
00172
00173
00174 XmlRpcServerConnection*
00175 XmlRpcServer::createConnection(int s)
00176 {
00177
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
00190 void
00191 XmlRpcServer::exit()
00192 {
00193 _disp.exit();
00194 }
00195
00196
00197
00198 void
00199 XmlRpcServer::shutdown()
00200 {
00201
00202 _disp.clear();
00203 }
00204
00205
00206
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
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
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
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
00286 result[i] = MULTICALL;
00287 }
00288
00289
00290