00001
00007 #include "XmlRpcClient.h"
00008
00009 #include "XmlRpcSocket.h"
00010 #include "XmlRpc.h"
00011
00012 #include "base64.h"
00013
00014 #include <stdio.h>
00015 #include <stdlib.h>
00016 #include <string>
00017 #include <string.h>
00018
00019 using namespace XmlRpc;
00020 using namespace std;
00021
00022
00023 const char XmlRpcClient::REQUEST_BEGIN[] =
00024 "<?xml version=\"1.0\"?>\r\n"
00025 "<methodCall><methodName>";
00026 const char XmlRpcClient::REQUEST_END_METHODNAME[] = "</methodName>\r\n";
00027 const char XmlRpcClient::PARAMS_TAG[] = "<params>";
00028 const char XmlRpcClient::PARAMS_ETAG[] = "</params>";
00029 const char XmlRpcClient::PARAM_TAG[] = "<param>";
00030 const char XmlRpcClient::PARAM_ETAG[] = "</param>";
00031 const char XmlRpcClient::REQUEST_END[] = "</methodCall>\r\n";
00032 const char XmlRpcClient::METHODRESPONSE_TAG[] = "<methodResponse>";
00033 const char XmlRpcClient::FAULT_TAG[] = "<fault>";
00034
00035
00036
00037 XmlRpcClient::XmlRpcClient(const char* host, int port, const char* uri)
00038 {
00039 XmlRpcUtil::log(1, "XmlRpcClient new client: host %s, port %d.", host, port);
00040
00041 _host = host;
00042 _port = port;
00043 if (uri && *uri)
00044 _uri = uri;
00045 else
00046 _uri = "/RPC2";
00047 _connectionState = NO_CONNECTION;
00048 _executing = false;
00049 _eof = false;
00050 _ssl = false; _ssl_ssl = (SSL *) NULL;
00051
00052
00053 setKeepOpen();
00054 }
00055 XmlRpcClient::XmlRpcClient(const char* host, int port, const char* uri, bool ssl)
00056 {
00057 XmlRpcUtil::log(1, "XmlRpcClient new client: host %s, port %d.", host, port);
00058
00059 _host = host;
00060 _port = port;
00061 if (uri && *uri)
00062 _uri = uri;
00063 else
00064 _uri = "/RPC2";
00065 _connectionState = NO_CONNECTION;
00066 _executing = false;
00067 _eof = false;
00068 _ssl = ssl;
00069 if (!_ssl) { _ssl_ssl = (SSL *) NULL; }
00070
00071
00072 setKeepOpen();
00073 }
00074
00075
00076 XmlRpcClient::XmlRpcClient(const char* host, int port,
00077 const char* login, const char* password, const char* uri)
00078 {
00079 XmlRpcUtil::log(1, "XmlRpcClient new client: host %s, port %d, login %s.", host, port, login);
00080
00081 _host = host;
00082 _port = port;
00083 if (uri)
00084 _uri = uri;
00085 else
00086 _uri = "/RPC2";
00087
00088 _login = login;
00089 _password = password;
00090
00091 _connectionState = NO_CONNECTION;
00092 _executing = false;
00093 _eof = false;
00094
00095
00096 setKeepOpen();
00097 }
00098
00099 XmlRpcClient::XmlRpcClient(const char* host, int port,
00100 const char* login, const char* password,
00101 const char* uri, bool ssl)
00102 {
00103 XmlRpcUtil::log(1, "XmlRpcClient new client: host %s, port %d, login %s.", host, port, login);
00104
00105 _host = host;
00106 _port = port;
00107 if (uri)
00108 _uri = uri;
00109 else
00110 _uri = "/RPC2";
00111
00112 _login = login;
00113 _password = password;
00114
00115 _connectionState = NO_CONNECTION;
00116 _executing = false;
00117 _eof = false;
00118 _ssl = ssl;
00119 if (!_ssl) { _ssl_ssl = (SSL *) NULL; }
00120
00121
00122 setKeepOpen();
00123 }
00124
00125
00126 XmlRpcClient::~XmlRpcClient()
00127 {
00128 XmlRpcUtil::log(1, "XmlRpcClient dtor client: host %s, port %d.", _host.c_str(), _port);
00129 if (_connectionState != NO_CONNECTION) close();
00130 }
00131
00132
00133
00134 void
00135 XmlRpcClient::close()
00136 {
00137 XmlRpcUtil::log(4, "XmlRpcClient::close: fd %d.", getfd());
00138 _connectionState = NO_CONNECTION;
00139 _disp.exit();
00140 _disp.removeSource(this);
00141 if (_ssl) {
00142
00143 XmlRpcUtil::log(4, "XmlRpcClient::close: before SSL_shutdown");
00144
00145 XmlRpcUtil::log(4, "XmlRpcClient::close: after SSL_shutdown");
00146 }
00147 XmlRpcSource::close();
00148 if (_ssl) {
00149
00150 XmlRpcUtil::log(4, "XmlRpcClient::close: before SSL_free(_ssl_ssl)");
00151
00152 XmlRpcUtil::log(4, "XmlRpcClient::close: before SSL_CTX_free(_ssl_ctx)");
00153
00154 XmlRpcUtil::log(4, "XmlRpcClient::close: SSL shutdown successful!");
00155 }
00156 }
00157
00158
00159
00160 struct ClearFlagOnExit {
00161 ClearFlagOnExit(bool& flag) : _flag(flag) {}
00162 ~ClearFlagOnExit() { _flag = false; }
00163 bool& _flag;
00164 };
00165
00166
00167
00168
00169
00170 bool
00171 XmlRpcClient::execute(const char* method, XmlRpcValue const& params, XmlRpcValue& result)
00172 {
00173 XmlRpcUtil::log(1, "XmlRpcClient::execute: method %s (_connectionState %d).", method, _connectionState);
00174
00175
00176
00177
00178 if (_executing)
00179 return false;
00180
00181 _executing = true;
00182 ClearFlagOnExit cf(_executing);
00183
00184 _sendAttempts = 0;
00185 _isFault = false;
00186
00187 if ( ! setupConnection())
00188 return false;
00189
00190 if ( ! generateRequest(method, params))
00191 return false;
00192
00193 result.clear();
00194 double msTime = -1.0;
00195 _disp.work(msTime);
00196
00197 if (_connectionState != IDLE || ! parseResponse(result))
00198 return false;
00199
00200 XmlRpcUtil::log(1, "XmlRpcClient::execute: method %s completed.", method);
00201 _response = "";
00202 return true;
00203 }
00204
00205
00206
00207 unsigned
00208 XmlRpcClient::handleEvent(unsigned eventType)
00209 {
00210 if (eventType == XmlRpcDispatch::Exception)
00211 {
00212
00213
00214
00215
00216 if (_connectionState == WRITE_REQUEST && _bytesWritten == 0)
00217 XmlRpcUtil::error("Error in XmlRpcClient::handleEvent: could not connect to server (%s).",
00218 XmlRpcSocket::getErrorMsg().c_str());
00219 else
00220 XmlRpcUtil::error("Error in XmlRpcClient::handleEvent (state %d): %s.",
00221 _connectionState, XmlRpcSocket::getErrorMsg().c_str());
00222 return 0;
00223 }
00224
00225 if (_connectionState == WRITE_REQUEST)
00226 if ( ! writeRequest()) return 0;
00227
00228 if (_connectionState == READ_HEADER)
00229 if ( ! readHeader()) return 0;
00230
00231 if (_connectionState == READ_RESPONSE)
00232 if ( ! readResponse()) return 0;
00233
00234
00235 return (_connectionState == WRITE_REQUEST)
00236 ? XmlRpcDispatch::WritableEvent : XmlRpcDispatch::ReadableEvent;
00237 }
00238
00239
00240
00241 bool
00242 XmlRpcClient::setupConnection()
00243 {
00244
00245 if ((_connectionState != NO_CONNECTION && _connectionState != IDLE) || _eof)
00246 close();
00247
00248 _eof = false;
00249 if (_connectionState == NO_CONNECTION)
00250 if (! doConnect())
00251 return false;
00252
00253
00254 _connectionState = WRITE_REQUEST;
00255 _bytesWritten = 0;
00256
00257
00258 _disp.removeSource(this);
00259 _disp.addSource(this, XmlRpcDispatch::WritableEvent | XmlRpcDispatch::Exception);
00260
00261 return true;
00262 }
00263
00264
00265
00266 bool
00267 XmlRpcClient::doConnect()
00268 {
00269 int fd = XmlRpcSocket::getSocket();
00270 if (fd < 0)
00271 {
00272 XmlRpcUtil::error("Error in XmlRpcClient::doConnect: Could not create socket (%s).", XmlRpcSocket::getErrorMsg().c_str());
00273 return false;
00274 }
00275
00276 XmlRpcUtil::log(3, "XmlRpcClient::doConnect: fd %d.", fd);
00277 this->setfd(fd);
00278
00279
00280 if ( ! XmlRpcSocket::setNonBlocking(fd))
00281 {
00282 this->close();
00283 XmlRpcUtil::error("Error in XmlRpcClient::doConnect: Could not set socket to non-blocking IO mode (%s).", XmlRpcSocket::getErrorMsg().c_str());
00284 return false;
00285 }
00286
00287 if ( ! XmlRpcSocket::connect(fd, _host, _port))
00288 {
00289 this->close();
00290 XmlRpcUtil::error("Error in XmlRpcClient::doConnect: Could not connect to server (%s).", XmlRpcSocket::getErrorMsg().c_str());
00291 return false;
00292 }
00293
00294 #ifdef USE_SSL
00295
00296 if (_ssl) {
00297 SSLeay_add_ssl_algorithms();
00298 _ssl_meth = SSLv23_client_method();
00299 SSL_load_error_strings();
00300 _ssl_ctx = SSL_CTX_new (_ssl_meth);
00301 _ssl_ssl = SSL_new (_ssl_ctx);
00302 SSL_set_fd (_ssl_ssl, fd);
00303 int err = SSL_connect (_ssl_ssl);
00304 }
00305 #endif
00306
00307
00308 return true;
00309 }
00310
00311
00312 bool
00313 XmlRpcClient::generateRequest(const char* methodName, XmlRpcValue const& params)
00314 {
00315 std::string body = REQUEST_BEGIN;
00316 body += methodName;
00317 body += REQUEST_END_METHODNAME;
00318
00319
00320 if (params.isValid()) {
00321 body += PARAMS_TAG;
00322 if (params.getType() == XmlRpcValue::TypeArray)
00323 {
00324 for (int i=0; i<params.size(); ++i) {
00325 body += PARAM_TAG;
00326 body += params[i].toXml();
00327 body += PARAM_ETAG;
00328 }
00329 }
00330 else
00331 {
00332 body += PARAM_TAG;
00333 body += params.toXml();
00334 body += PARAM_ETAG;
00335 }
00336
00337 body += PARAMS_ETAG;
00338 }
00339 body += REQUEST_END;
00340
00341 std::string header = generateHeader(body);
00342 XmlRpcUtil::log(4, "XmlRpcClient::generateRequest: header is %d bytes, content-length is %d.",
00343 header.length(), body.length());
00344
00345 _request = header + body;
00346 return true;
00347 }
00348
00349
00350 std::string
00351 XmlRpcClient::generateHeader(std::string const& body)
00352 {
00353 std::string header =
00354 "POST " + _uri + " HTTP/1.1\r\n"
00355 "User-Agent: ";
00356 header += XMLRPC_VERSION;
00357 header += "\r\nHost: ";
00358 header += _host;
00359
00360 char buff[40];
00361 sprintf(buff,":%d\r\n", _port);
00362
00363 header += buff;
00364
00365 if (_login.length() != 0)
00366 {
00367
00368 std::vector<char> base64data;
00369 int iostatus = 0;
00370 base64<char> encoder;
00371 std::back_insert_iterator<std::vector<char> > ins =
00372 std::back_inserter(base64data);
00373
00374 std::string authBuf = _login + ":" + _password;
00375
00376 encoder.put(authBuf.begin(), authBuf.end(), ins, iostatus,
00377 base64<>::crlf());
00378
00379 header += "Authorization: Basic ";
00380 std::string authEnc(base64data.begin(), base64data.end());
00381
00382 string::size_type lf;
00383 while ( (lf = authEnc.find("\r")) != string::npos ) {
00384 authEnc.erase(lf, 1);
00385 }
00386 while ( (lf = authEnc.find("\n")) != string::npos ) {
00387 authEnc.erase(lf, 1);
00388 }
00389 header += authEnc;
00390 header += "\r\n";
00391 }
00392
00393 header += "Content-Type: text/xml\r\nContent-length: ";
00394
00395 sprintf(buff,"%d\r\n\r\n", body.size());
00396
00397 return header + buff;
00398 }
00399
00400 bool
00401 XmlRpcClient::writeRequest()
00402 {
00403 if (_bytesWritten == 0)
00404 XmlRpcUtil::log(5, "XmlRpcClient::writeRequest (attempt %d):\n%s\n", _sendAttempts+1, _request.c_str());
00405
00406
00407 if ( ! XmlRpcSocket::nbWrite(this->getfd(), _request, &_bytesWritten, _ssl_ssl)) {
00408 XmlRpcUtil::error("Error in XmlRpcClient::writeRequest: write error (%s).",XmlRpcSocket::getErrorMsg().c_str());
00409 return false;
00410 }
00411
00412 XmlRpcUtil::log(3, "XmlRpcClient::writeRequest: wrote %d of %d bytes.", _bytesWritten, _request.length());
00413
00414
00415 if (_bytesWritten == int(_request.length())) {
00416 _header = "";
00417 _response = "";
00418 _connectionState = READ_HEADER;
00419 }
00420 return true;
00421 }
00422
00423
00424
00425 bool
00426 XmlRpcClient::readHeader()
00427 {
00428
00429 if ( ! XmlRpcSocket::nbRead(this->getfd(), _header, &_eof, _ssl_ssl) ||
00430 (_eof && _header.length() == 0)) {
00431
00432
00433
00434 if (getKeepOpen() && _header.length() == 0 && _sendAttempts++ == 0) {
00435 XmlRpcUtil::log(4, "XmlRpcClient::readHeader: re-trying connection");
00436 XmlRpcSource::close();
00437 _connectionState = NO_CONNECTION;
00438 _eof = false;
00439 return setupConnection();
00440 }
00441
00442 XmlRpcUtil::error("Error in XmlRpcClient::readHeader: error while reading header (%s) on fd %d.",
00443 XmlRpcSocket::getErrorMsg().c_str(), getfd());
00444 return false;
00445 }
00446
00447 XmlRpcUtil::log(4, "XmlRpcClient::readHeader: client has read %d bytes", _header.length());
00448
00449 char *hp = (char*)_header.c_str();
00450 char *ep = hp + _header.length();
00451 char *bp = 0;
00452 char *lp = 0;
00453
00454 for (char *cp = hp; (bp == 0) && (cp < ep); ++cp) {
00455 if ((ep - cp > 16) && (strncasecmp(cp, "Content-length: ", 16) == 0))
00456 lp = cp + 16;
00457 else if ((ep - cp > 4) && (strncmp(cp, "\r\n\r\n", 4) == 0))
00458 bp = cp + 4;
00459 else if ((ep - cp > 2) && (strncmp(cp, "\n\n", 2) == 0))
00460 bp = cp + 2;
00461 }
00462
00463
00464 if (bp == 0) {
00465 if (_eof)
00466 {
00467 XmlRpcUtil::error("Error in XmlRpcClient::readHeader: EOF while reading header");
00468 return false;
00469 }
00470
00471 return true;
00472 }
00473
00474
00475 if (lp == 0) {
00476 XmlRpcUtil::error("Error XmlRpcClient::readHeader: No Content-length specified");
00477 return false;
00478 }
00479
00480 _contentLength = atoi(lp);
00481 if (_contentLength <= 0) {
00482 XmlRpcUtil::error("Error in XmlRpcClient::readHeader: Invalid Content-length specified (%d).", _contentLength);
00483 return false;
00484 }
00485
00486 XmlRpcUtil::log(4, "client read content length: %d", _contentLength);
00487
00488
00489 _response = bp;
00490 _header = "";
00491 _connectionState = READ_RESPONSE;
00492 return true;
00493 }
00494
00495
00496 bool
00497 XmlRpcClient::readResponse()
00498 {
00499
00500 if (int(_response.length()) < _contentLength) {
00501 if ( ! XmlRpcSocket::nbRead(this->getfd(), _response, &_eof, _ssl_ssl)) {
00502 XmlRpcUtil::error("Error in XmlRpcClient::readResponse: read error (%s).",XmlRpcSocket::getErrorMsg().c_str());
00503 return false;
00504 }
00505
00506
00507 if (int(_response.length()) < _contentLength) {
00508 if (_eof) {
00509 XmlRpcUtil::error("Error in XmlRpcClient::readResponse: EOF while reading response");
00510 return false;
00511 }
00512 return true;
00513 }
00514 }
00515
00516
00517 XmlRpcUtil::log(3, "XmlRpcClient::readResponse (read %d bytes)", _response.length());
00518 XmlRpcUtil::log(5, "response:\n%s", _response.c_str());
00519
00520 _connectionState = IDLE;
00521
00522 return false;
00523 }
00524
00525
00526
00527 bool
00528 XmlRpcClient::parseResponse(XmlRpcValue& result)
00529 {
00530
00531 int offset = 0;
00532 if ( ! XmlRpcUtil::findTag(METHODRESPONSE_TAG,_response,&offset)) {
00533 XmlRpcUtil::error("Error in XmlRpcClient::parseResponse: Invalid response - no methodResponse. Response:\n%s", _response.c_str());
00534 return false;
00535 }
00536
00537
00538 if ((XmlRpcUtil::nextTagIs(PARAMS_TAG,_response,&offset) &&
00539 XmlRpcUtil::nextTagIs(PARAM_TAG,_response,&offset)) ||
00540 (XmlRpcUtil::nextTagIs(FAULT_TAG,_response,&offset) && (_isFault = true)))
00541 {
00542 if ( ! result.fromXml(_response, &offset)) {
00543 XmlRpcUtil::error("Error in XmlRpcClient::parseResponse: Invalid response value. Response:\n%s", _response.c_str());
00544 _response = "";
00545 return false;
00546 }
00547 } else {
00548 XmlRpcUtil::error("Error in XmlRpcClient::parseResponse: Invalid response - no param or fault tag. Response:\n%s", _response.c_str());
00549 _response = "";
00550 return false;
00551 }
00552
00553 _response = "";
00554 return result.isValid();
00555 }
00556