summaryrefslogtreecommitdiff
path: root/indra/llmessage/llcurl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llmessage/llcurl.cpp')
-rw-r--r--indra/llmessage/llcurl.cpp451
1 files changed, 316 insertions, 135 deletions
diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp
index a485fa0160..6e063818e2 100644
--- a/indra/llmessage/llcurl.cpp
+++ b/indra/llmessage/llcurl.cpp
@@ -1,5 +1,5 @@
/**
- * @file llcurl.h
+ * @file llcurl.cpp
* @author Zero / Donovan
* @date 2006-10-15
* @brief Implementation of wrapper around libcurl.
@@ -46,9 +46,11 @@
#endif
#include "llbufferstream.h"
-#include "llstl.h"
+#include "llproxy.h"
#include "llsdserialize.h"
+#include "llstl.h"
#include "llthread.h"
+#include "lltimer.h"
//////////////////////////////////////////////////////////////////////////////
/*
@@ -73,6 +75,7 @@ static const S32 MULTI_PERFORM_CALL_REPEAT = 5;
static const S32 CURL_REQUEST_TIMEOUT = 30; // seconds
static const S32 MAX_ACTIVE_REQUEST_COUNT = 100;
+static
// DEBUG //
S32 gCurlEasyCount = 0;
S32 gCurlMultiCount = 0;
@@ -84,6 +87,29 @@ std::vector<LLMutex*> LLCurl::sSSLMutex;
std::string LLCurl::sCAPath;
std::string LLCurl::sCAFile;
+bool LLCurl::sMultiThreaded = false;
+static U32 sMainThreadID = 0;
+
+void check_curl_code(CURLcode code)
+{
+ if (code != CURLE_OK)
+ {
+ // linux appears to throw a curl error once per session for a bad initialization
+ // at a pretty random time (when enabling cookies).
+ llinfos << "curl error detected: " << curl_easy_strerror(code) << llendl;
+ }
+}
+
+void check_curl_multi_code(CURLMcode code)
+{
+ if (code != CURLM_OK)
+ {
+ // linux appears to throw a curl error once per session for a bad initialization
+ // at a pretty random time (when enabling cookies).
+ llinfos << "curl multi error detected: " << curl_multi_strerror(code) << llendl;
+ }
+}
+
//static
void LLCurl::setCAPath(const std::string& path)
{
@@ -183,7 +209,7 @@ namespace boost
void intrusive_ptr_release(LLCurl::Responder* p)
{
- if(p && 0 == --p->mReferenceCount)
+ if (p && 0 == --p->mReferenceCount)
{
delete p;
}
@@ -193,63 +219,55 @@ namespace boost
//////////////////////////////////////////////////////////////////////////////
+std::set<CURL*> LLCurl::Easy::sFreeHandles;
+std::set<CURL*> LLCurl::Easy::sActiveHandles;
+LLMutex* LLCurl::Easy::sHandleMutex = NULL;
+LLMutex* LLCurl::Easy::sMultiMutex = NULL;
-class LLCurl::Easy
+//static
+CURL* LLCurl::Easy::allocEasyHandle()
{
- LOG_CLASS(Easy);
-
-private:
- Easy();
-
-public:
- static Easy* getEasy();
- ~Easy();
-
- CURL* getCurlHandle() const { return mCurlEasyHandle; }
+ CURL* ret = NULL;
+ LLMutexLock lock(sHandleMutex);
+ if (sFreeHandles.empty())
+ {
+ ret = curl_easy_init();
+ }
+ else
+ {
+ ret = *(sFreeHandles.begin());
+ sFreeHandles.erase(ret);
+ curl_easy_reset(ret);
+ }
- void setErrorBuffer();
- void setCA();
-
- void setopt(CURLoption option, S32 value);
- // These assume the setter does not free value!
- void setopt(CURLoption option, void* value);
- void setopt(CURLoption option, char* value);
- // Copies the string so that it is gauranteed to stick around
- void setoptString(CURLoption option, const std::string& value);
-
- void slist_append(const char* str);
- void setHeaders();
-
- U32 report(CURLcode);
- void getTransferInfo(LLCurl::TransferInfo* info);
+ if (ret)
+ {
+ sActiveHandles.insert(ret);
+ }
- void prepRequest(const std::string& url, const std::vector<std::string>& headers, ResponderPtr, bool post = false);
-
- const char* getErrorBuffer();
+ return ret;
+}
- std::stringstream& getInput() { return mInput; }
- std::stringstream& getHeaderOutput() { return mHeaderOutput; }
- LLIOPipe::buffer_ptr_t& getOutput() { return mOutput; }
- const LLChannelDescriptors& getChannels() { return mChannels; }
-
- void resetState();
+//static
+void LLCurl::Easy::releaseEasyHandle(CURL* handle)
+{
+ if (!handle)
+ {
+ llerrs << "handle cannot be NULL!" << llendl;
+ }
-private:
- CURL* mCurlEasyHandle;
- struct curl_slist* mHeaders;
+ LLMutexLock lock(sHandleMutex);
- std::stringstream mRequest;
- LLChannelDescriptors mChannels;
- LLIOPipe::buffer_ptr_t mOutput;
- std::stringstream mInput;
- std::stringstream mHeaderOutput;
- char mErrorBuffer[CURL_ERROR_SIZE];
-
- // Note: char*'s not strings since we pass pointers to curl
- std::vector<char*> mStrings;
-
- ResponderPtr mResponder;
-};
+ if (sActiveHandles.find(handle) != sActiveHandles.end())
+ {
+ sActiveHandles.erase(handle);
+ sFreeHandles.insert(handle);
+ }
+ else
+ {
+ llerrs << "Invalid handle." << llendl;
+ }
+}
LLCurl::Easy::Easy()
: mHeaders(NULL),
@@ -261,25 +279,28 @@ LLCurl::Easy::Easy()
LLCurl::Easy* LLCurl::Easy::getEasy()
{
Easy* easy = new Easy();
- easy->mCurlEasyHandle = curl_easy_init();
+ easy->mCurlEasyHandle = allocEasyHandle();
+
if (!easy->mCurlEasyHandle)
{
// this can happen if we have too many open files (fails in c-ares/ares_init.c)
- llwarns << "curl_multi_init() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << llendl;
+ llwarns << "allocEasyHandle() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << llendl;
delete easy;
return NULL;
}
- // set no DMS caching as default for all easy handles. This prevents them adopting a
+ // set no DNS caching as default for all easy handles. This prevents them adopting a
// multi handles cache if they are added to one.
- curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0);
+ CURLcode result = curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0);
+ check_curl_code(result);
+
++gCurlEasyCount;
return easy;
}
LLCurl::Easy::~Easy()
{
- curl_easy_cleanup(mCurlEasyHandle);
+ releaseEasyHandle(mCurlEasyHandle);
--gCurlEasyCount;
curl_slist_free_all(mHeaders);
for_each(mStrings.begin(), mStrings.end(), DeletePointerArray());
@@ -321,11 +342,11 @@ const char* LLCurl::Easy::getErrorBuffer()
void LLCurl::Easy::setCA()
{
- if(!sCAPath.empty())
+ if (!sCAPath.empty())
{
setoptString(CURLOPT_CAPATH, sCAPath);
}
- if(!sCAFile.empty())
+ if (!sCAFile.empty())
{
setoptString(CURLOPT_CAINFO, sCAFile);
}
@@ -338,9 +359,9 @@ void LLCurl::Easy::setHeaders()
void LLCurl::Easy::getTransferInfo(LLCurl::TransferInfo* info)
{
- curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SIZE_DOWNLOAD, &info->mSizeDownload);
- curl_easy_getinfo(mCurlEasyHandle, CURLINFO_TOTAL_TIME, &info->mTotalTime);
- curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SPEED_DOWNLOAD, &info->mSpeedDownload);
+ check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SIZE_DOWNLOAD, &info->mSizeDownload));
+ check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_TOTAL_TIME, &info->mTotalTime));
+ check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SPEED_DOWNLOAD, &info->mSpeedDownload));
}
U32 LLCurl::Easy::report(CURLcode code)
@@ -350,13 +371,14 @@ U32 LLCurl::Easy::report(CURLcode code)
if (code == CURLE_OK)
{
- curl_easy_getinfo(mCurlEasyHandle, CURLINFO_RESPONSE_CODE, &responseCode);
+ check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_RESPONSE_CODE, &responseCode));
//*TODO: get reason from first line of mHeaderOutput
}
else
{
responseCode = 499;
responseReason = strerror(code) + " : " + mErrorBuffer;
+ setopt(CURLOPT_FRESH_CONNECT, TRUE);
}
if (mResponder)
@@ -372,17 +394,20 @@ U32 LLCurl::Easy::report(CURLcode code)
// Note: these all assume the caller tracks the value (i.e. keeps it persistant)
void LLCurl::Easy::setopt(CURLoption option, S32 value)
{
- curl_easy_setopt(mCurlEasyHandle, option, value);
+ CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, value);
+ check_curl_code(result);
}
void LLCurl::Easy::setopt(CURLoption option, void* value)
{
- curl_easy_setopt(mCurlEasyHandle, option, value);
+ CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, value);
+ check_curl_code(result);
}
void LLCurl::Easy::setopt(CURLoption option, char* value)
{
- curl_easy_setopt(mCurlEasyHandle, option, value);
+ CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, value);
+ check_curl_code(result);
}
// Note: this copies the string so that the caller does not have to keep it around
@@ -391,7 +416,8 @@ void LLCurl::Easy::setoptString(CURLoption option, const std::string& value)
char* tstring = new char[value.length()+1];
strcpy(tstring, value.c_str());
mStrings.push_back(tstring);
- curl_easy_setopt(mCurlEasyHandle, option, tstring);
+ CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, tstring);
+ check_curl_code(result);
}
void LLCurl::Easy::slist_append(const char* str)
@@ -437,15 +463,18 @@ size_t curlHeaderCallback(void* data, size_t size, size_t nmemb, void* user_data
void LLCurl::Easy::prepRequest(const std::string& url,
const std::vector<std::string>& headers,
- ResponderPtr responder, bool post)
+ ResponderPtr responder, S32 time_out, bool post)
{
resetState();
if (post) setoptString(CURLOPT_ENCODING, "");
-// setopt(CURLOPT_VERBOSE, 1); // usefull for debugging
+ //setopt(CURLOPT_VERBOSE, 1); // useful for debugging
setopt(CURLOPT_NOSIGNAL, 1);
+ // Set the CURL options for either Socks or HTTP proxy
+ LLProxy::getInstance()->applyProxySettings(this);
+
mOutput.reset(new LLBufferArray);
setopt(CURLOPT_WRITEFUNCTION, (void*)&curlWriteCallback);
setopt(CURLOPT_WRITEDATA, (void*)this);
@@ -457,7 +486,7 @@ void LLCurl::Easy::prepRequest(const std::string& url,
setopt(CURLOPT_HEADERDATA, (void*)this);
// Allow up to five redirects
- if(responder && responder->followRedir())
+ if (responder && responder->followRedir())
{
setopt(CURLOPT_FOLLOWLOCATION, 1);
setopt(CURLOPT_MAXREDIRS, MAX_REDIRECTS);
@@ -467,7 +496,10 @@ void LLCurl::Easy::prepRequest(const std::string& url,
setCA();
setopt(CURLOPT_SSL_VERIFYPEER, true);
- setopt(CURLOPT_TIMEOUT, CURL_REQUEST_TIMEOUT);
+
+ //don't verify host name so urls with scrubbed host names will work (improves DNS performance)
+ setopt(CURLOPT_SSL_VERIFYHOST, 0);
+ setopt(CURLOPT_TIMEOUT, llmax(time_out, CURL_REQUEST_TIMEOUT));
setoptString(CURLOPT_URL, url);
@@ -488,62 +520,53 @@ void LLCurl::Easy::prepRequest(const std::string& url,
////////////////////////////////////////////////////////////////////////////
-class LLCurl::Multi
+LLCurl::Multi::Multi()
+ : LLThread("Curl Multi"),
+ mQueued(0),
+ mErrorCount(0),
+ mPerformState(PERFORM_STATE_READY)
{
- LOG_CLASS(Multi);
-public:
-
- Multi();
- ~Multi();
-
- Easy* allocEasy();
- bool addEasy(Easy* easy);
-
- void removeEasy(Easy* easy);
+ mQuitting = false;
- S32 process();
- S32 perform();
-
- CURLMsg* info_read(S32* msgs_in_queue);
-
- S32 mQueued;
- S32 mErrorCount;
-
-private:
- void easyFree(Easy*);
-
- CURLM* mCurlMultiHandle;
-
- typedef std::set<Easy*> easy_active_list_t;
- easy_active_list_t mEasyActiveList;
- typedef std::map<CURL*, Easy*> easy_active_map_t;
- easy_active_map_t mEasyActiveMap;
- typedef std::set<Easy*> easy_free_list_t;
- easy_free_list_t mEasyFreeList;
-};
+ mThreaded = LLCurl::sMultiThreaded && LLThread::currentID() == sMainThreadID;
+ if (mThreaded)
+ {
+ mSignal = new LLCondition();
+ }
+ else
+ {
+ mSignal = NULL;
+ }
-LLCurl::Multi::Multi()
- : mQueued(0),
- mErrorCount(0)
-{
mCurlMultiHandle = curl_multi_init();
if (!mCurlMultiHandle)
{
llwarns << "curl_multi_init() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << llendl;
mCurlMultiHandle = curl_multi_init();
}
+
llassert_always(mCurlMultiHandle);
++gCurlMultiCount;
}
LLCurl::Multi::~Multi()
{
+ llassert(isStopped());
+
+ if (LLCurl::sMultiThreaded)
+ {
+ LLCurl::Easy::sMultiMutex->lock();
+ }
+
+ delete mSignal;
+ mSignal = NULL;
+
// Clean up active
for(easy_active_list_t::iterator iter = mEasyActiveList.begin();
iter != mEasyActiveList.end(); ++iter)
{
Easy* easy = *iter;
- curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle());
+ check_curl_multi_code(curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle()));
delete easy;
}
mEasyActiveList.clear();
@@ -553,8 +576,13 @@ LLCurl::Multi::~Multi()
for_each(mEasyFreeList.begin(), mEasyFreeList.end(), DeletePointer());
mEasyFreeList.clear();
- curl_multi_cleanup(mCurlMultiHandle);
+ check_curl_multi_code(curl_multi_cleanup(mCurlMultiHandle));
--gCurlMultiCount;
+
+ if (LLCurl::sMultiThreaded)
+ {
+ LLCurl::Easy::sMultiMutex->unlock();
+ }
}
CURLMsg* LLCurl::Multi::info_read(S32* msgs_in_queue)
@@ -563,28 +591,65 @@ CURLMsg* LLCurl::Multi::info_read(S32* msgs_in_queue)
return curlmsg;
}
+void LLCurl::Multi::perform()
+{
+ if (mThreaded)
+ {
+ if (mPerformState == PERFORM_STATE_READY)
+ {
+ mSignal->signal();
+ }
+ }
+ else
+ {
+ doPerform();
+ }
+}
+
+void LLCurl::Multi::run()
+{
+ llassert(mThreaded);
-S32 LLCurl::Multi::perform()
+ while (!mQuitting)
+ {
+ mSignal->wait();
+ mPerformState = PERFORM_STATE_PERFORMING;
+ if (!mQuitting)
+ {
+ LLMutexLock lock(LLCurl::Easy::sMultiMutex);
+ doPerform();
+ }
+ }
+}
+
+void LLCurl::Multi::doPerform()
{
S32 q = 0;
for (S32 call_count = 0;
- call_count < MULTI_PERFORM_CALL_REPEAT;
- call_count += 1)
+ call_count < MULTI_PERFORM_CALL_REPEAT;
+ call_count += 1)
{
CURLMcode code = curl_multi_perform(mCurlMultiHandle, &q);
if (CURLM_CALL_MULTI_PERFORM != code || q == 0)
{
+ check_curl_multi_code(code);
break;
}
+
}
mQueued = q;
- return q;
+ mPerformState = PERFORM_STATE_COMPLETED;
}
S32 LLCurl::Multi::process()
{
perform();
-
+
+ if (mPerformState != PERFORM_STATE_COMPLETED)
+ {
+ return 0;
+ }
+
CURLMsg* msg;
int msgs_in_queue;
@@ -615,6 +680,8 @@ S32 LLCurl::Multi::process()
}
}
}
+
+ mPerformState = PERFORM_STATE_READY;
return processed;
}
@@ -642,11 +709,12 @@ LLCurl::Easy* LLCurl::Multi::allocEasy()
bool LLCurl::Multi::addEasy(Easy* easy)
{
CURLMcode mcode = curl_multi_add_handle(mCurlMultiHandle, easy->getCurlHandle());
- if (mcode != CURLM_OK)
- {
- llwarns << "Curl Error: " << curl_multi_strerror(mcode) << llendl;
- return false;
- }
+ check_curl_multi_code(mcode);
+ //if (mcode != CURLM_OK)
+ //{
+ // llwarns << "Curl Error: " << curl_multi_strerror(mcode) << llendl;
+ // return false;
+ //}
return true;
}
@@ -667,22 +735,14 @@ void LLCurl::Multi::easyFree(Easy* easy)
void LLCurl::Multi::removeEasy(Easy* easy)
{
- curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle());
+ check_curl_multi_code(curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle()));
easyFree(easy);
}
//static
std::string LLCurl::strerror(CURLcode errorcode)
{
-#if LL_DARWIN
- // curl_easy_strerror was added in libcurl 7.12.0. Unfortunately, the version in the Mac OS X 10.3.9 SDK is 7.10.2...
- // There's a problem with the custom curl headers in our build that keeps me from #ifdefing this on the libcurl version number
- // (the correct check would be #if LIBCURL_VERSION_NUM >= 0x070c00). We'll fix the header problem soon, but for now
- // just punt and print the numeric error code on the Mac.
- return llformat("%d", errorcode);
-#else // LL_DARWIN
return std::string(curl_easy_strerror(errorcode));
-#endif // LL_DARWIN
}
////////////////////////////////////////////////////////////////////////////
@@ -694,11 +754,27 @@ LLCurlRequest::LLCurlRequest() :
mActiveRequestCount(0)
{
mThreadID = LLThread::currentID();
+ mProcessing = FALSE;
}
LLCurlRequest::~LLCurlRequest()
{
llassert_always(mThreadID == LLThread::currentID());
+
+ //stop all Multi handle background threads
+ for (curlmulti_set_t::iterator iter = mMultiSet.begin(); iter != mMultiSet.end(); ++iter)
+ {
+ LLCurl::Multi* multi = *iter;
+ multi->mQuitting = true;
+ if (multi->mThreaded)
+ {
+ while (!multi->isStopped())
+ {
+ multi->mSignal->signal();
+ apr_sleep(1000);
+ }
+ }
+ }
for_each(mMultiSet.begin(), mMultiSet.end(), DeletePointer());
}
@@ -706,6 +782,10 @@ void LLCurlRequest::addMulti()
{
llassert_always(mThreadID == LLThread::currentID());
LLCurl::Multi* multi = new LLCurl::Multi();
+ if (multi->mThreaded)
+ {
+ multi->start();
+ }
mMultiSet.insert(multi);
mActiveMulti = multi;
mActiveRequestCount = 0;
@@ -728,6 +808,11 @@ LLCurl::Easy* LLCurlRequest::allocEasy()
bool LLCurlRequest::addEasy(LLCurl::Easy* easy)
{
llassert_always(mActiveMulti);
+
+ if (mProcessing)
+ {
+ llerrs << "Posting to a LLCurlRequest instance from within a responder is not allowed (causes DNS timeouts)." << llendl;
+ }
bool res = mActiveMulti->addEasy(easy);
return res;
}
@@ -762,14 +847,14 @@ bool LLCurlRequest::getByteRange(const std::string& url,
bool LLCurlRequest::post(const std::string& url,
const headers_t& headers,
const LLSD& data,
- LLCurl::ResponderPtr responder)
+ LLCurl::ResponderPtr responder, S32 time_out)
{
LLCurl::Easy* easy = allocEasy();
if (!easy)
{
return false;
}
- easy->prepRequest(url, headers, responder);
+ easy->prepRequest(url, headers, responder, time_out);
LLSDSerialize::toXML(data, easy->getInput());
S32 bytes = easy->getInput().str().length();
@@ -785,12 +870,41 @@ bool LLCurlRequest::post(const std::string& url,
bool res = addEasy(easy);
return res;
}
+
+bool LLCurlRequest::post(const std::string& url,
+ const headers_t& headers,
+ const std::string& data,
+ LLCurl::ResponderPtr responder, S32 time_out)
+{
+ LLCurl::Easy* easy = allocEasy();
+ if (!easy)
+ {
+ return false;
+ }
+ easy->prepRequest(url, headers, responder, time_out);
+
+ easy->getInput().write(data.data(), data.size());
+ S32 bytes = easy->getInput().str().length();
+ easy->setopt(CURLOPT_POST, 1);
+ easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL);
+ easy->setopt(CURLOPT_POSTFIELDSIZE, bytes);
+
+ easy->slist_append("Content-Type: application/octet-stream");
+ easy->setHeaders();
+
+ lldebugs << "POSTING: " << bytes << " bytes." << llendl;
+ bool res = addEasy(easy);
+ return res;
+}
+
// Note: call once per frame
S32 LLCurlRequest::process()
{
llassert_always(mThreadID == LLThread::currentID());
S32 res = 0;
+
+ mProcessing = TRUE;
for (curlmulti_set_t::iterator iter = mMultiSet.begin();
iter != mMultiSet.end(); )
{
@@ -801,9 +915,20 @@ S32 LLCurlRequest::process()
if (multi != mActiveMulti && tres == 0 && multi->mQueued == 0)
{
mMultiSet.erase(curiter);
+ multi->mQuitting = true;
+ if (multi->mThreaded)
+ {
+ while (!multi->isStopped())
+ {
+ multi->mSignal->signal();
+ apr_sleep(1000);
+ }
+ }
+
delete multi;
}
}
+ mProcessing = FALSE;
return res;
}
@@ -817,6 +942,10 @@ S32 LLCurlRequest::getQueued()
curlmulti_set_t::iterator curiter = iter++;
LLCurl::Multi* multi = *curiter;
queued += multi->mQueued;
+ if (multi->mPerformState != LLCurl::Multi::PERFORM_STATE_READY)
+ {
+ ++queued;
+ }
}
return queued;
}
@@ -830,16 +959,31 @@ LLCurlEasyRequest::LLCurlEasyRequest()
mResultReturned(false)
{
mMulti = new LLCurl::Multi();
+ if (mMulti->mThreaded)
+ {
+ mMulti->start();
+ }
mEasy = mMulti->allocEasy();
if (mEasy)
{
mEasy->setErrorBuffer();
mEasy->setCA();
+ // Set proxy settings if configured to do so.
+ LLProxy::getInstance()->applyProxySettings(mEasy);
}
}
LLCurlEasyRequest::~LLCurlEasyRequest()
{
+ mMulti->mQuitting = true;
+ if (mMulti->mThreaded)
+ {
+ while (!mMulti->isStopped())
+ {
+ mMulti->mSignal->signal();
+ apr_sleep(1000);
+ }
+ }
delete mMulti;
}
@@ -936,14 +1080,20 @@ void LLCurlEasyRequest::requestComplete()
}
}
-S32 LLCurlEasyRequest::perform()
+void LLCurlEasyRequest::perform()
{
- return mMulti->perform();
+ mMulti->perform();
}
// Usage: Call getRestult until it returns false (no more messages)
bool LLCurlEasyRequest::getResult(CURLcode* result, LLCurl::TransferInfo* info)
{
+ if (mMulti->mPerformState != LLCurl::Multi::PERFORM_STATE_COMPLETED)
+ { //we're busy, try again later
+ return false;
+ }
+ mMulti->mPerformState = LLCurl::Multi::PERFORM_STATE_READY;
+
if (!mEasy)
{
// Special case - we failed to initialize a curl_easy (can happen if too many open files)
@@ -1028,13 +1178,20 @@ unsigned long LLCurl::ssl_thread_id(void)
}
#endif
-void LLCurl::initClass()
+void LLCurl::initClass(bool multi_threaded)
{
+ sMainThreadID = LLThread::currentID();
+ sMultiThreaded = multi_threaded;
// Do not change this "unless you are familiar with and mean to control
// internal operations of libcurl"
// - http://curl.haxx.se/libcurl/c/curl_global_init.html
- curl_global_init(CURL_GLOBAL_ALL);
+ CURLcode code = curl_global_init(CURL_GLOBAL_ALL);
+
+ check_curl_code(code);
+ Easy::sHandleMutex = new LLMutex();
+ Easy::sMultiMutex = new LLMutex();
+
#if SAFE_SSL
S32 mutex_count = CRYPTO_num_locks();
for (S32 i=0; i<mutex_count; i++)
@@ -1052,7 +1209,31 @@ void LLCurl::cleanupClass()
CRYPTO_set_locking_callback(NULL);
for_each(sSSLMutex.begin(), sSSLMutex.end(), DeletePointer());
#endif
- curl_global_cleanup();
+
+ delete Easy::sHandleMutex;
+ Easy::sHandleMutex = NULL;
+ delete Easy::sMultiMutex;
+ Easy::sMultiMutex = NULL;
+
+ for (std::set<CURL*>::iterator iter = Easy::sFreeHandles.begin(); iter != Easy::sFreeHandles.end(); ++iter)
+ {
+ CURL* curl = *iter;
+ curl_easy_cleanup(curl);
+ }
+
+ Easy::sFreeHandles.clear();
+
+ llassert(Easy::sActiveHandles.empty());
}
const unsigned int LLCurl::MAX_REDIRECTS = 5;
+
+// Provide access to LLCurl free functions outside of llcurl.cpp without polluting the global namespace.
+void LLCurlFF::check_easy_code(CURLcode code)
+{
+ check_curl_code(code);
+}
+void LLCurlFF::check_multi_code(CURLMcode code)
+{
+ check_curl_multi_code(code);
+}