diff options
Diffstat (limited to 'indra/newview')
-rw-r--r-- | indra/newview/llappviewer.cpp | 17 | ||||
-rw-r--r-- | indra/newview/llinventorymodel.cpp | 301 | ||||
-rw-r--r-- | indra/newview/llinventorymodel.h | 28 | ||||
-rw-r--r-- | indra/newview/llviewerinventory.cpp | 48 | ||||
-rw-r--r-- | indra/newview/llviewerinventory.h | 1 | ||||
-rw-r--r-- | indra/newview/llviewerregion.cpp | 1 | ||||
-rw-r--r-- | indra/newview/llxmlrpctransaction.cpp | 152 |
7 files changed, 435 insertions, 113 deletions
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 666fcd1301..61699d21c8 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -51,6 +51,7 @@ #include "llstartup.h" #include "llfocusmgr.h" #include "llviewerjoystick.h" +#include "llares.h" #include "llcurl.h" #include "llfloatersnapshot.h" #include "llviewerwindow.h" @@ -1338,7 +1339,7 @@ bool LLAppViewer::mainLoop() // Create IO Pump to use for HTTP Requests. gServicePump = new LLPumpIO(gAPRPoolp); LLHTTPClient::setPump(*gServicePump); - LLHTTPClient::setCABundle(gDirUtilp->getCAFile()); + LLCurl::setCAFile(gDirUtilp->getCAFile()); // initialize voice stuff here gLocalSpeakerMgr = new LLLocalSpeakerMgr(); @@ -1398,10 +1399,14 @@ bool LLAppViewer::mainLoop() { LLFastTimer t3(LLFastTimer::FTM_IDLE); idle(); - LLCurl::process(); - // this pump is necessary to make the login screen show up - gServicePump->pump(); - gServicePump->callback(); + + { + LLFastTimer t4(LLFastTimer::FTM_PUMP); + gAres->process(); + // this pump is necessary to make the login screen show up + gServicePump->pump(); + gServicePump->callback(); + } } if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED)) @@ -1811,7 +1816,7 @@ bool LLAppViewer::cleanup() end_messaging_system(); // *NOTE:Mani - The following call is not thread safe. - LLCurl::cleanup(); + LLCurl::cleanupClass(); // If we're exiting to launch an URL, do that here so the screen // is at the right resolution before we launch IE. diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 7b27a830c4..17a8b84472 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -47,6 +47,7 @@ #include "llviewerinventory.h" #include "llviewermessage.h" #include "llviewerwindow.h" +#include "llviewerregion.h" #include "llappviewer.h" #include "lldbstrings.h" #include "llviewerstats.h" @@ -54,6 +55,8 @@ #include "llnotify.h" #include "llcallbacklist.h" #include "llpreview.h" +#include "llviewercontrol.h" +#include "llsdutil.h" #include <deque> //#define DIFF_INVENTORY_FILES @@ -69,6 +72,8 @@ F32 LLInventoryModel::sMinTimeBetweenFetches = 0.3f; F32 LLInventoryModel::sMaxTimeBetweenFetches = 10.f; BOOL LLInventoryModel::sTimelyFetchPending = FALSE; LLFrameTimer LLInventoryModel::sFetchTimer; +LLInventoryModel::cat_map_t LLInventoryModel::sBulkFetchMap; +S16 LLInventoryModel::sBulkFetchCount = 0; // RN: for some reason, using std::queue in the header file confuses the compiler which things it's an xmlrpc_queue static std::deque<LLUUID> sFetchQueue; @@ -1002,6 +1007,286 @@ void LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id) } } +//Initialize statics. +LLAlertDialog* LLInventoryModel::fetchDescendentsResponder::sRetryDialog=NULL; +LLSD LLInventoryModel::fetchDescendentsResponder::sRetrySD; + +bool LLInventoryModel::isBulkFetchProcessingComplete() +{ + return ( (sFetchQueue.empty() + && sBulkFetchMap.empty() + && sBulkFetchCount==0) ? TRUE : FALSE ) ; +} + +//If we get back a normal response, handle it here +void LLInventoryModel::fetchDescendentsResponder::result(const LLSD& content) +{ + if (content.has("folders")) + { + for(LLSD::array_const_iterator folder_it = content["folders"].beginArray(); + folder_it != content["folders"].endArray(); + ++folder_it) + { + LLSD folder_sd = *folder_it; + + + LLUUID agent_id = folder_sd["agent-id"]; + + if(agent_id != gAgent.getID()) //This should never happen. + { + llwarns << "Got a UpdateInventoryItem for the wrong agent." + << llendl; + break; + } + LLUUID parent_id = folder_sd["folder-id"]; + LLUUID owner_id = folder_sd["owner-id"]; + S32 version = (S32)folder_sd["version"].asInteger(); + S32 descendents = (S32)folder_sd["descendents"].asInteger(); + LLPointer<LLViewerInventoryCategory> tcategory = new LLViewerInventoryCategory(owner_id); + for(LLSD::array_const_iterator category_it = folder_sd["categories"].beginArray(); + category_it != folder_sd["categories"].endArray(); + ++category_it) + { + LLSD category = *category_it; + tcategory->fromLLSD(category); + + if (sFullFetchStarted) + { + sFetchQueue.push_back(tcategory->getUUID()); + } + else if ( !gInventory.isCategoryComplete(tcategory->getUUID()) ) + { + gInventory.updateCategory(tcategory); + } + + } + LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem; + for(LLSD::array_const_iterator item_it = folder_sd["items"].beginArray(); + item_it != folder_sd["items"].endArray(); + ++item_it) + { + LLSD item = *item_it; + titem->unpackMessage(item); + + gInventory.updateItem(titem); + } + + // set version and descendentcount according to message. + LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id); + if(cat) + { + cat->setVersion(version); + cat->setDescendentCount(descendents); + } + + } + } + + if (content.has("bad-folders")) + { + for(LLSD::array_const_iterator folder_it = content["bad-folders"].beginArray(); + folder_it != content["bad-folders"].endArray(); + ++folder_it) + { + LLSD folder_sd = *folder_it; + + //These folders failed on the dataserver. We probably don't want to retry them. + llinfos << "Folder " << folder_sd["folder-id"].asString() + << "Error: " << folder_sd["error"].asString() << llendl; + } + } + + LLInventoryModel::incrBulkFetch(-1); + + if (isBulkFetchProcessingComplete()) + { + llinfos << "Inventory fetch completed" << llendl; + if (sFullFetchStarted) + { + sAllFoldersFetched = TRUE; + } + stopBackgroundFetch(); + } + + gInventory.notifyObservers(); +} + +//If we get back an error (not found, etc...), handle it here +void LLInventoryModel::fetchDescendentsResponder::error(U32 status, const std::string& reason) +{ + llinfos << "fetchDescendentsResponder::error " + << status << ": " << reason << llendl; + + LLInventoryModel::incrBulkFetch(-1); + + if (status==499) //timed out. Let's be awesome! + { + for(LLSD::array_const_iterator folder_it = mRequestSD["folders"].beginArray(); + folder_it != mRequestSD["folders"].endArray(); + ++folder_it) + { + LLSD folder_sd = *folder_it; + sRetrySD["folders"].append(folder_sd); + } + sMinTimeBetweenFetches = 10.0f; //Add 10 seconds for every time out in this sequence. + + if (!sRetryDialog) //The dialog isn't up. Prompt the resident. + { + sRetryDialog = gViewerWindow->alertXml("RetryFetchInventoryDescendents", onClickRetry, this); + } + } + else + { + if (isBulkFetchProcessingComplete()) + { + if (sFullFetchStarted) + { + sAllFoldersFetched = TRUE; + } + stopBackgroundFetch(); + } + } + gInventory.notifyObservers(); +} + +void LLInventoryModel::fetchDescendentsResponder::onClickRetry(S32 option, void* userdata) +{ + if (option == 0) + { + std::string url = gAgent.getRegion()->getCapability("FetchInventoryDescendents"); + + if (!url.empty()) //Capability found. Build up LLSD and use it. + { + LLSD body = sRetrySD; + LLInventoryModel::incrBulkFetch(1); + LLHTTPClient::post(url, body, new LLInventoryModel::fetchDescendentsResponder(body),300); + } + } + else + { + if (isBulkFetchProcessingComplete()) + { + if (sFullFetchStarted) + { + sAllFoldersFetched = TRUE; + } + stopBackgroundFetch(); + } + } + sRetryDialog=NULL; + sRetrySD.clear(); +} + +//static Bundle up a bunch of requests to send all at once. +void LLInventoryModel::bulkFetch(std::string url) +{ + //Background fetch is called from gIdleCallbacks in a loop until background fetch is stopped. + //If there are items in sFetchQueue, we want to check the time since the last bulkFetch was + //sent. If it exceeds our retry time, go ahead and fire off another batch. + //Stopbackgroundfetch will be run from the Responder instead of here. + + S16 max_concurrent_fetches=8; + F32 new_min_time = 0.5f; //HACK! Clean this up when old code goes away entirely. + if (sMinTimeBetweenFetches <= new_min_time) sMinTimeBetweenFetches=new_min_time; //HACK! See above. + + if(gDisconnected + || sBulkFetchCount > max_concurrent_fetches + || sFetchTimer.getElapsedTimeF32() < sMinTimeBetweenFetches) + { + return; // just bail if we are disconnected. + } + + //HACK. This is inelegant. We're shuffling a dequeue to a map to get rid of + //redundant requests. When we get rid of the old code entirely, we can change + //the dequeue to a map. In the new model, there is no benefit to queue order. + U32 folder_count=0; + U32 max_batch_size=10; + while( !(sFetchQueue.empty() ) ) + { + LLViewerInventoryCategory* cat = gInventory.getCategory(sFetchQueue.front()); + + if (cat) + { + if ( !gInventory.isCategoryComplete(cat->getUUID()) ) //grab this folder. + { + sBulkFetchMap[(cat->getUUID())] = cat; + } + else if (sFullFetchStarted) + { //Already have this folder but append child folders to list. + // add all children to queue + parent_cat_map_t::iterator cat_it = gInventory.mParentChildCategoryTree.find(cat->getUUID()); + if (cat_it != gInventory.mParentChildCategoryTree.end()) + { + cat_array_t* child_categories = cat_it->second; + + for (S32 child_num = 0; child_num < child_categories->count(); child_num++) + { + sFetchQueue.push_back(child_categories->get(child_num)->getUUID()); + } + } + + } + } + sFetchQueue.pop_front(); + } + + + if (!sBulkFetchMap.empty()) //There's stuff to fetch. + { + U32 sort_order = gSavedSettings.getU32("InventorySortOrder") & 0x1; + + LLSD body; + + cat_map_t::iterator iter=sBulkFetchMap.begin(); + while( iter!=sBulkFetchMap.end() && (folder_count < max_batch_size) ) + { + LLViewerInventoryCategory* cat = iter->second; + + if (cat && !gInventory.isCategoryComplete(cat->getUUID()) ) //Category exists + { + BOOL fetchItems=TRUE; + if ( sFullFetchStarted + && gInventory.isCategoryComplete(cat->getUUID()) ) + { + fetchItems=FALSE; + } + + LLSD folder_sd; + folder_sd["folder-id"] = cat->getUUID(); + folder_sd["owner-id"] = cat->getOwnerID(); + folder_sd["sort-order"] = (LLSD::Integer)sort_order; + folder_sd["fetch-folders"] = (LLSD::Boolean)sFullFetchStarted; + folder_sd["fetch-items"] = (LLSD::Boolean)fetchItems; + body["folders"].append(folder_sd); + + folder_count++; + } + sBulkFetchMap.erase(iter); + iter=sBulkFetchMap.begin(); + } + + if (iter == sBulkFetchMap.end()) sBulkFetchMap.clear(); + + if (folder_count > 0) + { + sBulkFetchCount++; + + LLHTTPClient::post(url, body, new LLInventoryModel::fetchDescendentsResponder(body)); + sFetchTimer.reset(); + } + + } + + if (isBulkFetchProcessingComplete()) + { + if (sFullFetchStarted) + { + sAllFoldersFetched = TRUE; + } + stopBackgroundFetch(); + } +} + // static bool LLInventoryModel::isEverythingFetched() { @@ -1049,6 +1334,9 @@ void LLInventoryModel::stopBackgroundFetch() { sBackgroundFetchActive = FALSE; gIdleCallbacks.deleteFunction(&LLInventoryModel::backgroundFetch, NULL); + sBulkFetchCount=0; + sMinTimeBetweenFetches=0.0f; +// sFullFetchStarted=FALSE; } } @@ -1057,6 +1345,15 @@ void LLInventoryModel::backgroundFetch(void*) { if (sBackgroundFetchActive) { + //If we'll be using the capability, we'll be sending batches and the background thing isn't as important. + std::string url = gAgent.getRegion()->getCapability("FetchInventoryDescendents"); + if (!url.empty()) + { + bulkFetch(url); + return; + } + + //DEPRECATED OLD CODE FOLLOWS. // no more categories to fetch, stop fetch process if (sFetchQueue.empty()) { @@ -3063,8 +3360,8 @@ void LLInventoryFetchDescendentsObserver::fetchDescendents( if(!cat) continue; if(!isComplete(cat)) { - cat->fetchDescendents(); - mIncompleteFolders.push_back(*it); + cat->fetchDescendents(); //blindly fetch it without seeing if anything else is fetching it. + mIncompleteFolders.push_back(*it); //Add to list of things being downloaded for this observer. } else { diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index b560aea8b2..79a35f78ea 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -91,6 +91,7 @@ class LLViewerInventoryItem; class LLViewerInventoryCategory; class LLMessageSystem; class LLInventoryCollectFunctor; +class LLAlertDialog; class LLInventoryModel { @@ -105,11 +106,26 @@ public: // These are used a lot... typedef LLDynamicArray<LLPointer<LLViewerInventoryCategory> > cat_array_t; typedef LLDynamicArray<LLPointer<LLViewerInventoryItem> > item_array_t; - // construction & destruction LLInventoryModel(); ~LLInventoryModel(); + class fetchDescendentsResponder: public LLHTTPClient::Responder + { + public: + fetchDescendentsResponder(const LLSD& request_sd) : mRequestSD(request_sd) {}; + void result(const LLSD& content); + void error(U32 status, const std::string& reason); + static void onClickRetry(S32 option, void* userdata); + static void appendRetryList(LLSD retry_sd); + public: + typedef std::vector<LLViewerInventoryCategory*> folder_ref_t; + protected: + LLSD mRequestSD; + static LLSD sRetrySD; + static LLAlertDialog *sRetryDialog; + }; + // // Accessors // @@ -263,6 +279,9 @@ public: // make sure we have the descendents in the structure. void fetchDescendentsOf(const LLUUID& folder_id); + + // Add categories to a list to be fetched in bulk. + static void bulkFetch(std::string url); // call this method to request the inventory. //void requestFromServer(const LLUUID& agent_id); @@ -348,7 +367,7 @@ public: static BOOL backgroundFetchActive(); static bool isEverythingFetched(); static void backgroundFetch(void*); // background fetch idle function - + static void incrBulkFetch(S16 fetching) { sBulkFetchCount+=fetching; if (sBulkFetchCount<0) sBulkFetchCount=0; } protected: // Internal methods which add inventory and make sure that all of @@ -395,7 +414,8 @@ protected: static void processInventoryDescendents(LLMessageSystem* msg, void**); static void processMoveInventoryItem(LLMessageSystem* msg, void**); static void processFetchInventoryReply(LLMessageSystem* msg, void**); - + static bool isBulkFetchProcessingComplete(); + bool messageUpdateCore(LLMessageSystem* msg, bool do_accounting); protected: @@ -430,6 +450,7 @@ protected: observer_list_t mObservers; // completing the fetch once per session should be sufficient + static cat_map_t sBulkFetchMap; static BOOL sBackgroundFetchActive; static BOOL sTimelyFetchPending; static BOOL sAllFoldersFetched; @@ -438,6 +459,7 @@ protected: static LLFrameTimer sFetchTimer; static F32 sMinTimeBetweenFetches; static F32 sMaxTimeBetweenFetches; + static S16 sBulkFetchCount; // This flag is used to handle an invalid inventory state. bool mIsAgentInvUsable; diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 981605d1fa..01feff9b3c 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -48,6 +48,8 @@ #include "llviewerregion.h" #include "llviewerobjectlist.h" #include "llpreviewgesture.h" +#include "llviewerwindow.h" + ///---------------------------------------------------------------------------- /// Local function declarations, constants, enums, and typedefs ///---------------------------------------------------------------------------- @@ -213,6 +215,14 @@ void LLViewerInventoryItem::fetchFromServer(void) const } // virtual +BOOL LLViewerInventoryItem::unpackMessage(LLSD item) +{ + BOOL rv = LLInventoryItem::fromLLSD(item); + mIsComplete = TRUE; + return rv; +} + +// virtual BOOL LLViewerInventoryItem::unpackMessage( LLMessageSystem* msg, const char* block, S32 block_num) { @@ -420,30 +430,42 @@ void LLViewerInventoryCategory::removeFromServer( void ) bool LLViewerInventoryCategory::fetchDescendents() { if((VERSION_UNKNOWN == mVersion) - && mDescendentsRequested.hasExpired()) + && mDescendentsRequested.hasExpired()) //Expired check prevents multiple downloads. { const F32 FETCH_TIMER_EXPIRY = 10.0f; mDescendentsRequested.reset(); mDescendentsRequested.setTimerExpirySec(FETCH_TIMER_EXPIRY); - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("FetchInventoryDescendents"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->nextBlock("InventoryData"); - msg->addUUID("FolderID", mUUID); - msg->addUUID("OwnerID", mOwnerID); // bitfield // 1 = by date // 2 = folders by date // Need to mask off anything but the first bit. // This comes from LLInventoryFilter from llfolderview.h U32 sort_order = gSavedSettings.getU32("InventorySortOrder") & 0x1; - msg->addS32("SortOrder", sort_order); - msg->addBOOL("FetchFolders", FALSE); - msg->addBOOL("FetchItems", TRUE); - gAgent.sendReliableMessage(); + + std::string url = gAgent.getRegion()->getCapability("FetchInventoryDescendents"); + + if (!url.empty()) //Capability found. Build up LLSD and use it. + { + LLInventoryModel::startBackgroundFetch(mUUID); + } + else + { //Deprecated, but if we don't have a capability, use the old system. + llinfos << "FetchInventoryDescendents capability not found. Using deprecated UDP message." << llendl; + LLMessageSystem* msg = gMessageSystem; + msg->newMessage("FetchInventoryDescendents"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID()); + msg->addUUID("SessionID", gAgent.getSessionID()); + msg->nextBlock("InventoryData"); + msg->addUUID("FolderID", mUUID); + msg->addUUID("OwnerID", mOwnerID); + + msg->addS32("SortOrder", sort_order); + msg->addBOOL("FetchFolders", FALSE); + msg->addBOOL("FetchItems", TRUE); + gAgent.sendReliableMessage(); + } return true; } return false; diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index fd6928243b..bf49a1604f 100644 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -99,6 +99,7 @@ public: //virtual void packMessage(LLMessageSystem* msg) const; virtual BOOL unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0); + virtual BOOL unpackMessage(LLSD item); virtual BOOL importFile(FILE* fp); virtual BOOL importLegacyStream(std::istream& input_stream); diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 3f0f5bee98..42654e250b 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1378,6 +1378,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url) capabilityNames.append("DispatchRegionInfo"); capabilityNames.append("EstateChangeInfo"); capabilityNames.append("EventQueueGet"); + capabilityNames.append("FetchInventoryDescendents"); capabilityNames.append("GroupProposalBallot"); capabilityNames.append("MapLayer"); capabilityNames.append("MapLayerGod"); diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index 3df2073c6a..9dc92efa81 100644 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -33,10 +33,10 @@ #include "llxmlrpctransaction.h" +#include "llcurl.h" #include "llviewercontrol.h" // Have to include these last to avoid queue redefinition! -#include <curl/curl.h> #include <xmlrpc-epi/xmlrpc.h> #include "llappviewer.h" @@ -150,51 +150,48 @@ class LLXMLRPCTransaction::Impl { public: typedef LLXMLRPCTransaction::Status Status; - - CURL* mCurl; - CURLM* mCurlMulti; + + LLCurlEasyRequest* mCurlRequest; Status mStatus; CURLcode mCurlCode; std::string mStatusMessage; std::string mStatusURI; + LLCurl::TransferInfo mTransferInfo; - char mCurlErrorBuffer[CURL_ERROR_SIZE]; /* Flawfinder: ignore */ - std::string mURI; char* mRequestText; int mRequestTextSize; std::string mProxyAddress; - struct curl_slist* mHeaders; std::string mResponseText; XMLRPC_REQUEST mResponse; Impl(const std::string& uri, XMLRPC_REQUEST request, bool useGzip); Impl(const std::string& uri, - const std::string& method, LLXMLRPCValue params, bool useGzip); + const std::string& method, LLXMLRPCValue params, bool useGzip); ~Impl(); bool process(); void setStatus(Status code, - const std::string& message = "", const std::string& uri = ""); + const std::string& message = "", const std::string& uri = ""); void setCurlStatus(CURLcode); private: void init(XMLRPC_REQUEST request, bool useGzip); static size_t curlDownloadCallback( - void* data, size_t size, size_t nmemb, void* user_data); + char* data, size_t size, size_t nmemb, void* user_data); }; LLXMLRPCTransaction::Impl::Impl(const std::string& uri, XMLRPC_REQUEST request, bool useGzip) - : mCurl(0), mCurlMulti(0), + : mCurlRequest(0), mStatus(LLXMLRPCTransaction::StatusNotStarted), mURI(uri), - mRequestText(0), mHeaders(0), + mRequestText(0), mResponse(0) { init(request, useGzip); @@ -203,10 +200,10 @@ LLXMLRPCTransaction::Impl::Impl(const std::string& uri, LLXMLRPCTransaction::Impl::Impl(const std::string& uri, const std::string& method, LLXMLRPCValue params, bool useGzip) - : mCurl(0), mCurlMulti(0), + : mCurlRequest(0), mStatus(LLXMLRPCTransaction::StatusNotStarted), mURI(uri), - mRequestText(0), mHeaders(0), + mRequestText(0), mResponse(0) { XMLRPC_REQUEST request = XMLRPC_RequestNew(); @@ -222,55 +219,53 @@ LLXMLRPCTransaction::Impl::Impl(const std::string& uri, void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip) { - mCurl = curl_easy_init(); - + if (!mCurlRequest) + { + mCurlRequest = new LLCurlEasyRequest(); + } + if (gSavedSettings.getBOOL("BrowserProxyEnabled")) { mProxyAddress = gSavedSettings.getString("BrowserProxyAddress"); S32 port = gSavedSettings.getS32 ( "BrowserProxyPort" ); // tell curl about the settings - curl_easy_setopt(mCurl, CURLOPT_PROXY, mProxyAddress.c_str()); - curl_easy_setopt(mCurl, CURLOPT_PROXYPORT, (long) port); - curl_easy_setopt(mCurl, CURLOPT_PROXYTYPE, (long) CURLPROXY_HTTP); - }; - -// curl_easy_setopt(mCurl, CURLOPT_VERBOSE, 1L); // usefull for debugging - curl_easy_setopt(mCurl, CURLOPT_NOSIGNAL, 1L); - curl_easy_setopt(mCurl, CURLOPT_WRITEFUNCTION, &curlDownloadCallback); - curl_easy_setopt(mCurl, CURLOPT_WRITEDATA, this); - curl_easy_setopt(mCurl, CURLOPT_ERRORBUFFER, &mCurlErrorBuffer); - curl_easy_setopt(mCurl, CURLOPT_CAINFO, gDirUtilp->getCAFile().c_str()); - curl_easy_setopt(mCurl, CURLOPT_SSL_VERIFYPEER, (long) gVerifySSLCert); - curl_easy_setopt(mCurl, CURLOPT_SSL_VERIFYHOST, gVerifySSLCert? 2L : 0L); + mCurlRequest->setoptString(CURLOPT_PROXY, mProxyAddress); + mCurlRequest->setopt(CURLOPT_PROXYPORT, port); + mCurlRequest->setopt(CURLOPT_PROXYTYPE, CURLPROXY_HTTP); + } + +// mCurlRequest->setopt(CURLOPT_VERBOSE, 1); // usefull for debugging + mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1); + mCurlRequest->setWriteCallback(&curlDownloadCallback, (void*)this); + mCurlRequest->setopt(CURLOPT_SSL_VERIFYPEER, gVerifySSLCert); + mCurlRequest->setopt(CURLOPT_SSL_VERIFYHOST, gVerifySSLCert? 2 : 0); // Be a little impatient about establishing connections. - curl_easy_setopt(mCurl, CURLOPT_CONNECTTIMEOUT, 40L); + mCurlRequest->setopt(CURLOPT_CONNECTTIMEOUT, 40L); /* Setting the DNS cache timeout to -1 disables it completely. This might help with bug #503 */ - curl_easy_setopt(mCurl, CURLOPT_DNS_CACHE_TIMEOUT, -1L); + mCurlRequest->setopt(CURLOPT_DNS_CACHE_TIMEOUT, -1); + + mCurlRequest->slist_append("Content-Type: text/xml"); - mHeaders = curl_slist_append(mHeaders, "Content-Type: text/xml"); - curl_easy_setopt(mCurl, CURLOPT_URL, mURI.c_str()); - curl_easy_setopt(mCurl, CURLOPT_HTTPHEADER, mHeaders); if (useGzip) { - curl_easy_setopt(mCurl, CURLOPT_ENCODING, ""); + mCurlRequest->setoptString(CURLOPT_ENCODING, ""); } mRequestText = XMLRPC_REQUEST_ToXML(request, &mRequestTextSize); if (mRequestText) { - curl_easy_setopt(mCurl, CURLOPT_POSTFIELDS, mRequestText); - curl_easy_setopt(mCurl, CURLOPT_POSTFIELDSIZE, (long) mRequestTextSize); + mCurlRequest->setoptString(CURLOPT_POSTFIELDS, mRequestText); + mCurlRequest->setopt(CURLOPT_POSTFIELDSIZE, mRequestTextSize); } else { setStatus(StatusOtherError); } - - mCurlMulti = curl_multi_init(); - curl_multi_add_handle(mCurlMulti, mCurl); + + mCurlRequest->sendRequest(mURI); } @@ -281,30 +276,12 @@ LLXMLRPCTransaction::Impl::~Impl() XMLRPC_RequestFree(mResponse, 1); } - if (mHeaders) - { - curl_slist_free_all(mHeaders); - } - if (mRequestText) { XMLRPC_Free(mRequestText); } - if (mCurl) - { - if (mCurlMulti) - { - curl_multi_remove_handle(mCurlMulti, mCurl); - } - curl_easy_cleanup(mCurl); - } - - if (mCurlMulti) - { - curl_multi_cleanup(mCurlMulti); - } - + delete mCurlRequest; } bool LLXMLRPCTransaction::Impl::process() @@ -333,27 +310,28 @@ bool LLXMLRPCTransaction::Impl::process() const F32 MAX_PROCESSING_TIME = 0.05f; LLTimer timer; - int count; - - while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(mCurlMulti, &count)) + + while (mCurlRequest->perform() > 0) { if (timer.getElapsedTimeF32() >= MAX_PROCESSING_TIME) { return false; } } - - while(CURLMsg* curl_msg = curl_multi_info_read(mCurlMulti, &count)) + + while(1) { - if (CURLMSG_DONE == curl_msg->msg) + CURLcode result; + bool newmsg = mCurlRequest->getResult(&result, &mTransferInfo); + if (newmsg) { - if (curl_msg->data.result != CURLE_OK) + if (result != CURLE_OK) { - setCurlStatus(curl_msg->data.result); + setCurlStatus(result); llwarns << "LLXMLRPCTransaction CURL error " - << mCurlCode << ": " << mCurlErrorBuffer << llendl; + << mCurlCode << ": " << mCurlRequest->getErrorString() << llendl; llwarns << "LLXMLRPCTransaction request URI: " - << mURI << llendl; + << mURI << llendl; return true; } @@ -361,7 +339,7 @@ bool LLXMLRPCTransaction::Impl::process() setStatus(LLXMLRPCTransaction::StatusComplete); mResponse = XMLRPC_REQUEST_FromXML( - mResponseText.data(), mResponseText.size(), NULL); + mResponseText.data(), mResponseText.size(), NULL); bool hasError = false; bool hasFault = false; @@ -387,15 +365,19 @@ bool LLXMLRPCTransaction::Impl::process() setStatus(LLXMLRPCTransaction::StatusXMLRPCError); llwarns << "LLXMLRPCTransaction XMLRPC " - << (hasError ? "error " : "fault ") - << faultCode << ": " - << faultString << llendl; + << (hasError ? "error " : "fault ") + << faultCode << ": " + << faultString << llendl; llwarns << "LLXMLRPCTransaction request URI: " - << mURI << llendl; + << mURI << llendl; } return true; } + else + { + break; // done + } } return false; @@ -504,13 +486,13 @@ void LLXMLRPCTransaction::Impl::setCurlStatus(CURLcode code) } size_t LLXMLRPCTransaction::Impl::curlDownloadCallback( - void* data, size_t size, size_t nmemb, void* user_data) + char* data, size_t size, size_t nmemb, void* user_data) { Impl& impl(*(Impl*)user_data); size_t n = size * nmemb; - impl.mResponseText.append((const char*)data, n); + impl.mResponseText.append(data, n); if (impl.mStatus == LLXMLRPCTransaction::StatusStarted) { @@ -579,25 +561,17 @@ LLXMLRPCValue LLXMLRPCTransaction::responseValue() F64 LLXMLRPCTransaction::transferRate() { - if (!impl.mCurl || impl.mStatus != StatusComplete) + if (impl.mStatus != StatusComplete) { return 0.0L; } - double size_bytes = 0.0; - double time_seconds = 0.0; - double rate_bytes_per_sec = 0.0; - - curl_easy_getinfo(impl.mCurl, CURLINFO_SIZE_DOWNLOAD, &size_bytes); - curl_easy_getinfo(impl.mCurl, CURLINFO_TOTAL_TIME, &time_seconds); - curl_easy_getinfo(impl.mCurl, CURLINFO_SPEED_DOWNLOAD, &rate_bytes_per_sec); - - double rate_bits_per_sec = rate_bytes_per_sec * 8.0; + double rate_bits_per_sec = impl.mTransferInfo.mSpeedDownload * 8.0; llinfos << "Buffer size: " << impl.mResponseText.size() << " B" << llendl; - llinfos << "Transfer size: " << size_bytes << " B" << llendl; - llinfos << "Transfer time: " << time_seconds << " s" << llendl; - llinfos << "Transfer rate: " << rate_bits_per_sec/1000.0 << " Kb/s" << llendl; + llinfos << "Transfer size: " << impl.mTransferInfo.mSizeDownload << " B" << llendl; + llinfos << "Transfer time: " << impl.mTransferInfo.mTotalTime << " s" << llendl; + llinfos << "Transfer rate: " << rate_bits_per_sec / 1000.0 << " Kb/s" << llendl; return rate_bits_per_sec; } |