XmlRpcServer.cpp
Go to the documentation of this file.
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 
9 #include "xmlrpcpp/XmlRpcUtil.h"
11 
12 #include <errno.h>
13 #include <string.h>
14 #if !defined(_WINDOWS)
15 # include <sys/resource.h>
16 #else
17 # include <winsock2.h>
18 #endif
19 
20 using namespace XmlRpc;
21 
22 const int XmlRpcServer::FREE_FD_BUFFER = 32;
24 
26  : _introspectionEnabled(false),
27  _listMethods(0),
28  _methodHelp(0),
29  _port(0),
30  _accept_error(false),
31  _accept_retry_time_sec(0.0)
32 {
33  // Ask dispatch not to close this socket if it becomes unreadable.
34  setKeepOpen(true);
35 }
36 
37 
39 {
40  this->shutdown();
41  _methods.clear();
42  delete _listMethods;
43  delete _methodHelp;
44 }
45 
46 
47 // Add a command to the RPC server
48 void
50 {
51  _methods[method->name()] = method;
52 }
53 
54 // Remove a command from the RPC server
55 void
57 {
58  MethodMap::iterator i = _methods.find(method->name());
59  if (i != _methods.end())
60  _methods.erase(i);
61 }
62 
63 // Remove a command from the RPC server by name
64 void
65 XmlRpcServer::removeMethod(const std::string& methodName)
66 {
67  MethodMap::iterator i = _methods.find(methodName);
68  if (i != _methods.end())
69  _methods.erase(i);
70 }
71 
72 
73 // Look up a method by name
75 XmlRpcServer::findMethod(const std::string& name) const
76 {
77  MethodMap::const_iterator i = _methods.find(name);
78  if (i == _methods.end())
79  return 0;
80  return i->second;
81 }
82 
83 
84 // Create a socket, bind to the specified port, and
85 // set it in listen mode to make it available for clients.
86 bool
87 XmlRpcServer::bindAndListen(int port, int backlog /*= 5*/)
88 {
89  int fd = XmlRpcSocket::socket();
90  if (fd < 0)
91  {
92  XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not create socket (%s).", XmlRpcSocket::getErrorMsg().c_str());
93  return false;
94  }
95 
96  this->setfd(fd);
97 
98  // Don't block on reads/writes
100  {
101  this->close();
102  XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not set socket to non-blocking input mode (%s).", XmlRpcSocket::getErrorMsg().c_str());
103  return false;
104  }
105 
106  // Allow this port to be re-bound immediately so server re-starts are not delayed
107  if ( ! XmlRpcSocket::setReuseAddr(fd))
108  {
109  this->close();
110  XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not set SO_REUSEADDR socket option (%s).", XmlRpcSocket::getErrorMsg().c_str());
111  return false;
112  }
113 
114  // Bind to the specified port on the default interface
115  if ( ! XmlRpcSocket::bind(fd, port))
116  {
117  this->close();
118  XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not bind to specified port (%s).", XmlRpcSocket::getErrorMsg().c_str());
119  return false;
120  }
121 
122  // Set in listening mode
123  if ( ! XmlRpcSocket::listen(fd, backlog))
124  {
125  this->close();
126  XmlRpcUtil::error("XmlRpcServer::bindAndListen: Could not set socket in listening mode (%s).", XmlRpcSocket::getErrorMsg().c_str());
127  return false;
128  }
129 
131 
132  XmlRpcUtil::log(2, "XmlRpcServer::bindAndListen: server listening on port %d fd %d", _port, fd);
133 
134  // Notify the dispatcher to listen on this source when we are in work()
136 
137  return true;
138 }
139 
140 
141 // Process client requests for the specified time
142 void
143 XmlRpcServer::work(double msTime)
144 {
145  XmlRpcUtil::log(2, "XmlRpcServer::work: waiting for a connection");
148  }
149  _disp.work(msTime);
150 }
151 
152 
153 
154 // Handle input on the server socket by accepting the connection
155 // and reading the rpc request.
156 unsigned
158 {
159  return acceptConnection();
160 }
161 
162 
163 // Accept a client connection request and create a connection to
164 // handle method calls from the client.
165 unsigned
167 {
168  int s = XmlRpcSocket::accept(this->getfd());
169  XmlRpcUtil::log(2, "XmlRpcServer::acceptConnection: socket %d", s);
170  if (s < 0)
171  {
172  //this->close();
173  XmlRpcUtil::error("XmlRpcServer::acceptConnection: Could not accept connection (%s).", XmlRpcSocket::getErrorMsg().c_str());
174 
175  // Note that there was an accept error; retry in 1 second
176  _accept_error = true;
178  return 0; // Stop monitoring this FD
179  }
180  else if ( !enoughFreeFDs() )
181  {
183  XmlRpcUtil::error("XmlRpcServer::acceptConnection: Rejecting client, not enough free file descriptors");
184  }
185  else if ( ! XmlRpcSocket::setNonBlocking(s))
186  {
188  XmlRpcUtil::error("XmlRpcServer::acceptConnection: Could not set socket to non-blocking input mode (%s).", XmlRpcSocket::getErrorMsg().c_str());
189  }
190  else // Notify the dispatcher to listen for input on this source when we are in work()
191  {
192  _accept_error = false;
193  XmlRpcUtil::log(2, "XmlRpcServer::acceptConnection: creating a connection");
195  }
196  return XmlRpcDispatch::ReadableEvent; // Continue to monitor this fd
197 }
198 
200  // This function is just to check if enough FDs are there.
201  //
202  // If the underlying system calls here fail, this will print an error and
203  // return false
204 
205 #if !defined(_WINDOWS)
206  int free_fds = 0;
207 
208  struct rlimit limit = { .rlim_cur = 0, .rlim_max = 0 };
209 
210  // Get the current soft limit on the number of file descriptors.
211  if(getrlimit(RLIMIT_NOFILE, &limit) == 0) {
212  // If we have infinite file descriptors, always return true.
213  if( limit.rlim_max == RLIM_INFINITY ) {
214  return true;
215  }
216  } else {
217  // The man page for getrlimit says that it can fail if the requested
218  // resource is invalid or the second argument is invalid. I'm not sure
219  // either of these can actually fail in this code, but it's better to
220  // check.
221  XmlRpcUtil::error("XmlRpcServer::enoughFreeFDs: Could not get open file "
222  "limit, getrlimit() failed: %s", strerror(errno));
223  return false;
224  }
225 
226  // List of all file descriptors, used for counting open files.
227  pollfds.resize(limit.rlim_cur > FREE_FD_BUFFER ? FREE_FD_BUFFER : limit.rlim_cur);
228 
229  // Poll the available file descriptors.
230  // The POSIX specification guarantees that rlim_cur will always be less or
231  // equal to the process's initial rlim_max, so we don't need an additional
232  // bounds check here.
233  for(unsigned long long offset=0; offset<limit.rlim_cur; offset += FREE_FD_BUFFER) {
234  for(unsigned int i=0; i<pollfds.size(); i++) {
235  // Set up file descriptor query for all events.
236  pollfds[i].fd = i + offset;
237  pollfds[i].events = POLLIN | POLLPRI | POLLOUT;
238  }
239  if(poll(&pollfds[0], pollfds.size(), 1) >= 0) {
240  for(rlim_t i=0; i<pollfds.size(); i++) {
241  if(pollfds[i].revents & POLLNVAL) {
242  free_fds++;
243  }
244  if (free_fds >= FREE_FD_BUFFER) {
245  // Checked enough FDs are not opened.
246  return true;
247  }
248  }
249  } else {
250  // poll() may fail if interrupted, if the pollfds array is a bad pointer,
251  // if nfds exceeds RLIMIT_NOFILE, or if the system is out of memory.
252  XmlRpcUtil::error("XmlRpcServer::enoughFreeFDs: poll() failed: %s",
253  strerror(errno));
254  }
255  }
256 
257  return false;
258 #else
259  return true;
260 #endif
261 }
262 
263 
264 // Create a new connection object for processing requests from a specific client.
267 {
268  // Specify that the connection object be deleted when it is closed
269  return new XmlRpcServerConnection(s, this, true);
270 }
271 
272 
273 void
275 {
276  _disp.removeSource(sc);
277 }
278 
279 
280 // Stop processing client requests
281 void
283 {
284  _disp.exit();
285 }
286 
287 
288 // Close the server socket file descriptor and stop monitoring connections
289 void
291 {
292  // This closes and destroys all connections as well as closing this socket
293  _disp.clear();
294 }
295 
296 
297 // Introspection support
298 static const std::string LIST_METHODS("system.listMethods");
299 static const std::string METHOD_HELP("system.methodHelp");
300 static const std::string MULTICALL("system.multicall");
301 
302 
303 // List all methods available on a server
305 {
306 public:
308 
310  {
311  _server->listMethods(result);
312  }
313 
314  std::string help() { return std::string("List all methods available on a server as an array of strings"); }
315 };
316 
317 
318 // Retrieve the help string for a named method
320 {
321 public:
323 
324  void execute(XmlRpcValue& params, XmlRpcValue& result)
325  {
326  if (params[0].getType() != XmlRpcValue::TypeString)
327  throw XmlRpcException(METHOD_HELP + ": Invalid argument type");
328 
329  XmlRpcServerMethod* m = _server->findMethod(params[0]);
330  if ( ! m)
331  throw XmlRpcException(METHOD_HELP + ": Unknown method name");
332 
333  result = m->help();
334  }
335 
336  std::string help() { return std::string("Retrieve the help string for a named method"); }
337 };
338 
339 
340 // Specify whether introspection is enabled or not. Default is enabled.
341 void
343 {
344  if (_introspectionEnabled == enabled)
345  return;
346 
347  _introspectionEnabled = enabled;
348 
349  if (enabled)
350  {
351  if ( ! _listMethods)
352  {
353  _listMethods = new ListMethods(this);
354  _methodHelp = new MethodHelp(this);
355  } else {
358  }
359  }
360  else
361  {
364  }
365 }
366 
367 
368 void
370 {
371  int i = 0;
372  result.setSize(_methods.size()+1);
373  for (MethodMap::iterator it=_methods.begin(); it != _methods.end(); ++it)
374  result[i++] = it->first;
375 
376  // Multicall support is built into XmlRpcServerConnection
377  result[i] = MULTICALL;
378 }
379 
380 
381 
XmlRpc::XmlRpcServer::enableIntrospection
void enableIntrospection(bool enabled=true)
Specify whether introspection is enabled or not. Default is not enabled.
Definition: XmlRpcServer.cpp:342
XmlRpc::XmlRpcServer::_disp
XmlRpcDispatch _disp
Definition: XmlRpcServer.h:106
XmlRpc::XmlRpcServer::removeConnection
virtual void removeConnection(XmlRpcServerConnection *)
Remove a connection from the dispatcher.
Definition: XmlRpcServer.cpp:274
XmlRpc::XmlRpcSocket::socket
static int socket()
Creates a stream (TCP) socket. Returns -1 on failure.
Definition: XmlRpcSocket.cpp:101
XmlRpc::XmlRpcServer
A class to handle XML RPC requests.
Definition: XmlRpcServer.h:41
XmlRpc::XmlRpcServerMethod::help
virtual std::string help()
Definition: XmlRpcServerMethod.h:41
s
XmlRpcServer s
Definition: HelloServer.cpp:11
XmlRpc::XmlRpcSource::setfd
void setfd(int fd)
Specify the file descriptor to monitor.
Definition: XmlRpcSource.h:29
XmlRpc::XmlRpcUtil::log
static void log(int level, const char *fmt,...)
Dump messages somewhere.
Definition: XmlRpcUtil.cpp:82
XmlRpc::XmlRpcServer::FREE_FD_BUFFER
static const int FREE_FD_BUFFER
Definition: XmlRpcServer.h:127
XmlRpc::XmlRpcSocket::close
static void close(int socket)
Closes a socket.
Definition: XmlRpcSocket.cpp:109
XmlRpc::XmlRpcSource::setKeepOpen
void setKeepOpen(bool b=true)
Specify whether the file descriptor should be kept open if it is no longer monitored.
Definition: XmlRpcSource.h:34
XmlRpcServer.h
XmlRpc
Definition: XmlRpcClient.h:20
XmlRpc::XmlRpcServer::enoughFreeFDs
bool enoughFreeFDs()
Check if enough number of free file descriptors.
Definition: XmlRpcServer.cpp:199
XmlRpc::XmlRpcServer::_accept_retry_time_sec
double _accept_retry_time_sec
Definition: XmlRpcServer.h:124
XmlRpc::XmlRpcServer::_methodHelp
XmlRpcServerMethod * _methodHelp
Definition: XmlRpcServer.h:114
XmlRpc::XmlRpcDispatch::exit
void exit()
Exit from work routine.
Definition: XmlRpcDispatch.cpp:259
XmlRpc::XmlRpcDispatch::ReadableEvent
@ ReadableEvent
data available to read
Definition: XmlRpcDispatch.h:33
XmlRpc::XmlRpcSource::close
virtual void close()
Close the owned fd. If deleteOnClose was specified at construction, the object is deleted.
Definition: XmlRpcSource.cpp:20
XmlRpc::XmlRpcServer::_accept_error
bool _accept_error
Definition: XmlRpcServer.h:119
XmlRpc::XmlRpcServer::acceptConnection
virtual unsigned acceptConnection()
Accept a client connection request.
Definition: XmlRpcServer.cpp:166
XmlRpc::XmlRpcDispatch::addSource
void addSource(XmlRpcSource *source, unsigned eventMask)
Definition: XmlRpcDispatch.cpp:96
XmlRpc::XmlRpcServer::_introspectionEnabled
bool _introspectionEnabled
Definition: XmlRpcServer.h:103
XmlRpc::XmlRpcSocket::setNonBlocking
static bool setNonBlocking(int socket)
Sets a stream (TCP) socket to perform non-blocking IO. Returns false on failure.
Definition: XmlRpcSocket.cpp:123
XmlRpc::XmlRpcServer::_methods
MethodMap _methods
Definition: XmlRpcServer.h:110
MULTICALL
static const std::string MULTICALL("system.multicall")
XmlRpc::XmlRpcServer::exit
void exit()
Temporarily stop processing client requests and exit the work() method.
Definition: XmlRpcServer.cpp:282
XmlRpc::XmlRpcServer::listMethods
void listMethods(XmlRpcValue &result)
Introspection support.
Definition: XmlRpcServer.cpp:369
XmlRpc::XmlRpcServer::createConnection
virtual XmlRpcServerConnection * createConnection(int socket)
Create a new connection object for processing requests from a specific client.
Definition: XmlRpcServer.cpp:266
XmlRpc::XmlRpcSocket::get_port
static int get_port(int socket)
Definition: XmlRpcSocket.cpp:397
XmlRpc::XmlRpcValue::TypeString
@ TypeString
Definition: XmlRpcValue.h:33
MethodHelp::MethodHelp
MethodHelp(XmlRpcServer *s)
Definition: XmlRpcServer.cpp:322
XmlRpc::XmlRpcServerMethod
Abstract class representing a single RPC method.
Definition: XmlRpcServerMethod.h:26
XmlRpc::XmlRpcServer::_port
int _port
Definition: XmlRpcServer.h:116
XmlRpc::XmlRpcServer::ACCEPT_RETRY_INTERVAL_SEC
static const double ACCEPT_RETRY_INTERVAL_SEC
Definition: XmlRpcServer.h:122
XmlRpc::XmlRpcServer::findMethod
XmlRpcServerMethod * findMethod(const std::string &name) const
Look up a method by name.
Definition: XmlRpcServer.cpp:75
XmlRpc::XmlRpcDispatch::getTime
double getTime()
Definition: XmlRpcDispatch.cpp:281
XmlRpc::XmlRpcUtil::error
static void error(const char *fmt,...)
Dump error messages somewhere.
Definition: XmlRpcUtil.cpp:97
XmlRpcSocket.h
XmlRpc::XmlRpcDispatch::removeSource
void removeSource(XmlRpcSource *source)
Definition: XmlRpcDispatch.cpp:103
XmlRpc::XmlRpcSocket::accept
static int accept(int socket)
Accept a client connection request.
Definition: XmlRpcSocket.cpp:183
XmlRpc::XmlRpcSource::getfd
int getfd() const
Return the file descriptor being monitored.
Definition: XmlRpcSource.h:27
ListMethods::ListMethods
ListMethods(XmlRpcServer *s)
Definition: XmlRpcServer.cpp:307
MethodHelp::help
std::string help()
Definition: XmlRpcServer.cpp:336
XmlRpc::XmlRpcServer::bindAndListen
bool bindAndListen(int port, int backlog=5)
Definition: XmlRpcServer.cpp:87
XmlRpc::XmlRpcException
Definition: XmlRpcException.h:23
XmlRpc::XmlRpcServer::pollfds
std::vector< struct pollfd > pollfds
Definition: XmlRpcServer.h:130
XmlRpc::XmlRpcDispatch::work
void work(double msTime)
Definition: XmlRpcDispatch.cpp:130
LIST_METHODS
static const std::string LIST_METHODS("system.listMethods")
XmlRpc::XmlRpcDispatch::clear
void clear()
Clear all sources from the monitored sources list. Sources are closed.
Definition: XmlRpcDispatch.cpp:266
XmlRpc::XmlRpcServer::shutdown
void shutdown()
Close all connections with clients and the socket file descriptor.
Definition: XmlRpcServer.cpp:290
XmlRpc::XmlRpcServer::handleEvent
virtual unsigned handleEvent(unsigned eventType)
Handle client connection requests.
Definition: XmlRpcServer.cpp:157
XmlRpc::XmlRpcServer::work
void work(double msTime)
Process client requests for the specified time.
Definition: XmlRpcServer.cpp:143
XmlRpc::XmlRpcServerMethod::name
std::string & name()
Returns the name of the method.
Definition: XmlRpcServerMethod.h:34
XmlRpc::XmlRpcSocket::setReuseAddr
static bool setReuseAddr(int socket)
Definition: XmlRpcSocket.cpp:135
XmlRpc::XmlRpcServer::XmlRpcServer
XmlRpcServer()
Create a server object.
Definition: XmlRpcServer.cpp:25
XmlRpcServerMethod.h
XmlRpc::XmlRpcServer::removeMethod
void removeMethod(XmlRpcServerMethod *method)
Remove a command from the RPC server.
Definition: XmlRpcServer.cpp:56
ListMethods
Definition: XmlRpcServer.cpp:304
XmlRpc::XmlRpcServer::addMethod
void addMethod(XmlRpcServerMethod *method)
Add a command to the RPC server.
Definition: XmlRpcServer.cpp:49
XmlRpc::XmlRpcServer::~XmlRpcServer
virtual ~XmlRpcServer()
Destructor.
Definition: XmlRpcServer.cpp:38
XmlRpc::XmlRpcSocket::getErrorMsg
static std::string getErrorMsg()
Returns message corresponding to last error.
Definition: XmlRpcSocket.cpp:383
XmlRpcException.h
XmlRpc::XmlRpcValue::setSize
void setSize(int size)
Specify the size for array values. Array values will grow beyond this size if needed.
Definition: XmlRpcValue.h:130
XmlRpc::XmlRpcSocket::bind
static bool bind(int socket, int port)
Bind to a specified port.
Definition: XmlRpcSocket.cpp:145
ListMethods::help
std::string help()
Definition: XmlRpcServer.cpp:314
METHOD_HELP
static const std::string METHOD_HELP("system.methodHelp")
XmlRpc::XmlRpcServer::_listMethods
XmlRpcServerMethod * _listMethods
Definition: XmlRpcServer.h:113
XmlRpc::XmlRpcServerConnection
A class to handle XML RPC requests from a particular client.
Definition: XmlRpcServerConnection.h:26
ListMethods::execute
void execute(XmlRpcValue &, XmlRpcValue &result)
Execute the method. Subclasses must provide a definition for this method.
Definition: XmlRpcServer.cpp:309
MethodHelp::execute
void execute(XmlRpcValue &params, XmlRpcValue &result)
Execute the method. Subclasses must provide a definition for this method.
Definition: XmlRpcServer.cpp:324
XmlRpcUtil.h
XmlRpc::XmlRpcValue
RPC method arguments and results are represented by Values.
Definition: XmlRpcValue.h:24
XmlRpcServerConnection.h
MethodHelp
Definition: XmlRpcServer.cpp:319
XmlRpc::XmlRpcSocket::listen
static bool listen(int socket, int backlog)
Set socket in listen mode.
Definition: XmlRpcSocket.cpp:176


xmlrpcpp
Author(s): Chris Morley, Konstantin Pilipchuk, Morgan Quigley, Austin Hendrix, Dirk Thomas , Jacob Perron
autogenerated on Sat Apr 26 2025 02:59:11