WIP: Make curl thread code robust and flexible.
Conflicts: indra/llmessage/llcurl.cpp indra/llmessage/llcurl.h indra/newview/app_settings/settings.xml indra/newview/llappviewer.cpp indra/newview/llmeshrepository.cpp Resolved: indra/llmessage/llcurl.cpp: Basically removed (not used anyway) indra/llmessage/llcurl.h: Basically removed (just includes aiculr.h now) indra/newview/app_settings/settings.xml: CurlUseMultipleThreads was remvoved. CurlMaximumNumberOfHandles and CurlRequestTimeOut are still in there, but unused at the moment. indra/newview/llappviewer.cpp: CurlMaximumNumberOfHandles and CurlRequestTimeOut are unused at the moment. indra/newview/llmeshrepository.cpp: Lock mSignal always (is unlocked inside wait()). Use mSignal lock to see if we are waiting; remove mWaiting. Return false from the MeshFetch functions iff we have to retry a HTTP fetch. Catch the error exception thrown by getByteRange instead of using it's return value (always returns true anyway).
This commit is contained in:
@@ -43,6 +43,11 @@
|
||||
#include "llappviewer.h"
|
||||
|
||||
#include "hippogridmanager.h"
|
||||
#include "statemachine/aicurleasyrequeststatemachine.h"
|
||||
|
||||
#ifdef CWDEBUG
|
||||
#include <libcwd/buf2str.h>
|
||||
#endif
|
||||
|
||||
LLXMLRPCValue LLXMLRPCValue::operator[](const char* id) const
|
||||
{
|
||||
@@ -154,7 +159,7 @@ class LLXMLRPCTransaction::Impl
|
||||
public:
|
||||
typedef LLXMLRPCTransaction::Status Status;
|
||||
|
||||
LLCurlEasyRequest* mCurlRequest;
|
||||
AICurlEasyRequestStateMachine* mCurlEasyRequestStateMachinePtr;
|
||||
|
||||
Status mStatus;
|
||||
CURLcode mCurlCode;
|
||||
@@ -176,7 +181,8 @@ public:
|
||||
const std::string& method, LLXMLRPCValue params, bool useGzip);
|
||||
~Impl();
|
||||
|
||||
bool process();
|
||||
bool is_finished(void) const;
|
||||
void curlEasyRequestCallback(bool success);
|
||||
|
||||
void setStatus(Status code,
|
||||
const std::string& message = "", const std::string& uri = "");
|
||||
@@ -191,7 +197,7 @@ private:
|
||||
|
||||
LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
|
||||
XMLRPC_REQUEST request, bool useGzip)
|
||||
: mCurlRequest(0),
|
||||
: mCurlEasyRequestStateMachinePtr(NULL),
|
||||
mStatus(LLXMLRPCTransaction::StatusNotStarted),
|
||||
mURI(uri),
|
||||
mRequestText(0),
|
||||
@@ -203,7 +209,7 @@ LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
|
||||
|
||||
LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
|
||||
const std::string& method, LLXMLRPCValue params, bool useGzip)
|
||||
: mCurlRequest(0),
|
||||
: mCurlEasyRequestStateMachinePtr(NULL),
|
||||
mStatus(LLXMLRPCTransaction::StatusNotStarted),
|
||||
mURI(uri),
|
||||
mRequestText(0),
|
||||
@@ -222,60 +228,66 @@ LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
|
||||
|
||||
void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip)
|
||||
{
|
||||
if (!mCurlRequest)
|
||||
{
|
||||
mCurlRequest = new LLCurlEasyRequest();
|
||||
}
|
||||
try
|
||||
{
|
||||
mCurlEasyRequestStateMachinePtr = new AICurlEasyRequestStateMachine(false);
|
||||
}
|
||||
catch(AICurlNoEasyHandle const& error)
|
||||
{
|
||||
llwarns << "Failed to initialize LLXMLRPCTransaction: " << error.what() << llendl;
|
||||
setStatus(StatusOtherError, "No curl easy handle");
|
||||
return;
|
||||
}
|
||||
AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequestStateMachinePtr->mCurlEasyRequest);
|
||||
|
||||
if(!mCurlRequest->isValid())
|
||||
curlEasyRequest_w->setWriteCallback(&curlDownloadCallback, (void*)this);
|
||||
BOOL vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert");
|
||||
curlEasyRequest_w->setopt(CURLOPT_SSL_VERIFYPEER, vefifySSLCert);
|
||||
curlEasyRequest_w->setopt(CURLOPT_SSL_VERIFYHOST, vefifySSLCert ? 2 : 0);
|
||||
// Be a little impatient about establishing connections.
|
||||
curlEasyRequest_w->setopt(CURLOPT_CONNECTTIMEOUT, 40L);
|
||||
|
||||
/* Setting the DNS cache timeout to -1 disables it completely.
|
||||
This might help with bug #503 */
|
||||
curlEasyRequest_w->setopt(CURLOPT_DNS_CACHE_TIMEOUT, -1);
|
||||
|
||||
curlEasyRequest_w->addHeader("Content-Type: text/xml");
|
||||
|
||||
if (useGzip)
|
||||
{
|
||||
curlEasyRequest_w->setoptString(CURLOPT_ENCODING, "");
|
||||
}
|
||||
|
||||
mRequestText = XMLRPC_REQUEST_ToXML(request, &mRequestTextSize);
|
||||
if (mRequestText)
|
||||
{
|
||||
Dout(dc::curl, "Writing " << mRequestTextSize << " bytes: \"" << libcwd::buf2str(mRequestText, mRequestTextSize) << "\".");;
|
||||
curlEasyRequest_w->setopt(CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)mRequestTextSize);
|
||||
curlEasyRequest_w->setoptString(CURLOPT_COPYPOSTFIELDS, mRequestText);
|
||||
}
|
||||
else
|
||||
{
|
||||
setStatus(StatusOtherError);
|
||||
}
|
||||
|
||||
curlEasyRequest_w->finalizeRequest(mURI);
|
||||
}
|
||||
if (mStatus == LLXMLRPCTransaction::StatusNotStarted) // It could be LLXMLRPCTransaction::StatusOtherError.
|
||||
{
|
||||
llwarns << "mCurlRequest is invalid." << llendl ;
|
||||
|
||||
delete mCurlRequest ;
|
||||
mCurlRequest = NULL ;
|
||||
return ;
|
||||
mCurlEasyRequestStateMachinePtr->run(boost::bind(&LLXMLRPCTransaction::Impl::curlEasyRequestCallback, this, _1));
|
||||
setStatus(LLXMLRPCTransaction::StatusStarted);
|
||||
}
|
||||
|
||||
|
||||
LLProxy::getInstance()->applyProxySettings(mCurlRequest);
|
||||
|
||||
// mCurlRequest->setopt(CURLOPT_VERBOSE, 1); // usefull for debugging
|
||||
mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1);
|
||||
mCurlRequest->setWriteCallback(&curlDownloadCallback, (void*)this);
|
||||
BOOL vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert");
|
||||
mCurlRequest->setopt(CURLOPT_SSL_VERIFYPEER, vefifySSLCert);
|
||||
mCurlRequest->setopt(CURLOPT_SSL_VERIFYHOST, vefifySSLCert ? 2 : 0);
|
||||
// Be a little impatient about establishing connections.
|
||||
mCurlRequest->setopt(CURLOPT_CONNECTTIMEOUT, 40L);
|
||||
|
||||
/* Setting the DNS cache timeout to -1 disables it completely.
|
||||
This might help with bug #503 */
|
||||
mCurlRequest->setopt(CURLOPT_DNS_CACHE_TIMEOUT, -1);
|
||||
|
||||
mCurlRequest->slist_append("Content-Type: text/xml");
|
||||
|
||||
if (useGzip)
|
||||
{
|
||||
mCurlRequest->setoptString(CURLOPT_ENCODING, "");
|
||||
}
|
||||
|
||||
mRequestText = XMLRPC_REQUEST_ToXML(request, &mRequestTextSize);
|
||||
if (mRequestText)
|
||||
{
|
||||
mCurlRequest->setoptString(CURLOPT_POSTFIELDS, mRequestText);
|
||||
mCurlRequest->setopt(CURLOPT_POSTFIELDSIZE, mRequestTextSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
setStatus(StatusOtherError);
|
||||
}
|
||||
|
||||
mCurlRequest->sendRequest(mURI);
|
||||
}
|
||||
|
||||
|
||||
LLXMLRPCTransaction::Impl::~Impl()
|
||||
{
|
||||
if (mCurlEasyRequestStateMachinePtr && mCurlEasyRequestStateMachinePtr->running())
|
||||
{
|
||||
llwarns << "Calling LLXMLRPCTransaction::Impl::~Impl while mCurlEasyRequestStateMachinePtr is still running" << llendl;
|
||||
mCurlEasyRequestStateMachinePtr->abort();
|
||||
}
|
||||
|
||||
if (mResponse)
|
||||
{
|
||||
XMLRPC_RequestFree(mResponse, 1);
|
||||
@@ -285,119 +297,76 @@ LLXMLRPCTransaction::Impl::~Impl()
|
||||
{
|
||||
XMLRPC_Free(mRequestText);
|
||||
}
|
||||
|
||||
delete mCurlRequest;
|
||||
mCurlRequest = NULL ;
|
||||
}
|
||||
|
||||
bool LLXMLRPCTransaction::Impl::process()
|
||||
bool LLXMLRPCTransaction::Impl::is_finished(void) const
|
||||
{
|
||||
if(!mCurlRequest || !mCurlRequest->isValid())
|
||||
{
|
||||
llwarns << "transaction failed." << llendl ;
|
||||
// Nothing to process anymore. Just wait till the statemachine finished.
|
||||
return mStatus != LLXMLRPCTransaction::StatusNotStarted &&
|
||||
mStatus != LLXMLRPCTransaction::StatusStarted &&
|
||||
mStatus != LLXMLRPCTransaction::StatusDownloading;
|
||||
}
|
||||
|
||||
delete mCurlRequest ;
|
||||
mCurlRequest = NULL ;
|
||||
return true ; //failed, quit.
|
||||
void LLXMLRPCTransaction::Impl::curlEasyRequestCallback(bool success)
|
||||
{
|
||||
llassert(mStatus == LLXMLRPCTransaction::StatusStarted || mStatus == LLXMLRPCTransaction::StatusDownloading);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
setStatus(LLXMLRPCTransaction::StatusOtherError, "Statemachine failed");
|
||||
return;
|
||||
}
|
||||
|
||||
switch(mStatus)
|
||||
AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequestStateMachinePtr->mCurlEasyRequest);
|
||||
CURLcode result;
|
||||
curlEasyRequest_w->getResult(&result, &mTransferInfo);
|
||||
|
||||
if (result != CURLE_OK)
|
||||
{
|
||||
case LLXMLRPCTransaction::StatusComplete:
|
||||
case LLXMLRPCTransaction::StatusCURLError:
|
||||
case LLXMLRPCTransaction::StatusXMLRPCError:
|
||||
case LLXMLRPCTransaction::StatusOtherError:
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
case LLXMLRPCTransaction::StatusNotStarted:
|
||||
{
|
||||
setStatus(LLXMLRPCTransaction::StatusStarted);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
// continue onward
|
||||
}
|
||||
setCurlStatus(result);
|
||||
llwarns << "LLXMLRPCTransaction CURL error "
|
||||
<< mCurlCode << ": " << curlEasyRequest_w->getErrorString() << llendl;
|
||||
llwarns << "LLXMLRPCTransaction request URI: "
|
||||
<< mURI << llendl;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//const F32 MAX_PROCESSING_TIME = 0.05f;
|
||||
//LLTimer timer;
|
||||
setStatus(LLXMLRPCTransaction::StatusComplete);
|
||||
|
||||
mCurlRequest->wait();
|
||||
mResponse = XMLRPC_REQUEST_FromXML(
|
||||
mResponseText.data(), mResponseText.size(), NULL);
|
||||
|
||||
/*while (mCurlRequest->perform() > 0)
|
||||
bool hasError = false;
|
||||
bool hasFault = false;
|
||||
int faultCode = 0;
|
||||
std::string faultString;
|
||||
|
||||
LLXMLRPCValue error(XMLRPC_RequestGetError(mResponse));
|
||||
if (error.isValid())
|
||||
{
|
||||
if (timer.getElapsedTimeF32() >= MAX_PROCESSING_TIME)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}*/
|
||||
|
||||
while(1)
|
||||
{
|
||||
CURLcode result;
|
||||
bool newmsg = mCurlRequest->getResult(&result, &mTransferInfo);
|
||||
if (newmsg)
|
||||
{
|
||||
if (result != CURLE_OK)
|
||||
{
|
||||
setCurlStatus(result);
|
||||
llwarns << "LLXMLRPCTransaction CURL error "
|
||||
<< mCurlCode << ": " << mCurlRequest->getErrorString() << llendl;
|
||||
llwarns << "LLXMLRPCTransaction request URI: "
|
||||
<< mURI << llendl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
setStatus(LLXMLRPCTransaction::StatusComplete);
|
||||
|
||||
mResponse = XMLRPC_REQUEST_FromXML(
|
||||
mResponseText.data(), mResponseText.size(), NULL);
|
||||
|
||||
bool hasError = false;
|
||||
bool hasFault = false;
|
||||
int faultCode = 0;
|
||||
std::string faultString;
|
||||
|
||||
LLXMLRPCValue error(XMLRPC_RequestGetError(mResponse));
|
||||
if (error.isValid())
|
||||
{
|
||||
hasError = true;
|
||||
faultCode = error["faultCode"].asInt();
|
||||
faultString = error["faultString"].asString();
|
||||
}
|
||||
else if (XMLRPC_ResponseIsFault(mResponse))
|
||||
{
|
||||
hasFault = true;
|
||||
faultCode = XMLRPC_GetResponseFaultCode(mResponse);
|
||||
faultString = XMLRPC_GetResponseFaultString(mResponse);
|
||||
}
|
||||
|
||||
if (hasError || hasFault)
|
||||
{
|
||||
setStatus(LLXMLRPCTransaction::StatusXMLRPCError);
|
||||
|
||||
llwarns << "LLXMLRPCTransaction XMLRPC "
|
||||
<< (hasError ? "error " : "fault ")
|
||||
<< faultCode << ": "
|
||||
<< faultString << llendl;
|
||||
llwarns << "LLXMLRPCTransaction request URI: "
|
||||
<< mURI << llendl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
break; // done
|
||||
}
|
||||
hasError = true;
|
||||
faultCode = error["faultCode"].asInt();
|
||||
faultString = error["faultString"].asString();
|
||||
}
|
||||
else if (XMLRPC_ResponseIsFault(mResponse))
|
||||
{
|
||||
hasFault = true;
|
||||
faultCode = XMLRPC_GetResponseFaultCode(mResponse);
|
||||
faultString = XMLRPC_GetResponseFaultString(mResponse);
|
||||
}
|
||||
|
||||
if (hasError || hasFault)
|
||||
{
|
||||
setStatus(LLXMLRPCTransaction::StatusXMLRPCError);
|
||||
|
||||
llwarns << "LLXMLRPCTransaction XMLRPC "
|
||||
<< (hasError ? "error " : "fault ")
|
||||
<< faultCode << ": "
|
||||
<< faultString << llendl;
|
||||
llwarns << "LLXMLRPCTransaction request URI: "
|
||||
<< mURI << llendl;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLXMLRPCTransaction::Impl::setStatus(Status status,
|
||||
@@ -489,6 +458,8 @@ void LLXMLRPCTransaction::Impl::setCurlStatus(CURLcode code)
|
||||
size_t LLXMLRPCTransaction::Impl::curlDownloadCallback(
|
||||
char* data, size_t size, size_t nmemb, void* user_data)
|
||||
{
|
||||
DoutEntering(dc::curl, "LLXMLRPCTransaction::Impl::curlDownloadCallback(\"" << buf2str(data, size * nmemb) << "\", " << size << ", " << nmemb << ", " << user_data << ")");
|
||||
|
||||
Impl& impl(*(Impl*)user_data);
|
||||
|
||||
size_t n = size * nmemb;
|
||||
@@ -523,7 +494,7 @@ LLXMLRPCTransaction::~LLXMLRPCTransaction()
|
||||
|
||||
bool LLXMLRPCTransaction::process()
|
||||
{
|
||||
return impl.process();
|
||||
return impl.is_finished();
|
||||
}
|
||||
|
||||
LLXMLRPCTransaction::Status LLXMLRPCTransaction::status(int* curlCode)
|
||||
|
||||
Reference in New Issue
Block a user