summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/llappviewer.cpp17
-rw-r--r--indra/newview/llinventorymodel.cpp301
-rw-r--r--indra/newview/llinventorymodel.h28
-rw-r--r--indra/newview/llviewerinventory.cpp48
-rw-r--r--indra/newview/llviewerinventory.h1
-rw-r--r--indra/newview/llviewerregion.cpp1
-rw-r--r--indra/newview/llxmlrpctransaction.cpp152
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;
}