Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

XmlRpc::XmlRpcServerConnection Class Reference

A class to handle XML RPC requests from a particular client. More...

#include <XmlRpcServerConnection.h>

Inheritance diagram for XmlRpc::XmlRpcServerConnection:

XmlRpc::XmlRpcSource List of all members.

Public Member Functions

virtual void close ()
 Close the owned fd. If deleteOnClose was specified at construction, the object is deleted.
int getfd () const
 Return the file descriptor being monitored.
bool getKeepOpen () const
 Return whether the file descriptor should be kept open if it is no longer monitored.
virtual unsigned handleEvent (unsigned eventType)
void setfd (int fd)
 Specify the file descriptor to monitor.
void setKeepOpen (bool b=true)
 Specify whether the file descriptor should be kept open if it is no longer monitored.
 XmlRpcServerConnection (int fd, XmlRpcServer *server, bool deleteOnClose=false)
 Constructor.
virtual ~XmlRpcServerConnection ()
 Destructor.

Static Public Attributes

const std::string FAULTCODE = "faultCode"
const std::string FAULTSTRING = "faultString"
const std::string METHODNAME = "methodName"
const char METHODNAME_TAG [] = "<methodName>"
const char PARAM_ETAG [] = "</param>"
const char PARAM_TAG [] = "<param>"
const std::string PARAMS = "params"
const char PARAMS_ETAG [] = "</params>"
const char PARAMS_TAG [] = "<params>"
const std::string SYSTEM_MULTICALL = "system.multicall"

Protected Types

enum  ServerConnectionState { READ_HEADER, READ_REQUEST, WRITE_RESPONSE }

Protected Member Functions

bool executeMethod (const std::string &methodName, XmlRpcValue &params, XmlRpcValue &result)
bool executeMulticall (const std::string &methodName, XmlRpcValue &params, XmlRpcValue &result)
virtual void executeRequest ()
void generateFaultResponse (std::string const &msg, int errorCode=-1)
std::string generateHeader (std::string const &body)
void generateResponse (std::string const &resultXml)
std::string parseRequest (XmlRpcValue &params)
bool readHeader ()
bool readRequest ()
bool writeResponse ()

Protected Attributes

int _bytesWritten
ServerConnectionState _connectionState
int _contentLength
std::string _header
bool _keepAlive
std::string _request
std::string _response
XmlRpcServer_server

Detailed Description

A class to handle XML RPC requests from a particular client.


Member Enumeration Documentation

enum XmlRpc::XmlRpcServerConnection::ServerConnectionState [protected]
 

Enumeration values:
READ_HEADER 
READ_REQUEST 
WRITE_RESPONSE 
00079 { READ_HEADER, READ_REQUEST, WRITE_RESPONSE };


Constructor & Destructor Documentation

XmlRpcServerConnection::XmlRpcServerConnection int  fd,
XmlRpcServer server,
bool  deleteOnClose = false
 

Constructor.

00030                                                                                                            :
00031   XmlRpcSource(fd, deleteOnClose)
00032 {
00033   XmlRpcUtil::log(2,"XmlRpcServerConnection: new socket %d.", fd);
00034   _server = server;
00035   _connectionState = READ_HEADER;
00036   _keepAlive = true;
00037 }

XmlRpcServerConnection::~XmlRpcServerConnection  )  [virtual]
 

Destructor.

00041 {
00042   XmlRpcUtil::log(4,"XmlRpcServerConnection dtor.");
00043   _server->removeConnection(this);
00044 }


Member Function Documentation

void XmlRpc::XmlRpcSource::close  )  [virtual, inherited]
 

Close the owned fd. If deleteOnClose was specified at construction, the object is deleted.

Reimplemented in XmlRpc::XmlRpcClient.

00021   {
00022     if (_fd != -1) {
00023       XmlRpcUtil::log(2,"XmlRpcSource::close: closing socket %d.", _fd);
00024       XmlRpcSocket::close(_fd);
00025       XmlRpcUtil::log(2,"XmlRpcSource::close: done closing socket %d.", _fd);
00026       _fd = -1;
00027     }
00028     if (_deleteOnClose) {
00029       XmlRpcUtil::log(2,"XmlRpcSource::close: deleting this");
00030       _deleteOnClose = false;
00031       delete this;
00032     }
00033   }

bool XmlRpcServerConnection::executeMethod const std::string &  methodName,
XmlRpcValue params,
XmlRpcValue result
[protected]
 

00255 {
00256   XmlRpcServerMethod* method = _server->findMethod(methodName);
00257 
00258   if ( ! method) return false;
00259 
00260   method->execute(params, result);
00261 
00262   // Ensure a valid result value
00263   if ( ! result.valid())
00264       result = std::string();
00265 
00266   return true;
00267 }

bool XmlRpcServerConnection::executeMulticall const std::string &  methodName,
XmlRpcValue params,
XmlRpcValue result
[protected]
 

00273 {
00274   if (methodName != SYSTEM_MULTICALL) return false;
00275 
00276   // There ought to be 1 parameter, an array of structs
00277   if (params.size() != 1 || params[0].getType() != XmlRpcValue::TypeArray)
00278     throw XmlRpcException(SYSTEM_MULTICALL + ": Invalid argument (expected an array)");
00279 
00280   int nc = params[0].size();
00281   result.setSize(nc);
00282 
00283   for (int i=0; i<nc; ++i) {
00284 
00285     if ( ! params[0][i].hasMember(METHODNAME) ||
00286          ! params[0][i].hasMember(PARAMS)) {
00287       result[i][FAULTCODE] = -1;
00288       result[i][FAULTSTRING] = SYSTEM_MULTICALL +
00289               ": Invalid argument (expected a struct with members methodName and params)";
00290       continue;
00291     }
00292 
00293     const std::string& methodName = params[0][i][METHODNAME];
00294     XmlRpcValue& methodParams = params[0][i][PARAMS];
00295 
00296     XmlRpcValue resultValue;
00297     resultValue.setSize(1);
00298     try {
00299       if ( ! executeMethod(methodName, methodParams, resultValue[0]) &&
00300            ! executeMulticall(methodName, params, resultValue[0]))
00301       {
00302         result[i][FAULTCODE] = -1;
00303         result[i][FAULTSTRING] = methodName + ": unknown method name";
00304       }
00305       else
00306         result[i] = resultValue;
00307 
00308     } catch (const XmlRpcException& fault) {
00309         result[i][FAULTCODE] = fault.getCode();
00310         result[i][FAULTSTRING] = fault.getMessage();
00311     }
00312   }
00313 
00314   return true;
00315 }

void XmlRpcServerConnection::executeRequest  )  [protected, virtual]
 

00208 {
00209   XmlRpcValue params, resultValue;
00210   std::string methodName = parseRequest(params);
00211   XmlRpcUtil::log(2, "XmlRpcServerConnection::executeRequest: server calling method '%s'", 
00212                     methodName.c_str());
00213 
00214   try {
00215 
00216     if ( ! executeMethod(methodName, params, resultValue) &&
00217          ! executeMulticall(methodName, params, resultValue))
00218       generateFaultResponse(methodName + ": unknown method name");
00219     else
00220       generateResponse(resultValue.toXml());
00221 
00222   } catch (const XmlRpcException& fault) {
00223     XmlRpcUtil::log(2, "XmlRpcServerConnection::executeRequest: fault %s.",
00224                     fault.getMessage().c_str()); 
00225     generateFaultResponse(fault.getMessage(), fault.getCode());
00226   }
00227 }

void XmlRpcServerConnection::generateFaultResponse std::string const &  msg,
int  errorCode = -1
[protected]
 

00356 {
00357   const char RESPONSE_1[] = 
00358     "<?xml version=\"1.0\"?>\r\n"
00359     "<methodResponse><fault>\r\n\t";
00360   const char RESPONSE_2[] =
00361     "\r\n</fault></methodResponse>\r\n";
00362 
00363   XmlRpcValue faultStruct;
00364   faultStruct[FAULTCODE] = errorCode;
00365   faultStruct[FAULTSTRING] = errorMsg;
00366   std::string body = RESPONSE_1 + faultStruct.toXml() + RESPONSE_2;
00367   std::string header = generateHeader(body);
00368 
00369   _response = header + body;
00370 }

std::string XmlRpcServerConnection::generateHeader std::string const &  body  )  [protected]
 

00338 {
00339   std::string header = 
00340     "HTTP/1.1 200 OK\r\n"
00341     "Server: ";
00342   header += XMLRPC_VERSION;
00343   header += "\r\n"
00344     "Content-Type: text/xml\r\n"
00345     "Content-length: ";
00346 
00347   char buffLen[40];
00348   sprintf(buffLen,"%d\r\n\r\n", body.size());
00349 
00350   return header + buffLen;
00351 }

void XmlRpcServerConnection::generateResponse std::string const &  resultXml  )  [protected]
 

00321 {
00322   const char RESPONSE_1[] = 
00323     "<?xml version=\"1.0\"?>\r\n"
00324     "<methodResponse><params><param>\r\n\t";
00325   const char RESPONSE_2[] =
00326     "\r\n</param></params></methodResponse>\r\n";
00327 
00328   std::string body = RESPONSE_1 + resultXml + RESPONSE_2;
00329   std::string header = generateHeader(body);
00330 
00331   _response = header + body;
00332   XmlRpcUtil::log(5, "XmlRpcServerConnection::generateResponse:\n%s\n", _response.c_str()); 
00333 }

int XmlRpc::XmlRpcSource::getfd  )  const [inline, inherited]
 

Return the file descriptor being monitored.

00025 { return _fd; }

bool XmlRpc::XmlRpcSource::getKeepOpen  )  const [inline, inherited]
 

Return whether the file descriptor should be kept open if it is no longer monitored.

00030 { return _keepOpen; }

unsigned XmlRpcServerConnection::handleEvent unsigned  eventType  )  [virtual]
 

Handle IO on the client connection socket.

Parameters:
eventType Type of IO event that occurred.
See also:
XmlRpcDispatch::EventType.

Implements XmlRpc::XmlRpcSource.

00052 {
00053   if (_connectionState == READ_HEADER)
00054     if ( ! readHeader()) return 0;
00055 
00056   if (_connectionState == READ_REQUEST)
00057     if ( ! readRequest()) return 0;
00058 
00059   if (_connectionState == WRITE_RESPONSE)
00060     if ( ! writeResponse()) return 0;
00061 
00062   return (_connectionState == WRITE_RESPONSE) 
00063         ? XmlRpcDispatch::WritableEvent : XmlRpcDispatch::ReadableEvent;
00064 }

std::string XmlRpcServerConnection::parseRequest XmlRpcValue params  )  [protected]
 

00232 {
00233   int offset = 0;   // Number of chars parsed from the request
00234 
00235   std::string methodName = XmlRpcUtil::parseTag(METHODNAME_TAG, _request, &offset);
00236 
00237   if (methodName.size() > 0 && XmlRpcUtil::findTag(PARAMS_TAG, _request, &offset))
00238   {
00239     int nArgs = 0;
00240     while (XmlRpcUtil::nextTagIs(PARAM_TAG, _request, &offset)) {
00241       params[nArgs++] = XmlRpcValue(_request, &offset);
00242       (void) XmlRpcUtil::nextTagIs(PARAM_ETAG, _request, &offset);
00243     }
00244 
00245     (void) XmlRpcUtil::nextTagIs(PARAMS_ETAG, _request, &offset);
00246   }
00247 
00248   return methodName;
00249 }

bool XmlRpcServerConnection::readHeader  )  [protected]
 

00069 {
00070   // Read available data
00071   bool eof;
00072   if ( ! XmlRpcSocket::nbRead(this->getfd(), _header, &eof)) {
00073     // Its only an error if we already have read some data
00074     if (_header.length() > 0)
00075       XmlRpcUtil::error("XmlRpcServerConnection::readHeader: error while reading header (%s).",XmlRpcSocket::getErrorMsg().c_str());
00076     return false;
00077   }
00078 
00079   XmlRpcUtil::log(4, "XmlRpcServerConnection::readHeader: read %d bytes.", _header.length());
00080   char *hp = (char*)_header.c_str();  // Start of header
00081   char *ep = hp + _header.length();   // End of string
00082   char *bp = 0;                       // Start of body
00083   char *lp = 0;                       // Start of content-length value
00084   char *kp = 0;                       // Start of connection value
00085 
00086   for (char *cp = hp; (bp == 0) && (cp < ep); ++cp) {
00087         if ((ep - cp > 16) && (strncasecmp(cp, "Content-length: ", 16) == 0))
00088           lp = cp + 16;
00089         else if ((ep - cp > 12) && (strncasecmp(cp, "Connection: ", 12) == 0))
00090           kp = cp + 12;
00091         else if ((ep - cp > 4) && (strncmp(cp, "\r\n\r\n", 4) == 0))
00092           bp = cp + 4;
00093         else if ((ep - cp > 2) && (strncmp(cp, "\n\n", 2) == 0))
00094           bp = cp + 2;
00095   }
00096 
00097   // If we haven't gotten the entire header yet, return (keep reading)
00098   if (bp == 0) {
00099     // EOF in the middle of a request is an error, otherwise its ok
00100     if (eof) {
00101       XmlRpcUtil::log(4, "XmlRpcServerConnection::readHeader: EOF");
00102       if (_header.length() > 0)
00103         XmlRpcUtil::error("XmlRpcServerConnection::readHeader: EOF while reading header");
00104       return false;   // Either way we close the connection
00105     }
00106     
00107     return true;  // Keep reading
00108   }
00109 
00110   // Decode content length
00111   if (lp == 0) {
00112     XmlRpcUtil::error("XmlRpcServerConnection::readHeader: No Content-length specified");
00113     return false;   // We could try to figure it out by parsing as we read, but for now...
00114   }
00115 
00116   _contentLength = atoi(lp);
00117   if (_contentLength <= 0) {
00118     XmlRpcUtil::error("XmlRpcServerConnection::readHeader: Invalid Content-length specified (%d).", _contentLength);
00119     return false;
00120   }
00121         
00122   XmlRpcUtil::log(3, "XmlRpcServerConnection::readHeader: specified content length is %d.", _contentLength);
00123 
00124   // Otherwise copy non-header data to request buffer and set state to read request.
00125   _request = bp;
00126 
00127   // Parse out any interesting bits from the header (HTTP version, connection)
00128   _keepAlive = true;
00129   if (_header.find("HTTP/1.0") != std::string::npos) {
00130     if (kp == 0 || strncasecmp(kp, "keep-alive", 10) != 0)
00131       _keepAlive = false;           // Default for HTTP 1.0 is to close the connection
00132   } else {
00133     if (kp != 0 && strncasecmp(kp, "close", 5) == 0)
00134       _keepAlive = false;
00135   }
00136   XmlRpcUtil::log(3, "KeepAlive: %d", _keepAlive);
00137 
00138 
00139   _header = ""; 
00140   _connectionState = READ_REQUEST;
00141   return true;    // Continue monitoring this source
00142 }

bool XmlRpcServerConnection::readRequest  )  [protected]
 

00146 {
00147   // If we dont have the entire request yet, read available data
00148   if (int(_request.length()) < _contentLength) {
00149     bool eof;
00150     if ( ! XmlRpcSocket::nbRead(this->getfd(), _request, &eof)) {
00151       XmlRpcUtil::error("XmlRpcServerConnection::readRequest: read error (%s).",XmlRpcSocket::getErrorMsg().c_str());
00152       return false;
00153     }
00154 
00155     // If we haven't gotten the entire request yet, return (keep reading)
00156     if (int(_request.length()) < _contentLength) {
00157       if (eof) {
00158         XmlRpcUtil::error("XmlRpcServerConnection::readRequest: EOF while reading request");
00159         return false;   // Either way we close the connection
00160       }
00161       return true;
00162     }
00163   }
00164 
00165   // Otherwise, parse and dispatch the request
00166   XmlRpcUtil::log(3, "XmlRpcServerConnection::readRequest read %d bytes.", _request.length());
00167   //XmlRpcUtil::log(5, "XmlRpcServerConnection::readRequest:\n%s\n", _request.c_str());
00168 
00169   _connectionState = WRITE_RESPONSE;
00170 
00171   return true;    // Continue monitoring this source
00172 }

void XmlRpc::XmlRpcSource::setfd int  fd  )  [inline, inherited]
 

Specify the file descriptor to monitor.

00027 { _fd = fd; }

void XmlRpc::XmlRpcSource::setKeepOpen bool  b = true  )  [inline, inherited]
 

Specify whether the file descriptor should be kept open if it is no longer monitored.

00032 { _keepOpen = b; }

bool XmlRpcServerConnection::writeResponse  )  [protected]
 

00177 {
00178   if (_response.length() == 0) {
00179     executeRequest();
00180     _bytesWritten = 0;
00181     if (_response.length() == 0) {
00182       XmlRpcUtil::error("XmlRpcServerConnection::writeResponse: empty response.");
00183       return false;
00184     }
00185   }
00186 
00187   // Try to write the response
00188   if ( ! XmlRpcSocket::nbWrite(this->getfd(), _response, &_bytesWritten)) {
00189     XmlRpcUtil::error("XmlRpcServerConnection::writeResponse: write error (%s).",XmlRpcSocket::getErrorMsg().c_str());
00190     return false;
00191   }
00192   XmlRpcUtil::log(3, "XmlRpcServerConnection::writeResponse: wrote %d of %d bytes.", _bytesWritten, _response.length());
00193 
00194   // Prepare to read the next request
00195   if (_bytesWritten == int(_response.length())) {
00196     _header = "";
00197     _request = "";
00198     _response = "";
00199     _connectionState = READ_HEADER;
00200   }
00201 
00202   return _keepAlive;    // Continue monitoring this source if true
00203 }


Member Data Documentation

int XmlRpc::XmlRpcServerConnection::_bytesWritten [protected]
 

ServerConnectionState XmlRpc::XmlRpcServerConnection::_connectionState [protected]
 

int XmlRpc::XmlRpcServerConnection::_contentLength [protected]
 

std::string XmlRpc::XmlRpcServerConnection::_header [protected]
 

bool XmlRpc::XmlRpcServerConnection::_keepAlive [protected]
 

std::string XmlRpc::XmlRpcServerConnection::_request [protected]
 

std::string XmlRpc::XmlRpcServerConnection::_response [protected]
 

XmlRpcServer* XmlRpc::XmlRpcServerConnection::_server [protected]
 

const std::string XmlRpcServerConnection::FAULTCODE = "faultCode" [static]
 

const std::string XmlRpcServerConnection::FAULTSTRING = "faultString" [static]
 

const std::string XmlRpcServerConnection::METHODNAME = "methodName" [static]
 

const char XmlRpcServerConnection::METHODNAME_TAG = "<methodName>" [static]
 

const char XmlRpcServerConnection::PARAM_ETAG = "</param>" [static]
 

const char XmlRpcServerConnection::PARAM_TAG = "<param>" [static]
 

const std::string XmlRpcServerConnection::PARAMS = "params" [static]
 

const char XmlRpcServerConnection::PARAMS_ETAG = "</params>" [static]
 

const char XmlRpcServerConnection::PARAMS_TAG = "<params>" [static]
 

const std::string XmlRpcServerConnection::SYSTEM_MULTICALL = "system.multicall" [static]
 


The documentation for this class was generated from the following files:
Generated on Wed Feb 2 19:25:32 2011 for BOSS6.5.5 by  doxygen 1.3.9.1