OverSim
XmlRpc::XmlRpcClient Class Reference

A class to send XML RPC requests to a server and return the results. More...

#include <XmlRpcClient.h>

Inheritance diagram for XmlRpc::XmlRpcClient:
XmlRpc::XmlRpcSource

Public Member Functions

 XmlRpcClient (const char *host, int port, const char *uri=0)
 Construct a client to connect to the server at the specified host:port address.
 XmlRpcClient (const char *host, int port, const char *uri=0, bool ssl=false)
 XmlRpcClient (const char *host, int port, const char *login, const char *password, const char *uri=0)
 Construct a client to connect to the server at the specified host:port address including HTTP authentication.
 XmlRpcClient (const char *host, int port, const char *login, const char *password, const char *uri=0, bool ssl=false)
virtual ~XmlRpcClient ()
 Destructor.
bool execute (const char *method, XmlRpcValue const &params, XmlRpcValue &result)
 Execute the named procedure on the remote server.
bool isFault () const
 Returns true if the result of the last execute() was a fault response.
const char *const host () const
 Return the host name of the server.
int getPort () const
 Return the port.
const char *const uri () const
 Return the URI.
virtual void close ()
 Close the connection.
virtual unsigned handleEvent (unsigned eventType)
 Handle server responses.
- Public Member Functions inherited from XmlRpc::XmlRpcSource
 XmlRpcSource (int fd=-1, bool deleteOnClose=false)
 Constructor.
virtual ~XmlRpcSource ()
 Destructor.
int getfd () const
 Return the file descriptor being monitored.
void setfd (int fd)
 Specify the file descriptor to monitor.
bool getKeepOpen () const
 Return whether the file descriptor should be kept open if it is no longer monitored.
void setKeepOpen (bool b=true)
 Specify whether the file descriptor should be kept open if it is no longer monitored.

Static Public Attributes

static const char REQUEST_BEGIN [] = "<methodCall><methodName>"
static const char REQUEST_END_METHODNAME [] = "</methodName>\r\n"
static const char PARAMS_TAG [] = "<params>"
static const char PARAMS_ETAG [] = "</params>"
static const char PARAM_TAG [] = "<param>"
static const char PARAM_ETAG [] = "</param>"
static const char REQUEST_END [] = "</methodCall>\r\n"
static const char METHODRESPONSE_TAG [] = "<methodResponse>"
static const char FAULT_TAG [] = "<fault>"

Protected Types

enum  ClientConnectionState {
  NO_CONNECTION, CONNECTING, WRITE_REQUEST, READ_HEADER,
  READ_RESPONSE, IDLE
}

Protected Member Functions

virtual bool doConnect ()
virtual bool setupConnection ()
virtual bool generateRequest (const char *method, XmlRpcValue const &params)
virtual std::string generateHeader (std::string const &body)
virtual bool writeRequest ()
virtual bool readHeader ()
virtual bool readResponse ()
virtual bool parseResponse (XmlRpcValue &result)

Protected Attributes

ClientConnectionState _connectionState
std::string _host
std::string _uri
int _port
std::string _login
std::string _password
std::string _request
std::string _header
std::string _response
int _sendAttempts
int _bytesWritten
bool _executing
bool _eof
bool _isFault
int _contentLength
XmlRpcDispatch _disp

Additional Inherited Members

- Public Attributes inherited from XmlRpc::XmlRpcSource
bool _ssl
SSL_CTX_ssl_ctx
SSL_ssl_ssl
SSL_METHOD_ssl_meth

Detailed Description

A class to send XML RPC requests to a server and return the results.

Definition at line 32 of file XmlRpcClient.h.

Member Enumeration Documentation

Enumerator:
NO_CONNECTION 
CONNECTING 
WRITE_REQUEST 
READ_HEADER 
READ_RESPONSE 
IDLE 

Definition at line 112 of file XmlRpcClient.h.

Constructor & Destructor Documentation

XmlRpcClient::XmlRpcClient ( const char *  host,
int  port,
const char *  uri = 0 
)

Construct a client to connect to the server at the specified host:port address.

Parameters
hostThe name of the remote machine hosting the server, eg "myserver.mycompany.com"
portThe port on the remote machine where the server is listening
uriAn optional string to be sent as the URI in the HTTP GET header Note that the host is not a URL, do not prepend "http://" or other protocol specifiers.

Definition at line 37 of file XmlRpcClient.cc.

{
XmlRpcUtil::log(1, "XmlRpcClient new client: host %s, port %d.", host, port);
_port = port;
if (uri && *uri)
_uri = uri;
else
_uri = "/RPC2";
_executing = false;
_eof = false;
_ssl = false; _ssl_ssl = (SSL *) NULL;
// Default to keeping the connection open until an explicit close is done
}
XmlRpcClient::XmlRpcClient ( const char *  host,
int  port,
const char *  uri = 0,
bool  ssl = false 
)

Definition at line 55 of file XmlRpcClient.cc.

{
XmlRpcUtil::log(1, "XmlRpcClient new client: host %s, port %d.", host, port);
_port = port;
if (uri && *uri)
_uri = uri;
else
_uri = "/RPC2";
_executing = false;
_eof = false;
_ssl = ssl;
if (!_ssl) { _ssl_ssl = (SSL *) NULL; }
// Default to keeping the connection open until an explicit close is done
}
XmlRpcClient::XmlRpcClient ( const char *  host,
int  port,
const char *  login,
const char *  password,
const char *  uri = 0 
)

Construct a client to connect to the server at the specified host:port address including HTTP authentication.

Parameters
hostThe name of the remote machine hosting the server
portThe port on the remote machine where the server is listening
loginThe username passed to the server
passwordThe password passed to the server
uriAn optional string to be sent as the URI in the HTTP GET header

Definition at line 76 of file XmlRpcClient.cc.

{
XmlRpcUtil::log(1, "XmlRpcClient new client: host %s, port %d, login %s.", host, port, login);
_port = port;
if (uri)
_uri = uri;
else
_uri = "/RPC2";
_login = login;
_password = password;
_executing = false;
_eof = false;
// Default to keeping the connection open until an explicit close is done
}
XmlRpcClient::XmlRpcClient ( const char *  host,
int  port,
const char *  login,
const char *  password,
const char *  uri = 0,
bool  ssl = false 
)

Definition at line 99 of file XmlRpcClient.cc.

{
XmlRpcUtil::log(1, "XmlRpcClient new client: host %s, port %d, login %s.", host, port, login);
_port = port;
if (uri)
_uri = uri;
else
_uri = "/RPC2";
_login = login;
_password = password;
_executing = false;
_eof = false;
_ssl = ssl;
if (!_ssl) { _ssl_ssl = (SSL *) NULL; }
// Default to keeping the connection open until an explicit close is done
}
XmlRpcClient::~XmlRpcClient ( )
virtual

Destructor.

Definition at line 126 of file XmlRpcClient.cc.

{
XmlRpcUtil::log(1, "XmlRpcClient dtor client: host %s, port %d.", _host.c_str(), _port);
}

Member Function Documentation

void XmlRpcClient::close ( )
virtual

Close the connection.

Reimplemented from XmlRpc::XmlRpcSource.

Definition at line 135 of file XmlRpcClient.cc.

{
XmlRpcUtil::log(4, "XmlRpcClient::close: fd %d.", getfd());
if (_ssl) {
// Pre-socket shutdown
XmlRpcUtil::log(4, "XmlRpcClient::close: before SSL_shutdown");
//SSL_shutdown(_ssl_ssl);
XmlRpcUtil::log(4, "XmlRpcClient::close: after SSL_shutdown");
}
if (_ssl) {
// Post-socket shutdown
XmlRpcUtil::log(4, "XmlRpcClient::close: before SSL_free(_ssl_ssl)");
//SSL_free(_ssl_ssl);
XmlRpcUtil::log(4, "XmlRpcClient::close: before SSL_CTX_free(_ssl_ctx)");
//SSL_CTX_free(_ssl_ctx);
XmlRpcUtil::log(4, "XmlRpcClient::close: SSL shutdown successful!");
}
}
bool XmlRpcClient::doConnect ( )
protectedvirtual

Definition at line 267 of file XmlRpcClient.cc.

{
if (fd < 0)
{
XmlRpcUtil::error("Error in XmlRpcClient::doConnect: Could not create socket (%s).", XmlRpcSocket::getErrorMsg().c_str());
return false;
}
XmlRpcUtil::log(3, "XmlRpcClient::doConnect: fd %d.", fd);
this->setfd(fd);
// Don't block on connect/reads/writes
{
this->close();
XmlRpcUtil::error("Error in XmlRpcClient::doConnect: Could not set socket to non-blocking IO mode (%s).", XmlRpcSocket::getErrorMsg().c_str());
return false;
}
{
this->close();
XmlRpcUtil::error("Error in XmlRpcClient::doConnect: Could not connect to server (%s).", XmlRpcSocket::getErrorMsg().c_str());
return false;
}
#ifdef USE_SSL
// Perform SSL if needed
if (_ssl) {
int err = SSL_connect (_ssl_ssl);
}
#endif
return true;
}
bool XmlRpcClient::execute ( const char *  method,
XmlRpcValue const &  params,
XmlRpcValue result 
)

Execute the named procedure on the remote server.

Parameters
methodThe name of the remote procedure to execute
paramsAn array of the arguments for the method
resultThe result value to be returned to the client
Returns
true if the request was sent and a result received (although the result might be a fault).

Currently this is a synchronous (blocking) implementation (execute does not return until it receives a response or an error). Use isFault() to determine whether the result is a fault response.

Definition at line 171 of file XmlRpcClient.cc.

{
XmlRpcUtil::log(1, "XmlRpcClient::execute: method %s (_connectionState %d).", method, _connectionState);
// This is not a thread-safe operation, if you want to do multithreading, use separate
// clients for each thread. If you want to protect yourself from multiple threads
// accessing the same client, replace this code with a real mutex.
return false;
_executing = true;
_isFault = false;
if ( ! setupConnection())
return false;
if ( ! generateRequest(method, params))
return false;
result.clear();
double msTime = -1.0; // Process until exit is called
_disp.work(msTime);
if (_connectionState != IDLE || ! parseResponse(result))
return false;
XmlRpcUtil::log(1, "XmlRpcClient::execute: method %s completed.", method);
_response = "";
return true;
}
std::string XmlRpcClient::generateHeader ( std::string const &  body)
protectedvirtual

Definition at line 351 of file XmlRpcClient.cc.

{
std::string header =
"POST " + _uri + " HTTP/1.1\r\n"
"User-Agent: ";
header += XMLRPC_VERSION;
header += "\r\nHost: ";
header += _host;
char buff[40];
sprintf(buff,":%d\r\n", _port);
header += buff;
if (_login.length() != 0)
{
// convert to base64
std::vector<char> base64data;
int iostatus = 0;
base64<char> encoder;
std::back_insert_iterator<std::vector<char> > ins =
std::back_inserter(base64data);
std::string authBuf = _login + ":" + _password;
encoder.put(authBuf.begin(), authBuf.end(), ins, iostatus,
header += "Authorization: Basic ";
std::string authEnc(base64data.begin(), base64data.end());
// handle pesky linefeed characters
string::size_type lf;
while ( (lf = authEnc.find("\r")) != string::npos ) {
authEnc.erase(lf, 1);
}
while ( (lf = authEnc.find("\n")) != string::npos ) {
authEnc.erase(lf, 1);
}
header += authEnc;
header += "\r\n";
}
header += "Content-Type: text/xml\r\nContent-length: ";
sprintf(buff,"%zu\r\n\r\n", body.size());
return header + buff;
}
bool XmlRpcClient::generateRequest ( const char *  method,
XmlRpcValue const &  params 
)
protectedvirtual

Definition at line 313 of file XmlRpcClient.cc.

{
std::string body = REQUEST_BEGIN;
body += methodName;
// If params is an array, each element is a separate parameter
if (params.isValid()) {
body += PARAMS_TAG;
if (params.getType() == XmlRpcValue::TypeArray)
{
for (int i=0; i<params.size(); ++i) {
body += PARAM_TAG;
body += params[i].toXml();
body += PARAM_ETAG;
}
}
else
{
body += PARAM_TAG;
body += params.toXml();
body += PARAM_ETAG;
}
body += PARAMS_ETAG;
}
body += REQUEST_END;
std::string header = generateHeader(body);
XmlRpcUtil::log(4, "XmlRpcClient::generateRequest: header is %d bytes, content-length is %d.",
header.length(), body.length());
_request = header + body;
return true;
}
int XmlRpc::XmlRpcClient::getPort ( ) const
inline

Return the port.

Definition at line 85 of file XmlRpcClient.h.

{ return _port; }
unsigned XmlRpcClient::handleEvent ( unsigned  eventType)
virtual

Handle server responses.

Called by the event dispatcher during execute.

Parameters
eventTypeThe type of event that occurred.
See Also
XmlRpcDispatch::EventType

Implements XmlRpc::XmlRpcSource.

Definition at line 208 of file XmlRpcClient.cc.

{
if (eventType == XmlRpcDispatch::Exception)
{
//if (XmlRpcSocket::nonFatalError())
// return (_connectionState == WRITE_REQUEST)
// ? XmlRpcDispatch::WritableEvent : XmlRpcDispatch::ReadableEvent;
XmlRpcUtil::error("Error in XmlRpcClient::handleEvent: could not connect to server (%s).",
else
XmlRpcUtil::error("Error in XmlRpcClient::handleEvent (state %d): %s.",
return 0;
}
if ( ! writeRequest()) return 0;
if ( ! readHeader()) return 0;
if ( ! readResponse()) return 0;
// This should probably always ask for Exception events too
}
const char* const XmlRpc::XmlRpcClient::host ( ) const
inline

Return the host name of the server.

Definition at line 82 of file XmlRpcClient.h.

{ return _host.c_str(); }
bool XmlRpc::XmlRpcClient::isFault ( ) const
inline

Returns true if the result of the last execute() was a fault response.

Definition at line 79 of file XmlRpcClient.h.

{ return _isFault; }
bool XmlRpcClient::parseResponse ( XmlRpcValue result)
protectedvirtual

Definition at line 528 of file XmlRpcClient.cc.

{
// Parse response xml into result
int offset = 0;
XmlRpcUtil::error("Error in XmlRpcClient::parseResponse: Invalid response - no methodResponse. Response:\n%s", _response.c_str());
return false;
}
// Expect either <params><param>... or <fault>...
{
if ( ! result.fromXml(_response, &offset)) {
XmlRpcUtil::error("Error in XmlRpcClient::parseResponse: Invalid response value. Response:\n%s", _response.c_str());
_response = "";
return false;
}
} else {
XmlRpcUtil::error("Error in XmlRpcClient::parseResponse: Invalid response - no param or fault tag. Response:\n%s", _response.c_str());
_response = "";
return false;
}
_response = "";
return result.isValid();
}
bool XmlRpcClient::readHeader ( )
protectedvirtual

Definition at line 426 of file XmlRpcClient.cc.

{
// Read available data
(_eof && _header.length() == 0)) {
// If we haven't read any data yet and this is a keep-alive connection, the server may
// have timed out, so we try one more time.
if (getKeepOpen() && _header.length() == 0 && _sendAttempts++ == 0) {
XmlRpcUtil::log(4, "XmlRpcClient::readHeader: re-trying connection");
_eof = false;
return setupConnection();
}
XmlRpcUtil::error("Error in XmlRpcClient::readHeader: error while reading header (%s) on fd %d.",
return false;
}
XmlRpcUtil::log(4, "XmlRpcClient::readHeader: client has read %d bytes", _header.length());
char *hp = (char*)_header.c_str(); // Start of header
char *ep = hp + _header.length(); // End of string
char *bp = 0; // Start of body
char *lp = 0; // Start of content-length value
for (char *cp = hp; (bp == 0) && (cp < ep); ++cp) {
if ((ep - cp > 16) && (strncasecmp(cp, "Content-length: ", 16) == 0))
lp = cp + 16;
else if ((ep - cp > 4) && (strncmp(cp, "\r\n\r\n", 4) == 0))
bp = cp + 4;
else if ((ep - cp > 2) && (strncmp(cp, "\n\n", 2) == 0))
bp = cp + 2;
}
// If we haven't gotten the entire header yet, return (keep reading)
if (bp == 0) {
if (_eof) // EOF in the middle of a response is an error
{
XmlRpcUtil::error("Error in XmlRpcClient::readHeader: EOF while reading header");
return false; // Close the connection
}
return true; // Keep reading
}
// Decode content length
if (lp == 0) {
XmlRpcUtil::error("Error XmlRpcClient::readHeader: No Content-length specified");
return false; // We could try to figure it out by parsing as we read, but for now...
}
_contentLength = atoi(lp);
if (_contentLength <= 0) {
XmlRpcUtil::error("Error in XmlRpcClient::readHeader: Invalid Content-length specified (%d).", _contentLength);
return false;
}
XmlRpcUtil::log(4, "client read content length: %d", _contentLength);
// Otherwise copy non-header data to response buffer and set state to read response.
_response = bp;
_header = ""; // should parse out any interesting bits from the header (connection, etc)...
return true; // Continue monitoring this source
}
bool XmlRpcClient::readResponse ( )
protectedvirtual

Definition at line 497 of file XmlRpcClient.cc.

{
// If we dont have the entire response yet, read available data
if (int(_response.length()) < _contentLength) {
XmlRpcUtil::error("Error in XmlRpcClient::readResponse: read error (%s).",XmlRpcSocket::getErrorMsg().c_str());
return false;
}
// If we haven't gotten the entire _response yet, return (keep reading)
if (int(_response.length()) < _contentLength) {
if (_eof) {
XmlRpcUtil::error("Error in XmlRpcClient::readResponse: EOF while reading response");
return false;
}
return true;
}
}
// Otherwise, parse and return the result
XmlRpcUtil::log(3, "XmlRpcClient::readResponse (read %d bytes)", _response.length());
XmlRpcUtil::log(5, "response:\n%s", _response.c_str());
return false; // Stop monitoring this source (causes return from work)
}
bool XmlRpcClient::setupConnection ( )
protectedvirtual

Definition at line 242 of file XmlRpcClient.cc.

{
// If an error occurred last time through, or if the server closed the connection, close our end
close();
_eof = false;
if (! doConnect())
return false;
// Prepare to write the request
// Notify the dispatcher to listen on this source (calls handleEvent when the socket is writable)
_disp.removeSource(this); // Make sure nothing is left over
return true;
}
const char* const XmlRpc::XmlRpcClient::uri ( ) const
inline

Return the URI.

Definition at line 88 of file XmlRpcClient.h.

{ return _uri.c_str(); }
bool XmlRpcClient::writeRequest ( )
protectedvirtual

Definition at line 401 of file XmlRpcClient.cc.

{
if (_bytesWritten == 0)
XmlRpcUtil::log(5, "XmlRpcClient::writeRequest (attempt %d):\n%s\n", _sendAttempts+1, _request.c_str());
// Try to write the request
XmlRpcUtil::error("Error in XmlRpcClient::writeRequest: write error (%s).",XmlRpcSocket::getErrorMsg().c_str());
return false;
}
XmlRpcUtil::log(3, "XmlRpcClient::writeRequest: wrote %d of %d bytes.", _bytesWritten, _request.length());
// Wait for the result
if (_bytesWritten == int(_request.length())) {
_header = "";
_response = "";
}
return true;
}

Member Data Documentation

int XmlRpc::XmlRpcClient::_bytesWritten
protected

Definition at line 133 of file XmlRpcClient.h.

ClientConnectionState XmlRpc::XmlRpcClient::_connectionState
protected

Definition at line 113 of file XmlRpcClient.h.

int XmlRpc::XmlRpcClient::_contentLength
protected

Definition at line 146 of file XmlRpcClient.h.

XmlRpcDispatch XmlRpc::XmlRpcClient::_disp
protected

Definition at line 149 of file XmlRpcClient.h.

bool XmlRpc::XmlRpcClient::_eof
protected

Definition at line 140 of file XmlRpcClient.h.

bool XmlRpc::XmlRpcClient::_executing
protected

Definition at line 137 of file XmlRpcClient.h.

std::string XmlRpc::XmlRpcClient::_header
protected

Definition at line 126 of file XmlRpcClient.h.

std::string XmlRpc::XmlRpcClient::_host
protected

Definition at line 116 of file XmlRpcClient.h.

Referenced by host().

bool XmlRpc::XmlRpcClient::_isFault
protected

Definition at line 143 of file XmlRpcClient.h.

Referenced by isFault().

std::string XmlRpc::XmlRpcClient::_login
protected

Definition at line 121 of file XmlRpcClient.h.

std::string XmlRpc::XmlRpcClient::_password
protected

Definition at line 122 of file XmlRpcClient.h.

int XmlRpc::XmlRpcClient::_port
protected

Definition at line 118 of file XmlRpcClient.h.

Referenced by getPort().

std::string XmlRpc::XmlRpcClient::_request
protected

Definition at line 125 of file XmlRpcClient.h.

std::string XmlRpc::XmlRpcClient::_response
protected

Definition at line 127 of file XmlRpcClient.h.

int XmlRpc::XmlRpcClient::_sendAttempts
protected

Definition at line 130 of file XmlRpcClient.h.

std::string XmlRpc::XmlRpcClient::_uri
protected

Definition at line 117 of file XmlRpcClient.h.

Referenced by uri().

const char XmlRpcClient::FAULT_TAG = "<fault>"
static

Definition at line 44 of file XmlRpcClient.h.

const char XmlRpcClient::METHODRESPONSE_TAG = "<methodResponse>"
static

Definition at line 43 of file XmlRpcClient.h.

const char XmlRpcClient::PARAM_ETAG = "</param>"
static

Definition at line 40 of file XmlRpcClient.h.

const char XmlRpcClient::PARAM_TAG = "<param>"
static

Definition at line 39 of file XmlRpcClient.h.

const char XmlRpcClient::PARAMS_ETAG = "</params>"
static

Definition at line 38 of file XmlRpcClient.h.

const char XmlRpcClient::PARAMS_TAG = "<params>"
static

Definition at line 37 of file XmlRpcClient.h.

const char XmlRpcClient::REQUEST_BEGIN = "<methodCall><methodName>"
static

Definition at line 35 of file XmlRpcClient.h.

const char XmlRpcClient::REQUEST_END = "</methodCall>\r\n"
static

Definition at line 41 of file XmlRpcClient.h.

const char XmlRpcClient::REQUEST_END_METHODNAME = "</methodName>\r\n"
static

Definition at line 36 of file XmlRpcClient.h.


The documentation for this class was generated from the following files: