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:
Aleric Inglewood
2012-06-27 12:57:07 +02:00
parent 221e3908b9
commit 69ca6cd5b2
47 changed files with 4173 additions and 2502 deletions

View File

@@ -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)