#include "XmlRpcClient.h"
#include "XmlRpcSocket.h"
#include "XmlRpc.h"
#include <stdio.h>
#include <stdlib.h>
using namespace XmlRpc;
// Static data
const 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 fd
void
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.
unsigned
XmlRpcClient::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 necessary
bool
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 server
bool
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 xml
bool
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 headers
std::string
XmlRpcClient::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 response
bool
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() && _heade
XmlRpcClient.zip_xml_xml rpc_xmlrpc
版权申诉
76 浏览量
2022-09-19
13:17:23
上传
评论
收藏 4KB ZIP 举报
四散
- 粉丝: 51
- 资源: 1万+
最新资源
- 部署yolov8的tensorrt模型支持检测分割姿态估计的C++源码+部署步骤.zip
- 以简单、易用、高性能为目标、开源的时序数据库,支持Linux及Windows, Time Series Database.zip
- python-leetcode面试题解之第198题打家劫舍-题解.zip
- python-leetcode面试题解之第191题位1的个数-题解.zip
- python-leetcode面试题解之第186题反转字符串中的单词II-题解.zip
- 一个基于python的web后端高性能开发框架,下载可用
- python-leetcode面试题解之第179题最大数-题解.zip
- python-leetcode面试题解之第170题两数之和III数据结构设计-题解.zip
- python-leetcode面试题解之第168题Excel表列名称-题解.zip
- python-leetcode面试题解之第167题两数之和II输入有序数组-题解.zip
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈