00001
00032 #include "llviewerprecompiledheaders.h"
00033
00034 #include "llxmlrpctransaction.h"
00035
00036 #include "llcurl.h"
00037 #include "llviewercontrol.h"
00038
00039
00040 #include <xmlrpc-epi/xmlrpc.h>
00041
00042 #include "llappviewer.h"
00043
00044 LLXMLRPCValue LLXMLRPCValue::operator[](const char* id) const
00045 {
00046 return LLXMLRPCValue(XMLRPC_VectorGetValueWithID(mV, id));
00047 }
00048
00049 std::string LLXMLRPCValue::asString() const
00050 {
00051 const char* s = XMLRPC_GetValueString(mV);
00052 return s ? s : "";
00053 }
00054
00055 int LLXMLRPCValue::asInt() const { return XMLRPC_GetValueInt(mV); }
00056 bool LLXMLRPCValue::asBool() const { return XMLRPC_GetValueBoolean(mV) != 0; }
00057 double LLXMLRPCValue::asDouble() const { return XMLRPC_GetValueDouble(mV); }
00058
00059 LLXMLRPCValue LLXMLRPCValue::rewind()
00060 {
00061 return LLXMLRPCValue(XMLRPC_VectorRewind(mV));
00062 }
00063
00064 LLXMLRPCValue LLXMLRPCValue::next()
00065 {
00066 return LLXMLRPCValue(XMLRPC_VectorNext(mV));
00067 }
00068
00069 bool LLXMLRPCValue::isValid() const
00070 {
00071 return mV != NULL;
00072 }
00073
00074 LLXMLRPCValue LLXMLRPCValue::createArray()
00075 {
00076 return LLXMLRPCValue(XMLRPC_CreateVector(NULL, xmlrpc_vector_array));
00077 }
00078
00079 LLXMLRPCValue LLXMLRPCValue::createStruct()
00080 {
00081 return LLXMLRPCValue(XMLRPC_CreateVector(NULL, xmlrpc_vector_struct));
00082 }
00083
00084
00085 void LLXMLRPCValue::append(LLXMLRPCValue& v)
00086 {
00087 XMLRPC_AddValueToVector(mV, v.mV);
00088 }
00089
00090 void LLXMLRPCValue::appendString(const std::string& v)
00091 {
00092 XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueString(NULL, v.c_str(), 0));
00093 }
00094
00095 void LLXMLRPCValue::appendInt(int v)
00096 {
00097 XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueInt(NULL, v));
00098 }
00099
00100 void LLXMLRPCValue::appendBool(bool v)
00101 {
00102 XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueBoolean(NULL, v));
00103 }
00104
00105 void LLXMLRPCValue::appendDouble(double v)
00106 {
00107 XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueDouble(NULL, v));
00108 }
00109
00110
00111 void LLXMLRPCValue::append(const char* id, LLXMLRPCValue& v)
00112 {
00113 XMLRPC_SetValueID(v.mV, id, 0);
00114 XMLRPC_AddValueToVector(mV, v.mV);
00115 }
00116
00117 void LLXMLRPCValue::appendString(const char* id, const std::string& v)
00118 {
00119 XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueString(id, v.c_str(), 0));
00120 }
00121
00122 void LLXMLRPCValue::appendInt(const char* id, int v)
00123 {
00124 XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueInt(id, v));
00125 }
00126
00127 void LLXMLRPCValue::appendBool(const char* id, bool v)
00128 {
00129 XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueBoolean(id, v));
00130 }
00131
00132 void LLXMLRPCValue::appendDouble(const char* id, double v)
00133 {
00134 XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueDouble(id, v));
00135 }
00136
00137 void LLXMLRPCValue::free()
00138 {
00139 XMLRPC_CleanupValue(mV);
00140 mV = NULL;
00141 }
00142
00143 XMLRPC_VALUE LLXMLRPCValue::getValue() const
00144 {
00145 return mV;
00146 }
00147
00148
00149 class LLXMLRPCTransaction::Impl
00150 {
00151 public:
00152 typedef LLXMLRPCTransaction::Status Status;
00153
00154 LLCurlEasyRequest* mCurlRequest;
00155
00156 Status mStatus;
00157 CURLcode mCurlCode;
00158 std::string mStatusMessage;
00159 std::string mStatusURI;
00160 LLCurl::TransferInfo mTransferInfo;
00161
00162 std::string mURI;
00163 char* mRequestText;
00164 int mRequestTextSize;
00165
00166 std::string mProxyAddress;
00167
00168 std::string mResponseText;
00169 XMLRPC_REQUEST mResponse;
00170
00171 Impl(const std::string& uri, XMLRPC_REQUEST request, bool useGzip);
00172 Impl(const std::string& uri,
00173 const std::string& method, LLXMLRPCValue params, bool useGzip);
00174 ~Impl();
00175
00176 bool process();
00177
00178 void setStatus(Status code,
00179 const std::string& message = "", const std::string& uri = "");
00180 void setCurlStatus(CURLcode);
00181
00182 private:
00183 void init(XMLRPC_REQUEST request, bool useGzip);
00184
00185 static size_t curlDownloadCallback(
00186 char* data, size_t size, size_t nmemb, void* user_data);
00187 };
00188
00189 LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
00190 XMLRPC_REQUEST request, bool useGzip)
00191 : mCurlRequest(0),
00192 mStatus(LLXMLRPCTransaction::StatusNotStarted),
00193 mURI(uri),
00194 mRequestText(0),
00195 mResponse(0)
00196 {
00197 init(request, useGzip);
00198 }
00199
00200
00201 LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
00202 const std::string& method, LLXMLRPCValue params, bool useGzip)
00203 : mCurlRequest(0),
00204 mStatus(LLXMLRPCTransaction::StatusNotStarted),
00205 mURI(uri),
00206 mRequestText(0),
00207 mResponse(0)
00208 {
00209 XMLRPC_REQUEST request = XMLRPC_RequestNew();
00210 XMLRPC_RequestSetMethodName(request, method.c_str());
00211 XMLRPC_RequestSetRequestType(request, xmlrpc_request_call);
00212 XMLRPC_RequestSetData(request, params.getValue());
00213
00214 init(request, useGzip);
00215 }
00216
00217
00218
00219
00220 void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip)
00221 {
00222 if (!mCurlRequest)
00223 {
00224 mCurlRequest = new LLCurlEasyRequest();
00225 }
00226
00227 if (gSavedSettings.getBOOL("BrowserProxyEnabled"))
00228 {
00229 mProxyAddress = gSavedSettings.getString("BrowserProxyAddress");
00230 S32 port = gSavedSettings.getS32 ( "BrowserProxyPort" );
00231
00232
00233 mCurlRequest->setoptString(CURLOPT_PROXY, mProxyAddress);
00234 mCurlRequest->setopt(CURLOPT_PROXYPORT, port);
00235 mCurlRequest->setopt(CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
00236 }
00237
00238
00239 mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1);
00240 mCurlRequest->setWriteCallback(&curlDownloadCallback, (void*)this);
00241 BOOL vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert");
00242 mCurlRequest->setopt(CURLOPT_SSL_VERIFYPEER, vefifySSLCert);
00243 mCurlRequest->setopt(CURLOPT_SSL_VERIFYHOST, vefifySSLCert ? 2 : 0);
00244
00245 mCurlRequest->setopt(CURLOPT_CONNECTTIMEOUT, 40L);
00246
00247
00248
00249 mCurlRequest->setopt(CURLOPT_DNS_CACHE_TIMEOUT, -1);
00250
00251 mCurlRequest->slist_append("Content-Type: text/xml");
00252
00253 if (useGzip)
00254 {
00255 mCurlRequest->setoptString(CURLOPT_ENCODING, "");
00256 }
00257
00258 mRequestText = XMLRPC_REQUEST_ToXML(request, &mRequestTextSize);
00259 if (mRequestText)
00260 {
00261 mCurlRequest->setoptString(CURLOPT_POSTFIELDS, mRequestText);
00262 mCurlRequest->setopt(CURLOPT_POSTFIELDSIZE, mRequestTextSize);
00263 }
00264 else
00265 {
00266 setStatus(StatusOtherError);
00267 }
00268
00269 mCurlRequest->sendRequest(mURI);
00270 }
00271
00272
00273 LLXMLRPCTransaction::Impl::~Impl()
00274 {
00275 if (mResponse)
00276 {
00277 XMLRPC_RequestFree(mResponse, 1);
00278 }
00279
00280 if (mRequestText)
00281 {
00282 XMLRPC_Free(mRequestText);
00283 }
00284
00285 delete mCurlRequest;
00286 }
00287
00288 bool LLXMLRPCTransaction::Impl::process()
00289 {
00290 switch(mStatus)
00291 {
00292 case LLXMLRPCTransaction::StatusComplete:
00293 case LLXMLRPCTransaction::StatusCURLError:
00294 case LLXMLRPCTransaction::StatusXMLRPCError:
00295 case LLXMLRPCTransaction::StatusOtherError:
00296 {
00297 return true;
00298 }
00299
00300 case LLXMLRPCTransaction::StatusNotStarted:
00301 {
00302 setStatus(LLXMLRPCTransaction::StatusStarted);
00303 break;
00304 }
00305
00306 default:
00307 {
00308
00309 }
00310 }
00311
00312 const F32 MAX_PROCESSING_TIME = 0.05f;
00313 LLTimer timer;
00314
00315 while (mCurlRequest->perform() > 0)
00316 {
00317 if (timer.getElapsedTimeF32() >= MAX_PROCESSING_TIME)
00318 {
00319 return false;
00320 }
00321 }
00322
00323 while(1)
00324 {
00325 CURLcode result;
00326 bool newmsg = mCurlRequest->getResult(&result, &mTransferInfo);
00327 if (newmsg)
00328 {
00329 if (result != CURLE_OK)
00330 {
00331 setCurlStatus(result);
00332 llwarns << "LLXMLRPCTransaction CURL error "
00333 << mCurlCode << ": " << mCurlRequest->getErrorString() << llendl;
00334 llwarns << "LLXMLRPCTransaction request URI: "
00335 << mURI << llendl;
00336
00337 return true;
00338 }
00339
00340 setStatus(LLXMLRPCTransaction::StatusComplete);
00341
00342 mResponse = XMLRPC_REQUEST_FromXML(
00343 mResponseText.data(), mResponseText.size(), NULL);
00344
00345 bool hasError = false;
00346 bool hasFault = false;
00347 int faultCode = 0;
00348 std::string faultString;
00349
00350 LLXMLRPCValue error(XMLRPC_RequestGetError(mResponse));
00351 if (error.isValid())
00352 {
00353 hasError = true;
00354 faultCode = error["faultCode"].asInt();
00355 faultString = error["faultString"].asString();
00356 }
00357 else if (XMLRPC_ResponseIsFault(mResponse))
00358 {
00359 hasFault = true;
00360 faultCode = XMLRPC_GetResponseFaultCode(mResponse);
00361 faultString = XMLRPC_GetResponseFaultString(mResponse);
00362 }
00363
00364 if (hasError || hasFault)
00365 {
00366 setStatus(LLXMLRPCTransaction::StatusXMLRPCError);
00367
00368 llwarns << "LLXMLRPCTransaction XMLRPC "
00369 << (hasError ? "error " : "fault ")
00370 << faultCode << ": "
00371 << faultString << llendl;
00372 llwarns << "LLXMLRPCTransaction request URI: "
00373 << mURI << llendl;
00374 }
00375
00376 return true;
00377 }
00378 else
00379 {
00380 break;
00381 }
00382 }
00383
00384 return false;
00385 }
00386
00387 void LLXMLRPCTransaction::Impl::setStatus(Status status,
00388 const std::string& message, const std::string& uri)
00389 {
00390 mStatus = status;
00391 mStatusMessage = message;
00392 mStatusURI = uri;
00393
00394 if (mStatusMessage.empty())
00395 {
00396 switch (mStatus)
00397 {
00398 case StatusNotStarted:
00399 mStatusMessage = "(not started)";
00400 break;
00401
00402 case StatusStarted:
00403 mStatusMessage = "(waiting for server response)";
00404 break;
00405
00406 case StatusDownloading:
00407 mStatusMessage = "(reading server response)";
00408 break;
00409
00410 case StatusComplete:
00411 mStatusMessage = "(done)";
00412 break;
00413
00414 default:
00415
00416
00417 mStatusMessage =
00418 "Despite our best efforts, something unexpected has gone wrong. \n"
00419 " \n"
00420 "Please check www.secondlife.com/status \n"
00421 "to see if there is a known problem with the service.";
00422
00423 mStatusURI = "http://secondlife.com/status/";
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442 }
00443 }
00444 }
00445
00446 void LLXMLRPCTransaction::Impl::setCurlStatus(CURLcode code)
00447 {
00448 std::string message;
00449 std::string uri = "http://secondlife.com/community/support.php";
00450
00451 switch (code)
00452 {
00453 case CURLE_COULDNT_RESOLVE_HOST:
00454 message =
00455 "DNS could not resolve the host name.\n"
00456 "Please verify that you can connect to the www.secondlife.com\n"
00457 "web site. If you can, but continue to receive this error,\n"
00458 "please go to the support section and report this problem.";
00459 break;
00460
00461 case CURLE_SSL_PEER_CERTIFICATE:
00462 message =
00463 "The login server couldn't verify itself via SSL.\n"
00464 "If you continue to receive this error, please go\n"
00465 "to the Support section of the SecondLife.com web site\n"
00466 "and report the problem.";
00467 break;
00468
00469 case CURLE_SSL_CACERT:
00470 case CURLE_SSL_CONNECT_ERROR:
00471 message =
00472 "Often this means that your computer\'s clock is set incorrectly.\n"
00473 "Please go to Control Panels and make sure the time and date\n"
00474 "are set correctly.\n"
00475 "\n"
00476 "If you continue to receive this error, please go\n"
00477 "to the Support section of the SecondLife.com web site\n"
00478 "and report the problem.";
00479 break;
00480
00481 default:
00482 break;
00483 }
00484
00485 mCurlCode = code;
00486 setStatus(StatusCURLError, message, uri);
00487 }
00488
00489 size_t LLXMLRPCTransaction::Impl::curlDownloadCallback(
00490 char* data, size_t size, size_t nmemb, void* user_data)
00491 {
00492 Impl& impl(*(Impl*)user_data);
00493
00494 size_t n = size * nmemb;
00495
00496 impl.mResponseText.append(data, n);
00497
00498 if (impl.mStatus == LLXMLRPCTransaction::StatusStarted)
00499 {
00500 impl.setStatus(LLXMLRPCTransaction::StatusDownloading);
00501 }
00502
00503 return n;
00504 }
00505
00506
00507 LLXMLRPCTransaction::LLXMLRPCTransaction(
00508 const std::string& uri, XMLRPC_REQUEST request, bool useGzip)
00509 : impl(* new Impl(uri, request, useGzip))
00510 { }
00511
00512
00513 LLXMLRPCTransaction::LLXMLRPCTransaction(
00514 const std::string& uri,
00515 const std::string& method, LLXMLRPCValue params, bool useGzip)
00516 : impl(* new Impl(uri, method, params, useGzip))
00517 { }
00518
00519 LLXMLRPCTransaction::~LLXMLRPCTransaction()
00520 {
00521 delete &impl;
00522 }
00523
00524 bool LLXMLRPCTransaction::process()
00525 {
00526 return impl.process();
00527 }
00528
00529 LLXMLRPCTransaction::Status LLXMLRPCTransaction::status(int* curlCode)
00530 {
00531 if (curlCode)
00532 {
00533 *curlCode =
00534 (impl.mStatus == StatusCURLError)
00535 ? impl.mCurlCode
00536 : CURLE_OK;
00537 }
00538
00539 return impl.mStatus;
00540 }
00541
00542 std::string LLXMLRPCTransaction::statusMessage()
00543 {
00544 return impl.mStatusMessage;
00545 }
00546
00547 std::string LLXMLRPCTransaction::statusURI()
00548 {
00549 return impl.mStatusURI;
00550 }
00551
00552 XMLRPC_REQUEST LLXMLRPCTransaction::response()
00553 {
00554 return impl.mResponse;
00555 }
00556
00557 LLXMLRPCValue LLXMLRPCTransaction::responseValue()
00558 {
00559 return LLXMLRPCValue(XMLRPC_RequestGetData(impl.mResponse));
00560 }
00561
00562
00563 F64 LLXMLRPCTransaction::transferRate()
00564 {
00565 if (impl.mStatus != StatusComplete)
00566 {
00567 return 0.0L;
00568 }
00569
00570 double rate_bits_per_sec = impl.mTransferInfo.mSpeedDownload * 8.0;
00571
00572 LL_INFOS("AppInit") << "Buffer size: " << impl.mResponseText.size() << " B" << LL_ENDL;
00573 LL_DEBUGS("AppInit") << "Transfer size: " << impl.mTransferInfo.mSizeDownload << " B" << LL_ENDL;
00574 LL_DEBUGS("AppInit") << "Transfer time: " << impl.mTransferInfo.mTotalTime << " s" << LL_ENDL;
00575 LL_INFOS("AppInit") << "Transfer rate: " << rate_bits_per_sec / 1000.0 << " Kb/s" << LL_ENDL;
00576
00577 return rate_bits_per_sec;
00578 }