llxmlrpctransaction.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #include "llxmlrpctransaction.h"
00035 
00036 #include "llcurl.h"
00037 #include "llviewercontrol.h"
00038 
00039 // Have to include these last to avoid queue redefinition!
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                 // tell curl about the settings
00233                 mCurlRequest->setoptString(CURLOPT_PROXY, mProxyAddress);
00234                 mCurlRequest->setopt(CURLOPT_PROXYPORT, port);
00235                 mCurlRequest->setopt(CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
00236         }
00237 
00238 //      mCurlRequest->setopt(CURLOPT_VERBOSE, 1); // usefull for debugging
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         // Be a little impatient about establishing connections.
00245         mCurlRequest->setopt(CURLOPT_CONNECTTIMEOUT, 40L);
00246 
00247         /* Setting the DNS cache timeout to -1 disables it completely.
00248            This might help with bug #503 */
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                         // continue onward
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; // done
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                                 // Usually this means that there's a problem with the login server,
00416                                 // not with the client.  Direct user to status page. JC
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                                 mStatusMessage =
00426                                         "Despite our best efforts, something unexpected has gone wrong.\n"
00427                                         "Please go to the Support section of the SecondLife.com web site\n"
00428                                         "and report the problem.  If possible, include your SecondLife.log\n"
00429                                         "file from:\n"
00430 #if LL_WINDOWS
00431                                         "C:\\Documents and Settings\<name>\\Application Data\\SecondLife\\logs\n"
00432 #elif LL_DARWIN
00433                                         "~/Library/Application Support/SecondLife/logs\n"
00434 #elif LL_LINUX
00435                                         "~/.secondlife/logs\n"
00436 #else
00437 #error "Need platform here."
00438 #endif
00439                                         "Thank you.";
00440                                 mStatusURI = "http://secondlife.com/community/support.php";
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 }

Generated on Fri May 16 08:34:27 2008 for SecondLife by  doxygen 1.5.5