$search
00001 00002 #include "XmlRpcClient.h" 00003 00004 #include "XmlRpcSocket.h" 00005 #include "XmlRpc.h" 00006 00007 #include <stdio.h> 00008 #include <stdlib.h> 00009 #ifndef _WINDOWS 00010 # include <strings.h> 00011 #endif 00012 #include <string.h> 00013 00014 00015 using namespace XmlRpc; 00016 00017 // Static data 00018 const char XmlRpcClient::REQUEST_BEGIN[] = 00019 "<?xml version=\"1.0\"?>\r\n" 00020 "<methodCall><methodName>"; 00021 const char XmlRpcClient::REQUEST_END_METHODNAME[] = "</methodName>\r\n"; 00022 const char XmlRpcClient::PARAMS_TAG[] = "<params>"; 00023 const char XmlRpcClient::PARAMS_ETAG[] = "</params>"; 00024 const char XmlRpcClient::PARAM_TAG[] = "<param>"; 00025 const char XmlRpcClient::PARAM_ETAG[] = "</param>"; 00026 const char XmlRpcClient::REQUEST_END[] = "</methodCall>\r\n"; 00027 const char XmlRpcClient::METHODRESPONSE_TAG[] = "<methodResponse>"; 00028 const char XmlRpcClient::FAULT_TAG[] = "<fault>"; 00029 00030 00031 00032 XmlRpcClient::XmlRpcClient(const char* host, int port, const char* uri/*=0*/) 00033 { 00034 XmlRpcUtil::log(1, "XmlRpcClient new client: host %s, port %d.", host, port); 00035 00036 _host = host; 00037 _port = port; 00038 if (uri) 00039 _uri = uri; 00040 else 00041 _uri = "/RPC2"; 00042 _connectionState = NO_CONNECTION; 00043 _executing = false; 00044 _eof = false; 00045 00046 // Default to keeping the connection open until an explicit close is done 00047 setKeepOpen(); 00048 } 00049 00050 00051 XmlRpcClient::~XmlRpcClient() 00052 { 00053 this->close(); 00054 } 00055 00056 // Close the owned fd 00057 void 00058 XmlRpcClient::close() 00059 { 00060 XmlRpcUtil::log(4, "XmlRpcClient::close: fd %d.", getfd()); 00061 _connectionState = NO_CONNECTION; 00062 _disp.exit(); 00063 _disp.removeSource(this); 00064 XmlRpcSource::close(); 00065 } 00066 00067 00068 // Clear the referenced flag even if exceptions or errors occur. 00069 struct ClearFlagOnExit { 00070 ClearFlagOnExit(bool& flag) : _flag(flag) {} 00071 ~ClearFlagOnExit() { _flag = false; } 00072 bool& _flag; 00073 }; 00074 00075 // Execute the named procedure on the remote server. 00076 // Params should be an array of the arguments for the method. 00077 // Returns true if the request was sent and a result received (although the result 00078 // might be a fault). 00079 bool 00080 XmlRpcClient::execute(const char* method, XmlRpcValue const& params, XmlRpcValue& result) 00081 { 00082 XmlRpcUtil::log(1, "XmlRpcClient::execute: method %s (_connectionState %d).", method, _connectionState); 00083 00084 // This is not a thread-safe operation, if you want to do multithreading, use separate 00085 // clients for each thread. If you want to protect yourself from multiple threads 00086 // accessing the same client, replace this code with a real mutex. 00087 if (_executing) 00088 return false; 00089 00090 _executing = true; 00091 ClearFlagOnExit cf(_executing); 00092 00093 _sendAttempts = 0; 00094 _isFault = false; 00095 00096 if ( ! setupConnection()) 00097 return false; 00098 00099 if ( ! generateRequest(method, params)) 00100 return false; 00101 00102 result.clear(); 00103 double msTime = -1.0; // Process until exit is called 00104 _disp.work(msTime); 00105 00106 if (_connectionState != IDLE || ! parseResponse(result)) 00107 return false; 00108 00109 XmlRpcUtil::log(1, "XmlRpcClient::execute: method %s completed.", method); 00110 _response = ""; 00111 return true; 00112 } 00113 00114 // Execute the named procedure on the remote server, non-blocking. 00115 // Params should be an array of the arguments for the method. 00116 // Returns true if the request was sent and a result received (although the result 00117 // might be a fault). 00118 bool 00119 XmlRpcClient::executeNonBlock(const char* method, XmlRpcValue const& params) 00120 { 00121 XmlRpcUtil::log(1, "XmlRpcClient::execute: method %s (_connectionState %d).", method, _connectionState); 00122 00123 // This is not a thread-safe operation, if you want to do multithreading, use separate 00124 // clients for each thread. If you want to protect yourself from multiple threads 00125 // accessing the same client, replace this code with a real mutex. 00126 if (_executing) 00127 return false; 00128 00129 _executing = true; 00130 ClearFlagOnExit cf(_executing); 00131 00132 _sendAttempts = 0; 00133 _isFault = false; 00134 00135 if ( ! setupConnection()) 00136 return false; 00137 00138 if ( ! generateRequest(method, params)) 00139 return false; 00140 00141 return true; 00142 } 00143 00144 bool 00145 XmlRpcClient::executeCheckDone(XmlRpcValue& result) 00146 { 00147 result.clear(); 00148 // Are we done yet? 00149 if (_connectionState != IDLE) 00150 return false; 00151 if (! parseResponse(result)) 00152 { 00153 // Hopefully the caller can determine that parsing failed. 00154 } 00155 //XmlRpcUtil::log(1, "XmlRpcClient::execute: method %s completed.", method); 00156 _response = ""; 00157 return true; 00158 } 00159 00160 // XmlRpcSource interface implementation 00161 // Handle server responses. Called by the event dispatcher during execute. 00162 unsigned 00163 XmlRpcClient::handleEvent(unsigned eventType) 00164 { 00165 if (eventType == XmlRpcDispatch::Exception) 00166 { 00167 if (_connectionState == WRITE_REQUEST && _bytesWritten == 0) 00168 XmlRpcUtil::error("Error in XmlRpcClient::handleEvent: could not connect to server (%s).", 00169 XmlRpcSocket::getErrorMsg().c_str()); 00170 else 00171 XmlRpcUtil::error("Error in XmlRpcClient::handleEvent (state %d): %s.", 00172 _connectionState, XmlRpcSocket::getErrorMsg().c_str()); 00173 return 0; 00174 } 00175 00176 if (_connectionState == WRITE_REQUEST) 00177 if ( ! writeRequest()) return 0; 00178 00179 if (_connectionState == READ_HEADER) 00180 if ( ! readHeader()) return 0; 00181 00182 if (_connectionState == READ_RESPONSE) 00183 if ( ! readResponse()) return 0; 00184 00185 // This should probably always ask for Exception events too 00186 return (_connectionState == WRITE_REQUEST) 00187 ? XmlRpcDispatch::WritableEvent : XmlRpcDispatch::ReadableEvent; 00188 } 00189 00190 00191 // Create the socket connection to the server if necessary 00192 bool 00193 XmlRpcClient::setupConnection() 00194 { 00195 // If an error occurred last time through, or if the server closed the connection, close our end 00196 if ((_connectionState != NO_CONNECTION && _connectionState != IDLE) || _eof) 00197 close(); 00198 00199 _eof = false; 00200 if (_connectionState == NO_CONNECTION) 00201 if (! doConnect()) 00202 return false; 00203 00204 // Prepare to write the request 00205 _connectionState = WRITE_REQUEST; 00206 _bytesWritten = 0; 00207 00208 // Notify the dispatcher to listen on this source (calls handleEvent when the socket is writable) 00209 _disp.removeSource(this); // Make sure nothing is left over 00210 _disp.addSource(this, XmlRpcDispatch::WritableEvent | XmlRpcDispatch::Exception); 00211 00212 return true; 00213 } 00214 00215 00216 // Connect to the xmlrpc server 00217 bool 00218 XmlRpcClient::doConnect() 00219 { 00220 int fd = XmlRpcSocket::socket(); 00221 if (fd < 0) 00222 { 00223 XmlRpcUtil::error("Error in XmlRpcClient::doConnect: Could not create socket (%s).", XmlRpcSocket::getErrorMsg().c_str()); 00224 return false; 00225 } 00226 00227 XmlRpcUtil::log(3, "XmlRpcClient::doConnect: fd %d.", fd); 00228 this->setfd(fd); 00229 00230 // Don't block on connect/reads/writes 00231 if ( ! XmlRpcSocket::setNonBlocking(fd)) 00232 { 00233 this->close(); 00234 XmlRpcUtil::error("Error in XmlRpcClient::doConnect: Could not set socket to non-blocking IO mode (%s).", XmlRpcSocket::getErrorMsg().c_str()); 00235 return false; 00236 } 00237 00238 if ( ! XmlRpcSocket::connect(fd, _host, _port)) 00239 { 00240 this->close(); 00241 XmlRpcUtil::error("Error in XmlRpcClient::doConnect: Could not connect to server (%s).", XmlRpcSocket::getErrorMsg().c_str()); 00242 return false; 00243 } 00244 00245 return true; 00246 } 00247 00248 // Encode the request to call the specified method with the specified parameters into xml 00249 bool 00250 XmlRpcClient::generateRequest(const char* methodName, XmlRpcValue const& params) 00251 { 00252 std::string body = REQUEST_BEGIN; 00253 body += methodName; 00254 body += REQUEST_END_METHODNAME; 00255 00256 // If params is an array, each element is a separate parameter 00257 if (params.valid()) { 00258 body += PARAMS_TAG; 00259 if (params.getType() == XmlRpcValue::TypeArray) 00260 { 00261 for (int i=0; i<params.size(); ++i) { 00262 body += PARAM_TAG; 00263 body += params[i].toXml(); 00264 body += PARAM_ETAG; 00265 } 00266 } 00267 else 00268 { 00269 body += PARAM_TAG; 00270 body += params.toXml(); 00271 body += PARAM_ETAG; 00272 } 00273 00274 body += PARAMS_ETAG; 00275 } 00276 body += REQUEST_END; 00277 00278 std::string header = generateHeader(body); 00279 XmlRpcUtil::log(4, "XmlRpcClient::generateRequest: header is %d bytes, content-length is %d.", 00280 header.length(), body.length()); 00281 00282 _request = header + body; 00283 return true; 00284 } 00285 00286 // Prepend http headers 00287 std::string 00288 XmlRpcClient::generateHeader(std::string const& body) 00289 { 00290 std::string header = 00291 "POST " + _uri + " HTTP/1.1\r\n" 00292 "User-Agent: "; 00293 header += XMLRPC_VERSION; 00294 header += "\r\nHost: "; 00295 header += _host; 00296 00297 char buff[40]; 00298 #ifdef _MSC_VER 00299 sprintf_s(buff,40,":%d\r\n", _port); 00300 #else 00301 sprintf(buff,":%d\r\n", _port); 00302 #endif 00303 00304 header += buff; 00305 header += "Content-Type: text/xml\r\nContent-length: "; 00306 00307 #ifdef _MSC_VER 00308 sprintf_s(buff,40,"%d\r\n\r\n", (int)body.size()); 00309 #else 00310 sprintf(buff,"%d\r\n\r\n", (int)body.size()); 00311 #endif 00312 00313 return header + buff; 00314 } 00315 00316 bool 00317 XmlRpcClient::writeRequest() 00318 { 00319 if (_bytesWritten == 0) 00320 XmlRpcUtil::log(5, "XmlRpcClient::writeRequest (attempt %d):\n%s\n", _sendAttempts+1, _request.c_str()); 00321 00322 // Try to write the request 00323 if ( ! XmlRpcSocket::nbWrite(this->getfd(), _request, &_bytesWritten)) { 00324 XmlRpcUtil::error("Error in XmlRpcClient::writeRequest: write error (%s).",XmlRpcSocket::getErrorMsg().c_str()); 00325 return false; 00326 } 00327 00328 XmlRpcUtil::log(3, "XmlRpcClient::writeRequest: wrote %d of %d bytes.", _bytesWritten, _request.length()); 00329 00330 // Wait for the result 00331 if (_bytesWritten == int(_request.length())) { 00332 _header = ""; 00333 _response = ""; 00334 _connectionState = READ_HEADER; 00335 } 00336 return true; 00337 } 00338 00339 00340 // Read the header from the response 00341 bool 00342 XmlRpcClient::readHeader() 00343 { 00344 // Read available data 00345 if ( ! XmlRpcSocket::nbRead(this->getfd(), _header, &_eof) || 00346 (_eof && _header.length() == 0)) { 00347 00348 // If we haven't read any data yet and this is a keep-alive connection, the server may 00349 // have timed out, so we try one more time. 00350 if (getKeepOpen() && _header.length() == 0 && _sendAttempts++ == 0) { 00351 XmlRpcUtil::log(4, "XmlRpcClient::readHeader: re-trying connection"); 00352 XmlRpcSource::close(); 00353 _connectionState = NO_CONNECTION; 00354 _eof = false; 00355 return setupConnection(); 00356 } 00357 00358 XmlRpcUtil::error("Error in XmlRpcClient::readHeader: error while reading header (%s) on fd %d.", 00359 XmlRpcSocket::getErrorMsg().c_str(), getfd()); 00360 return false; 00361 } 00362 00363 XmlRpcUtil::log(4, "XmlRpcClient::readHeader: client has read %d bytes", _header.length()); 00364 00365 char *hp = (char*)_header.c_str(); // Start of header 00366 char *ep = hp + _header.length(); // End of string 00367 char *bp = 0; // Start of body 00368 char *lp = 0; // Start of content-length value 00369 00370 for (char *cp = hp; (bp == 0) && (cp < ep); ++cp) { 00371 if ((ep - cp > 16) && (strncasecmp(cp, "Content-length: ", 16) == 0)) 00372 lp = cp + 16; 00373 else if ((ep - cp > 4) && (strncmp(cp, "\r\n\r\n", 4) == 0)) 00374 bp = cp + 4; 00375 else if ((ep - cp > 2) && (strncmp(cp, "\n\n", 2) == 0)) 00376 bp = cp + 2; 00377 } 00378 00379 // If we haven't gotten the entire header yet, return (keep reading) 00380 if (bp == 0) { 00381 if (_eof) // EOF in the middle of a response is an error 00382 { 00383 XmlRpcUtil::error("Error in XmlRpcClient::readHeader: EOF while reading header"); 00384 return false; // Close the connection 00385 } 00386 00387 return true; // Keep reading 00388 } 00389 00390 // Decode content length 00391 if (lp == 0) { 00392 XmlRpcUtil::error("Error XmlRpcClient::readHeader: No Content-length specified"); 00393 return false; // We could try to figure it out by parsing as we read, but for now... 00394 } 00395 00396 _contentLength = atoi(lp); 00397 if (_contentLength <= 0) { 00398 XmlRpcUtil::error("Error in XmlRpcClient::readHeader: Invalid Content-length specified (%d).", _contentLength); 00399 return false; 00400 } 00401 00402 XmlRpcUtil::log(4, "client read content length: %d", _contentLength); 00403 00404 // Otherwise copy non-header data to response buffer and set state to read response. 00405 _response = bp; 00406 _header = ""; // should parse out any interesting bits from the header (connection, etc)... 00407 _connectionState = READ_RESPONSE; 00408 return true; // Continue monitoring this source 00409 } 00410 00411 00412 bool 00413 XmlRpcClient::readResponse() 00414 { 00415 // If we dont have the entire response yet, read available data 00416 if (int(_response.length()) < _contentLength) { 00417 if ( ! XmlRpcSocket::nbRead(this->getfd(), _response, &_eof)) { 00418 XmlRpcUtil::error("Error in XmlRpcClient::readResponse: read error (%s).",XmlRpcSocket::getErrorMsg().c_str()); 00419 return false; 00420 } 00421 00422 // If we haven't gotten the entire _response yet, return (keep reading) 00423 if (int(_response.length()) < _contentLength) { 00424 if (_eof) { 00425 XmlRpcUtil::error("Error in XmlRpcClient::readResponse: EOF while reading response"); 00426 return false; 00427 } 00428 return true; 00429 } 00430 } 00431 00432 // Otherwise, parse and return the result 00433 XmlRpcUtil::log(3, "XmlRpcClient::readResponse (read %d bytes)", _response.length()); 00434 XmlRpcUtil::log(5, "response:\n%s", _response.c_str()); 00435 00436 _connectionState = IDLE; 00437 00438 return false; // Stop monitoring this source (causes return from work) 00439 } 00440 00441 00442 // Convert the response xml into a result value 00443 bool 00444 XmlRpcClient::parseResponse(XmlRpcValue& result) 00445 { 00446 // Parse response xml into result 00447 int offset = 0; 00448 if ( ! XmlRpcUtil::findTag(METHODRESPONSE_TAG,_response,&offset)) { 00449 XmlRpcUtil::error("Error in XmlRpcClient::parseResponse: Invalid response - no methodResponse. Response:\n%s", _response.c_str()); 00450 return false; 00451 } 00452 00453 // Expect either <params><param>... or <fault>... 00454 if ((XmlRpcUtil::nextTagIs(PARAMS_TAG,_response,&offset) && 00455 XmlRpcUtil::nextTagIs(PARAM_TAG,_response,&offset)) || 00456 (XmlRpcUtil::nextTagIs(FAULT_TAG,_response,&offset) && (_isFault = true))) 00457 { 00458 if ( ! result.fromXml(_response, &offset)) { 00459 XmlRpcUtil::error("Error in XmlRpcClient::parseResponse: Invalid response value. Response:\n%s", _response.c_str()); 00460 _response = ""; 00461 return false; 00462 } 00463 } else { 00464 XmlRpcUtil::error("Error in XmlRpcClient::parseResponse: Invalid response - no param or fault tag. Response:\n%s", _response.c_str()); 00465 _response = ""; 00466 return false; 00467 } 00468 00469 _response = ""; 00470 return result.valid(); 00471 } 00472