⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xmlrpcclient.cpp

📁 linux下客户端xmlrpc上传文件的client源代码支持上传功能
💻 CPP
字号:
#include "XmlRpcClient.h"#include "XmlRpcSocket.h"#include "XmlRpc.h"#include <stdio.h>#include <stdlib.h>using namespace XmlRpc;// Static dataconst char XmlRpcClient::REQUEST_BEGIN[] =   "<?xml version=\"1.0\"?>\r\n"  "<methodCall><methodName>";const char XmlRpcClient::REQUEST_END_METHODNAME[] = "</methodName>\r\n";const char XmlRpcClient::PARAMS_TAG[] = "<params>";const char XmlRpcClient::PARAMS_ETAG[] = "</params>";const char XmlRpcClient::PARAM_TAG[] = "<param>";const char XmlRpcClient::PARAM_ETAG[] =  "</param>";const char XmlRpcClient::REQUEST_END[] = "</methodCall>\r\n";const char XmlRpcClient::METHODRESPONSE_TAG[] = "<methodResponse>";const char XmlRpcClient::FAULT_TAG[] = "<fault>";XmlRpcClient::XmlRpcClient(const char* host, int port, const char* uri/*=0*/){  XmlRpcUtil::log(1, "XmlRpcClient new client: host %s, port %d.", host, port);  _host = host;  _port = port;  if (uri)    _uri = uri;  else    _uri = "/RPC2";  _connectionState = NO_CONNECTION;  _executing = false;  _eof = false;  // Default to keeping the connection open until an explicit close is done  setKeepOpen();}XmlRpcClient::~XmlRpcClient(){}// Close the owned fdvoid XmlRpcClient::close(){  XmlRpcUtil::log(4, "XmlRpcClient::close: fd %d.", getfd());  _connectionState = NO_CONNECTION;  _disp.exit();  _disp.removeSource(this);  XmlRpcSource::close();}// Clear the referenced flag even if exceptions or errors occur.struct ClearFlagOnExit {  ClearFlagOnExit(bool& flag) : _flag(flag) {}  ~ClearFlagOnExit() { _flag = false; }  bool& _flag;};// Execute the named procedure on the remote server.// Params should be an array of the arguments for the method.// Returns true if the request was sent and a result received (although the result// might be a fault).bool XmlRpcClient::execute(const char* method, XmlRpcValue const& params, XmlRpcValue& result){  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.  if (_executing)    return false;  _executing = true;  ClearFlagOnExit cf(_executing);  _sendAttempts = 0;  _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;}// XmlRpcSource interface implementation// Handle server responses. Called by the event dispatcher during execute.unsignedXmlRpcClient::handleEvent(unsigned eventType){  if (eventType == XmlRpcDispatch::Exception)  {    if (_connectionState == WRITE_REQUEST && _bytesWritten == 0)      XmlRpcUtil::error("Error in XmlRpcClient::handleEvent: could not connect to server (%s).",                        XmlRpcSocket::getErrorMsg().c_str());    else      XmlRpcUtil::error("Error in XmlRpcClient::handleEvent (state %d): %s.",                         _connectionState, XmlRpcSocket::getErrorMsg().c_str());    return 0;  }  if (_connectionState == WRITE_REQUEST)    if ( ! writeRequest()) return 0;  if (_connectionState == READ_HEADER)    if ( ! readHeader()) return 0;  if (_connectionState == READ_RESPONSE)    if ( ! readResponse()) return 0;  // This should probably always ask for Exception events too  return (_connectionState == WRITE_REQUEST)         ? XmlRpcDispatch::WritableEvent : XmlRpcDispatch::ReadableEvent;}// Create the socket connection to the server if necessarybool XmlRpcClient::setupConnection(){  // If an error occurred last time through, or if the server closed the connection, close our end  if ((_connectionState != NO_CONNECTION && _connectionState != IDLE) || _eof)    close();  _eof = false;  if (_connectionState == NO_CONNECTION)    if (! doConnect())       return false;  // Prepare to write the request  _connectionState = WRITE_REQUEST;  _bytesWritten = 0;  // Notify the dispatcher to listen on this source (calls handleEvent when the socket is writable)  _disp.removeSource(this);       // Make sure nothing is left over  _disp.addSource(this, XmlRpcDispatch::WritableEvent | XmlRpcDispatch::Exception);  return true;}// Connect to the xmlrpc serverbool XmlRpcClient::doConnect(){  int fd = XmlRpcSocket::socket();  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  if ( ! XmlRpcSocket::setNonBlocking(fd))  {    this->close();    XmlRpcUtil::error("Error in XmlRpcClient::doConnect: Could not set socket to non-blocking IO mode (%s).", XmlRpcSocket::getErrorMsg().c_str());    return false;  }  if ( ! XmlRpcSocket::connect(fd, _host, _port))  {    this->close();    XmlRpcUtil::error("Error in XmlRpcClient::doConnect: Could not connect to server (%s).", XmlRpcSocket::getErrorMsg().c_str());    return false;  }  return true;}// Encode the request to call the specified method with the specified parameters into xmlbool XmlRpcClient::generateRequest(const char* methodName, XmlRpcValue const& params){  std::string body = REQUEST_BEGIN;  body += methodName;  body += REQUEST_END_METHODNAME;  // If params is an array, each element is a separate parameter  if (params.valid()) {    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;}// Prepend http headersstd::stringXmlRpcClient::generateHeader(std::string const& body){  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;  header += "Content-Type: text/xml\r\nContent-length: ";  sprintf(buff,"%d\r\n\r\n", body.size());  return header + buff;}bool XmlRpcClient::writeRequest(){  if (_bytesWritten == 0)    XmlRpcUtil::log(5, "XmlRpcClient::writeRequest (attempt %d):\n%s\n", _sendAttempts+1, _request.c_str());  // Try to write the request  if ( ! XmlRpcSocket::nbWrite(this->getfd(), _request, &_bytesWritten)) {    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 = "";    _connectionState = READ_HEADER;  }  return true;}// Read the header from the responsebool XmlRpcClient::readHeader(){  // Read available data  if ( ! XmlRpcSocket::nbRead(this->getfd(), _header, &_eof) ||       (_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");      XmlRpcSource::close();      _connectionState = NO_CONNECTION;      _eof = false;      return setupConnection();    }    XmlRpcUtil::error("Error in XmlRpcClient::readHeader: error while reading header (%s) on fd %d.",                      XmlRpcSocket::getErrorMsg().c_str(), getfd());    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)...  _connectionState = READ_RESPONSE;  return true;    // Continue monitoring this source}    bool XmlRpcClient::readResponse(){  // If we dont have the entire response yet, read available data  if (int(_response.length()) < _contentLength) {    if ( ! XmlRpcSocket::nbRead(this->getfd(), _response, &_eof)) {      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());  _connectionState = IDLE;  return false;    // Stop monitoring this source (causes return from work)}// Convert the response xml into a result valuebool XmlRpcClient::parseResponse(XmlRpcValue& result){  // Parse response xml into result  int offset = 0;  if ( ! XmlRpcUtil::findTag(METHODRESPONSE_TAG,_response,&offset)) {    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 ((XmlRpcUtil::nextTagIs(PARAMS_TAG,_response,&offset) &&       XmlRpcUtil::nextTagIs(PARAM_TAG,_response,&offset)) ||      XmlRpcUtil::nextTagIs(FAULT_TAG,_response,&offset) && (_isFault = true))  {    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.valid();}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -