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