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:
@@ -151,6 +151,7 @@ set(viewer_SOURCE_FILES
|
||||
llconfirmationmanager.cpp
|
||||
llconsole.cpp
|
||||
llcontainerview.cpp
|
||||
llcurlrequest.cpp
|
||||
llcurrencyuimanager.cpp
|
||||
llcylinder.cpp
|
||||
lldebugmessagebox.cpp
|
||||
@@ -646,6 +647,7 @@ set(viewer_HEADER_FILES
|
||||
llconfirmationmanager.h
|
||||
llconsole.h
|
||||
llcontainerview.h
|
||||
llcurlrequest.h
|
||||
llcurrencyuimanager.h
|
||||
llcylinder.h
|
||||
lldebugmessagebox.h
|
||||
|
||||
@@ -4016,17 +4016,6 @@
|
||||
<key>Value</key>
|
||||
<real>120.0</real>
|
||||
</map>
|
||||
<key>CurlUseMultipleThreads</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Use background threads for executing curl_multi_perform (requires restart)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>Cursor3D</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
||||
@@ -255,7 +255,16 @@ static void request(const std::string &url,
|
||||
}
|
||||
LLPumpIO::chain_t chain;
|
||||
|
||||
LLURLRequest *req = new LLURLRequest(method, url);
|
||||
LLURLRequest *req;
|
||||
try
|
||||
{
|
||||
req = new LLURLRequest(method, url);
|
||||
}
|
||||
catch(AICurlNoEasyHandle const& error)
|
||||
{
|
||||
llwarns << "Failed to create LLURLRequest: " << error.what() << llendl;
|
||||
return;
|
||||
}
|
||||
req->setSSLVerifyCallback(LLHTTPClient::getCertVerifyCallback(), (void *)req);
|
||||
|
||||
/*
|
||||
@@ -324,10 +333,11 @@ int HippoRestRequest::getBlocking(const std::string &url, std::string *result)
|
||||
|
||||
char curlErrorBuffer[CURL_ERROR_SIZE];
|
||||
CURL* curlp = curl_easy_init();
|
||||
llassert_always(curlp);
|
||||
|
||||
curl_easy_setopt(curlp, CURLOPT_NOSIGNAL, 1); // don't use SIGALRM for timeouts
|
||||
curl_easy_setopt(curlp, CURLOPT_TIMEOUT, 5); // seconds
|
||||
curl_easy_setopt(curlp, CURLOPT_CAINFO, gDirUtilp->getCAFile().c_str());
|
||||
curl_easy_setopt(curlp, CURLOPT_CAINFO, gDirUtilp->getCAFile().c_str());
|
||||
|
||||
curl_easy_setopt(curlp, CURLOPT_WRITEFUNCTION, curlWrite);
|
||||
curl_easy_setopt(curlp, CURLOPT_WRITEDATA, result);
|
||||
@@ -337,7 +347,7 @@ int HippoRestRequest::getBlocking(const std::string &url, std::string *result)
|
||||
|
||||
*result = "";
|
||||
S32 curlSuccess = curl_easy_perform(curlp);
|
||||
S32 httpStatus = 499;
|
||||
long httpStatus = 499L; // curl_easy_getinfo demands pointer to long.
|
||||
curl_easy_getinfo(curlp, CURLINFO_RESPONSE_CODE, &httpStatus);
|
||||
|
||||
if (curlSuccess != 0) {
|
||||
|
||||
@@ -2370,7 +2370,7 @@ bool LLAgent::sendMaturityPreferenceToServer(int preferredMaturity)
|
||||
body["access_prefs"] = access_prefs;
|
||||
llinfos << "Sending access prefs update to " << (access_prefs["max"].asString()) << " via capability to: "
|
||||
<< url << llendl;
|
||||
LLHTTPClient::post(url, body, new LLHTTPClient::Responder()); // Ignore response
|
||||
LLHTTPClient::post(url, body, new LLHTTPClient::ResponderIgnore); // Ignore response
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -61,7 +61,7 @@ bool LLAgentLanguage::update()
|
||||
body["language"] = language;
|
||||
body["language_is_public"] = gSavedSettings.getBOOL("LanguageIsPublic");
|
||||
|
||||
LLHTTPClient::post(url, body, new LLHTTPClient::Responder);
|
||||
LLHTTPClient::post(url, body, new LLHTTPClient::ResponderIgnore);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -611,6 +611,9 @@ bool LLAppViewer::init()
|
||||
|
||||
initLogging();
|
||||
|
||||
// Curl must be initialized before any thread is running.
|
||||
AICurlInterface::initCurl();
|
||||
|
||||
// Logging is initialized. Now it's safe to start the error thread.
|
||||
startErrorThread();
|
||||
|
||||
@@ -635,12 +638,6 @@ bool LLAppViewer::init()
|
||||
LLPrivateMemoryPoolManager::initClass((BOOL)gSavedSettings.getBOOL("MemoryPrivatePoolEnabled"), (U32)gSavedSettings.getU32("MemoryPrivatePoolSize")) ;
|
||||
|
||||
mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling"));
|
||||
// *NOTE:Mani - LLCurl::initClass is not thread safe.
|
||||
// Called before threads are created.
|
||||
LLCurl::initClass(gSavedSettings.getF32("CurlRequestTimeOut"),
|
||||
gSavedSettings.getS32("CurlMaximumNumberOfHandles"),
|
||||
gSavedSettings.getBOOL("CurlUseMultipleThreads"));
|
||||
LL_INFOS("InitInfo") << "LLCurl initialized." << LL_ENDL ;
|
||||
|
||||
initThreads();
|
||||
LL_INFOS("InitInfo") << "Threads initialized." << LL_ENDL ;
|
||||
@@ -1767,10 +1764,9 @@ bool LLAppViewer::cleanup()
|
||||
end_messaging_system();
|
||||
llinfos << "Message system deleted." << llendflush;
|
||||
|
||||
LLUserAuth::getInstance()->reset(); //reset before LLCurl::cleanupClass, else LLCURL::sHandleMutex == NULL
|
||||
// *NOTE:Mani - The following call is not thread safe.
|
||||
LLCurl::cleanupClass();
|
||||
llinfos << "LLCurl cleaned up." << llendflush;
|
||||
LLUserAuth::getInstance()->reset(); // Reset before AICurlInterface::cleanupCurl, else LLCURL::sHandleMutex == NULL
|
||||
LLApp::stopErrorThread(); // The following call is not thread-safe. Have to stop all threads.
|
||||
AICurlInterface::cleanupCurl();
|
||||
|
||||
// If we're exiting to launch an URL, do that here so the screen
|
||||
// is at the right resolution before we launch IE.
|
||||
@@ -1839,6 +1835,8 @@ bool LLAppViewer::initThreads()
|
||||
LLWatchdog::getInstance()->init(watchdog_killer_callback);
|
||||
}
|
||||
|
||||
AICurlInterface::startCurlThread();
|
||||
|
||||
LLImage::initClass();
|
||||
|
||||
LLVFSThread::initClass(enable_threads && false);
|
||||
|
||||
147
indra/newview/llcurlrequest.cpp
Normal file
147
indra/newview/llcurlrequest.cpp
Normal file
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* @file llcurlrequest.cpp
|
||||
* @brief Implementation of Request.
|
||||
*
|
||||
* Copyright (c) 2012, Aleric Inglewood.
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution.
|
||||
*
|
||||
* CHANGELOG
|
||||
* and additional copyright holders.
|
||||
*
|
||||
* 17/03/2012
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*
|
||||
* 20/03/2012
|
||||
* Added copyright notice for Linden Lab for those parts that were
|
||||
* copied or derived from llcurl.cpp. The code of those parts are
|
||||
* already in their own llcurl.cpp, so they do not ever need to
|
||||
* even look at this file; the reason I added the copyright notice
|
||||
* is to make clear that I am not the author of 100% of this code
|
||||
* and hence I cannot change the license of it.
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llsdserialize.h"
|
||||
#include "llcurlrequest.h"
|
||||
#include "statemachine/aicurleasyrequeststatemachine.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// class Request
|
||||
//
|
||||
|
||||
namespace AICurlInterface {
|
||||
|
||||
bool Request::get(std::string const& url, ResponderPtr responder)
|
||||
{
|
||||
return getByteRange(url, headers_t(), 0, -1, responder);
|
||||
}
|
||||
|
||||
bool Request::getByteRange(std::string const& url, headers_t const& headers, S32 offset, S32 length, ResponderPtr responder)
|
||||
{
|
||||
DoutEntering(dc::curl, "Request::getByteRange(" << url << ", ...)");
|
||||
|
||||
// This might throw AICurlNoEasyHandle.
|
||||
AICurlEasyRequestStateMachine* buffered_easy_request = new AICurlEasyRequestStateMachine(true);
|
||||
|
||||
{
|
||||
AICurlEasyRequest_wat buffered_easy_request_w(*buffered_easy_request->mCurlEasyRequest);
|
||||
|
||||
AICurlResponderBuffer_wat(*buffered_easy_request->mCurlEasyRequest)->prepRequest(buffered_easy_request_w, headers, responder);
|
||||
|
||||
buffered_easy_request_w->setopt(CURLOPT_HTTPGET, 1);
|
||||
if (length > 0)
|
||||
{
|
||||
std::string range = llformat("Range: bytes=%d-%d", offset, offset + length - 1);
|
||||
buffered_easy_request_w->addHeader(range.c_str());
|
||||
}
|
||||
|
||||
buffered_easy_request_w->finalizeRequest(url);
|
||||
}
|
||||
|
||||
buffered_easy_request->run();
|
||||
|
||||
return true; // We throw in case of problems.
|
||||
}
|
||||
|
||||
bool Request::post(std::string const& url, headers_t const& headers, std::string const& data, ResponderPtr responder, S32 time_out)
|
||||
{
|
||||
DoutEntering(dc::curl, "Request::post(" << url << ", ...)");
|
||||
|
||||
// This might throw AICurlNoEasyHandle.
|
||||
AICurlEasyRequestStateMachine* buffered_easy_request = new AICurlEasyRequestStateMachine(true);
|
||||
|
||||
{
|
||||
AICurlEasyRequest_wat buffered_easy_request_w(*buffered_easy_request->mCurlEasyRequest);
|
||||
AICurlResponderBuffer_wat buffer_w(*buffered_easy_request->mCurlEasyRequest);
|
||||
|
||||
buffer_w->prepRequest(buffered_easy_request_w, headers, responder);
|
||||
|
||||
buffer_w->getInput().write(data.data(), data.size());
|
||||
S32 bytes = buffer_w->getInput().str().length();
|
||||
buffered_easy_request_w->setPost(NULL, bytes);
|
||||
buffered_easy_request_w->addHeader("Content-Type: application/octet-stream");
|
||||
buffered_easy_request_w->finalizeRequest(url);
|
||||
|
||||
lldebugs << "POSTING: " << bytes << " bytes." << llendl;
|
||||
}
|
||||
|
||||
buffered_easy_request->run();
|
||||
|
||||
return true; // We throw in case of problems.
|
||||
}
|
||||
|
||||
bool Request::post(std::string const& url, headers_t const& headers, LLSD const& data, ResponderPtr responder, S32 time_out)
|
||||
{
|
||||
DoutEntering(dc::curl, "Request::post(" << url << ", ...)");
|
||||
|
||||
// This might throw AICurlNoEasyHandle.
|
||||
AICurlEasyRequestStateMachine* buffered_easy_request = new AICurlEasyRequestStateMachine(true);
|
||||
|
||||
{
|
||||
AICurlEasyRequest_wat buffered_easy_request_w(*buffered_easy_request->mCurlEasyRequest);
|
||||
AICurlResponderBuffer_wat buffer_w(*buffered_easy_request->mCurlEasyRequest);
|
||||
|
||||
buffer_w->prepRequest(buffered_easy_request_w, headers, responder);
|
||||
|
||||
LLSDSerialize::toXML(data, buffer_w->getInput());
|
||||
S32 bytes = buffer_w->getInput().str().length();
|
||||
buffered_easy_request_w->setPost(NULL, bytes);
|
||||
buffered_easy_request_w->addHeader("Content-Type: application/llsd+xml");
|
||||
buffered_easy_request_w->finalizeRequest(url);
|
||||
|
||||
lldebugs << "POSTING: " << bytes << " bytes." << llendl;
|
||||
}
|
||||
|
||||
buffered_easy_request->run();
|
||||
|
||||
return true; // We throw in case of problems.
|
||||
}
|
||||
|
||||
S32 Request::process(void)
|
||||
{
|
||||
//FIXME: needs implementation
|
||||
//DoutEntering(dc::warning, "Request::process()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace AICurlInterface
|
||||
//==================================================================================
|
||||
|
||||
59
indra/newview/llcurlrequest.h
Normal file
59
indra/newview/llcurlrequest.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* @file llcurlrequest.h
|
||||
* @brief Declaration of class Request
|
||||
*
|
||||
* Copyright (c) 2012, Aleric Inglewood.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution.
|
||||
*
|
||||
* CHANGELOG
|
||||
* and additional copyright holders.
|
||||
*
|
||||
* 17/03/2012
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
#ifndef AICURLREQUEST_H
|
||||
#define AICURLREQUEST_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
|
||||
// Things defined in this namespace are called from elsewhere in the viewer code.
|
||||
namespace AICurlInterface {
|
||||
|
||||
// Forward declaration.
|
||||
class Responder;
|
||||
typedef boost::intrusive_ptr<Responder> ResponderPtr;
|
||||
|
||||
class Request {
|
||||
public:
|
||||
typedef std::vector<std::string> headers_t;
|
||||
|
||||
bool get(std::string const& url, ResponderPtr responder);
|
||||
bool getByteRange(std::string const& url, headers_t const& headers, S32 offset, S32 length, ResponderPtr responder);
|
||||
bool post(std::string const& url, headers_t const& headers, std::string const& data, ResponderPtr responder, S32 time_out = 0);
|
||||
bool post(std::string const& url, headers_t const& headers, LLSD const& data, ResponderPtr responder, S32 time_out = 0);
|
||||
|
||||
S32 process(void);
|
||||
};
|
||||
|
||||
} // namespace AICurlInterface
|
||||
|
||||
#endif
|
||||
@@ -760,7 +760,7 @@ BOOL LLPanelRegionGeneralInfo::sendUpdate()
|
||||
body["allow_parcel_changes"] = childGetValue("allow_parcel_changes_check");
|
||||
body["block_parcel_search"] = childGetValue("block_parcel_search_check");
|
||||
|
||||
LLHTTPClient::post(url, body, new LLHTTPClient::Responder());
|
||||
LLHTTPClient::post(url, body, new LLHTTPClient::ResponderIgnore);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
#include "llappviewer.h"
|
||||
#include "llbufferstream.h"
|
||||
#include "llcallbacklist.h"
|
||||
#include "llcurl.h"
|
||||
#include "llcurlrequest.h"
|
||||
#include "lldatapacker.h"
|
||||
#include "llfasttimer.h"
|
||||
#if MESH_IMPORT
|
||||
@@ -465,7 +465,6 @@ public:
|
||||
LLMeshRepoThread::LLMeshRepoThread()
|
||||
: LLThread("mesh repo")
|
||||
{
|
||||
mWaiting = false;
|
||||
mMutex = new LLMutex();
|
||||
mHeaderMutex = new LLMutex();
|
||||
mSignal = new LLCondition();
|
||||
@@ -483,7 +482,7 @@ LLMeshRepoThread::~LLMeshRepoThread()
|
||||
|
||||
void LLMeshRepoThread::run()
|
||||
{
|
||||
mCurlRequest = new LLCurlRequest();
|
||||
mCurlRequest = new AICurlInterface::Request;
|
||||
#if MESH_IMPORT
|
||||
LLCDResult res = LLConvexDecomposition::initThread();
|
||||
if (res != LLCD_OK)
|
||||
@@ -492,13 +491,10 @@ void LLMeshRepoThread::run()
|
||||
}
|
||||
#endif //MESH_IMPORT
|
||||
|
||||
mSignal->lock();
|
||||
while (!LLApp::isQuitting())
|
||||
{
|
||||
mWaiting = true;
|
||||
mSignal->wait();
|
||||
mWaiting = false;
|
||||
|
||||
if (!LLApp::isQuitting())
|
||||
// Left braces in order not to change the indentation.
|
||||
{
|
||||
static U32 count = 0;
|
||||
|
||||
@@ -511,38 +507,53 @@ void LLMeshRepoThread::run()
|
||||
}
|
||||
|
||||
// NOTE: throttling intentionally favors LOD requests over header requests
|
||||
|
||||
|
||||
while (!mLODReqQ.empty() && count < MAX_MESH_REQUESTS_PER_SECOND && sActiveLODRequests < (S32)sMaxConcurrentRequests)
|
||||
{
|
||||
if (mMutex)
|
||||
{
|
||||
mMutex->lock();
|
||||
LODRequest req = mLODReqQ.front();
|
||||
mLODReqQ.pop();
|
||||
LLMeshRepository::sLODProcessing--;
|
||||
mMutex->unlock();
|
||||
if (!fetchMeshLOD(req.mMeshParams, req.mLOD, count))//failed, resubmit
|
||||
try
|
||||
{
|
||||
fetchMeshLOD(req.mMeshParams, req.mLOD, count);
|
||||
}
|
||||
catch(AICurlNoEasyHandle const& error)
|
||||
{
|
||||
llwarns << "fetchMeshLOD() failed: " << error.what() << llendl;
|
||||
mMutex->lock();
|
||||
mLODReqQ.push(req) ;
|
||||
LLMeshRepository::sLODProcessing++;
|
||||
mLODReqQ.push(req);
|
||||
mMutex->unlock();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (!mHeaderReqQ.empty() && count < MAX_MESH_REQUESTS_PER_SECOND && sActiveHeaderRequests < (S32)sMaxConcurrentRequests)
|
||||
{
|
||||
if (mMutex)
|
||||
{
|
||||
mMutex->lock();
|
||||
HeaderRequest req = mHeaderReqQ.front();
|
||||
mHeaderReqQ.pop();
|
||||
mMutex->unlock();
|
||||
if (!fetchMeshHeader(req.mMeshParams, count))//failed, resubmit
|
||||
bool success = false;
|
||||
try
|
||||
{
|
||||
success = fetchMeshHeader(req.mMeshParams, count);
|
||||
}
|
||||
catch(AICurlNoEasyHandle const& error)
|
||||
{
|
||||
llwarns << "fetchMeshHeader() failed: " << error.what() << llendl;
|
||||
}
|
||||
if (!success)
|
||||
{
|
||||
mMutex->lock();
|
||||
mHeaderReqQ.push(req) ;
|
||||
mMutex->unlock();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -552,7 +563,16 @@ void LLMeshRepoThread::run()
|
||||
for (std::set<LLUUID>::iterator iter = mSkinRequests.begin(); iter != mSkinRequests.end(); ++iter)
|
||||
{
|
||||
LLUUID mesh_id = *iter;
|
||||
if (!fetchMeshSkinInfo(mesh_id))
|
||||
bool success = false;
|
||||
try
|
||||
{
|
||||
success = fetchMeshSkinInfo(mesh_id);
|
||||
}
|
||||
catch(AICurlNoEasyHandle const& error)
|
||||
{
|
||||
llwarns << "fetchMeshSkinInfo(" << mesh_id << ") failed: " << error.what() << llendl;
|
||||
}
|
||||
if (!success)
|
||||
{
|
||||
incomplete.insert(mesh_id);
|
||||
}
|
||||
@@ -565,7 +585,16 @@ void LLMeshRepoThread::run()
|
||||
for (std::set<LLUUID>::iterator iter = mDecompositionRequests.begin(); iter != mDecompositionRequests.end(); ++iter)
|
||||
{
|
||||
LLUUID mesh_id = *iter;
|
||||
if (!fetchMeshDecomposition(mesh_id))
|
||||
bool success = false;
|
||||
try
|
||||
{
|
||||
success = fetchMeshDecomposition(mesh_id);
|
||||
}
|
||||
catch(AICurlNoEasyHandle const& error)
|
||||
{
|
||||
llwarns << "fetchMeshDecomposition(" << mesh_id << ") failed: " << error.what() << llendl;
|
||||
}
|
||||
if (!success)
|
||||
{
|
||||
incomplete.insert(mesh_id);
|
||||
}
|
||||
@@ -578,7 +607,16 @@ void LLMeshRepoThread::run()
|
||||
for (std::set<LLUUID>::iterator iter = mPhysicsShapeRequests.begin(); iter != mPhysicsShapeRequests.end(); ++iter)
|
||||
{
|
||||
LLUUID mesh_id = *iter;
|
||||
if (!fetchMeshPhysicsShape(mesh_id))
|
||||
bool success = false;
|
||||
try
|
||||
{
|
||||
success = fetchMeshPhysicsShape(mesh_id);
|
||||
}
|
||||
catch(AICurlNoEasyHandle const& error)
|
||||
{
|
||||
llwarns << "fetchMeshPhysicsShape(" << mesh_id << ") failed: " << error.what() << llendl;
|
||||
}
|
||||
if (!success)
|
||||
{
|
||||
incomplete.insert(mesh_id);
|
||||
}
|
||||
@@ -586,14 +624,11 @@ void LLMeshRepoThread::run()
|
||||
mPhysicsShapeRequests = incomplete;
|
||||
}
|
||||
|
||||
mCurlRequest->process();
|
||||
}
|
||||
|
||||
mSignal->wait();
|
||||
}
|
||||
|
||||
if (mSignal->isLocked())
|
||||
{ //make sure to let go of the mutex associated with the given signal before shutting down
|
||||
mSignal->unlock();
|
||||
}
|
||||
mSignal->unlock();
|
||||
|
||||
#if MESH_IMPORT
|
||||
res = LLConvexDecomposition::quitThread();
|
||||
@@ -681,21 +716,15 @@ std::string LLMeshRepoThread::constructUrl(LLUUID mesh_id)
|
||||
|
||||
bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)
|
||||
{ //protected by mMutex
|
||||
|
||||
if (!mHeaderMutex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
mHeaderMutex->lock();
|
||||
|
||||
if (mMeshHeader.find(mesh_id) == mMeshHeader.end())
|
||||
{ //we have no header info for this mesh, do nothing
|
||||
{
|
||||
// We have no header info for this mesh, try again later.
|
||||
mHeaderMutex->unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret = true ;
|
||||
U32 header_size = mMeshHeaderSize[mesh_id];
|
||||
|
||||
if (header_size > 0)
|
||||
@@ -743,12 +772,10 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)
|
||||
std::string http_url = constructUrl(mesh_id);
|
||||
if (!http_url.empty())
|
||||
{
|
||||
ret = mCurlRequest->getByteRange(http_url, headers, offset, size,
|
||||
new LLMeshSkinInfoResponder(mesh_id, offset, size));
|
||||
if(ret)
|
||||
{
|
||||
LLMeshRepository::sHTTPRequestCount++;
|
||||
}
|
||||
// This might throw AICurlNoEasyHandle.
|
||||
mCurlRequest->getByteRange(http_url, headers, offset, size,
|
||||
new LLMeshSkinInfoResponder(mesh_id, offset, size));
|
||||
LLMeshRepository::sHTTPRequestCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -758,26 +785,22 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)
|
||||
}
|
||||
|
||||
//early out was not hit, effectively fetched
|
||||
return ret;
|
||||
return true;
|
||||
}
|
||||
|
||||
//return false if failed to get header
|
||||
bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)
|
||||
{ //protected by mMutex
|
||||
if (!mHeaderMutex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
mHeaderMutex->lock();
|
||||
|
||||
if (mMeshHeader.find(mesh_id) == mMeshHeader.end())
|
||||
{ //we have no header info for this mesh, do nothing
|
||||
{
|
||||
// We have no header info for this mesh, try again later.
|
||||
mHeaderMutex->unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
U32 header_size = mMeshHeaderSize[mesh_id];
|
||||
bool ret = true ;
|
||||
|
||||
if (header_size > 0)
|
||||
{
|
||||
@@ -824,12 +847,10 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)
|
||||
std::string http_url = constructUrl(mesh_id);
|
||||
if (!http_url.empty())
|
||||
{
|
||||
ret = mCurlRequest->getByteRange(http_url, headers, offset, size,
|
||||
new LLMeshDecompositionResponder(mesh_id, offset, size));
|
||||
if(ret)
|
||||
{
|
||||
LLMeshRepository::sHTTPRequestCount++;
|
||||
}
|
||||
// This might throw AICurlNoEasyHandle.
|
||||
mCurlRequest->getByteRange(http_url, headers, offset, size,
|
||||
new LLMeshDecompositionResponder(mesh_id, offset, size));
|
||||
LLMeshRepository::sHTTPRequestCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -839,26 +860,22 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)
|
||||
}
|
||||
|
||||
//early out was not hit, effectively fetched
|
||||
return ret;
|
||||
return true;
|
||||
}
|
||||
|
||||
//return false if failed to get header
|
||||
bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)
|
||||
{ //protected by mMutex
|
||||
if (!mHeaderMutex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
mHeaderMutex->lock();
|
||||
|
||||
if (mMeshHeader.find(mesh_id) == mMeshHeader.end())
|
||||
{ //we have no header info for this mesh, do nothing
|
||||
{
|
||||
// We have no header info for this mesh, retry later.
|
||||
mHeaderMutex->unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
U32 header_size = mMeshHeaderSize[mesh_id];
|
||||
bool ret = true ;
|
||||
|
||||
if (header_size > 0)
|
||||
{
|
||||
@@ -905,13 +922,10 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)
|
||||
std::string http_url = constructUrl(mesh_id);
|
||||
if (!http_url.empty())
|
||||
{
|
||||
ret = mCurlRequest->getByteRange(http_url, headers, offset, size,
|
||||
new LLMeshPhysicsShapeResponder(mesh_id, offset, size));
|
||||
|
||||
if(ret)
|
||||
{
|
||||
LLMeshRepository::sHTTPRequestCount++;
|
||||
}
|
||||
// This might throw AICurlNoEasyHandle.
|
||||
mCurlRequest->getByteRange(http_url, headers, offset, size,
|
||||
new LLMeshPhysicsShapeResponder(mesh_id, offset, size));
|
||||
LLMeshRepository::sHTTPRequestCount++;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -925,7 +939,7 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)
|
||||
}
|
||||
|
||||
//early out was not hit, effectively fetched
|
||||
return ret;
|
||||
return true;
|
||||
}
|
||||
|
||||
//return false if failed to get header
|
||||
@@ -944,14 +958,14 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, U32& c
|
||||
LLMeshRepository::sCacheBytesRead += bytes;
|
||||
file.read(buffer, bytes);
|
||||
if (headerReceived(mesh_params, buffer, bytes))
|
||||
{ //did not do an HTTP request, return false
|
||||
{
|
||||
// Already have header, no need to retry.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//either cache entry doesn't exist or is corrupt, request header from simulator
|
||||
bool retval = true ;
|
||||
std::vector<std::string> headers;
|
||||
headers.push_back("Accept: application/octet-stream");
|
||||
|
||||
@@ -961,29 +975,19 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, U32& c
|
||||
//grab first 4KB if we're going to bother with a fetch. Cache will prevent future fetches if a full mesh fits
|
||||
//within the first 4KB
|
||||
//NOTE -- this will break of headers ever exceed 4KB
|
||||
retval = mCurlRequest->getByteRange(http_url, headers, 0, 4096, new LLMeshHeaderResponder(mesh_params));
|
||||
if(retval)
|
||||
{
|
||||
LLMeshRepository::sHTTPRequestCount++;
|
||||
}
|
||||
// This might throw AICurlNoEasyHandle.
|
||||
mCurlRequest->getByteRange(http_url, headers, 0, 4096, new LLMeshHeaderResponder(mesh_params));
|
||||
LLMeshRepository::sHTTPRequestCount++;
|
||||
count++;
|
||||
}
|
||||
|
||||
return retval;
|
||||
return true;
|
||||
}
|
||||
|
||||
//return false if failed to get mesh lod.
|
||||
bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, U32& count)
|
||||
void LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, U32& count)
|
||||
{ //protected by mMutex
|
||||
if (!mHeaderMutex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
mHeaderMutex->lock();
|
||||
|
||||
bool retval = true;
|
||||
|
||||
LLUUID mesh_id = mesh_params.getSculptID();
|
||||
|
||||
U32 header_size = mMeshHeaderSize[mesh_id];
|
||||
@@ -1019,7 +1023,7 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod,
|
||||
if (lodReceived(mesh_params, lod, buffer, size))
|
||||
{
|
||||
delete[] buffer;
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1033,13 +1037,10 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod,
|
||||
std::string http_url = constructUrl(mesh_id);
|
||||
if (!http_url.empty())
|
||||
{
|
||||
retval = mCurlRequest->getByteRange(constructUrl(mesh_id), headers, offset, size,
|
||||
// This might throw AICurlNoEasyHandle.
|
||||
mCurlRequest->getByteRange(constructUrl(mesh_id), headers, offset, size,
|
||||
new LLMeshLODResponder(mesh_params, lod, offset, size));
|
||||
|
||||
if(retval)
|
||||
{
|
||||
LLMeshRepository::sHTTPRequestCount++;
|
||||
}
|
||||
LLMeshRepository::sHTTPRequestCount++;
|
||||
count++;
|
||||
}
|
||||
else
|
||||
@@ -1056,8 +1057,6 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod,
|
||||
{
|
||||
mHeaderMutex->unlock();
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* data, S32 data_size)
|
||||
@@ -1102,7 +1101,7 @@ bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* dat
|
||||
LLMutexLock lock(mHeaderMutex);
|
||||
mMeshHeaderSize[mesh_id] = header_size;
|
||||
mMeshHeader[mesh_id] = header;
|
||||
}
|
||||
}
|
||||
|
||||
//check for pending requests
|
||||
pending_lod_map::iterator iter = mPendingLOD.find(mesh_params);
|
||||
@@ -1599,7 +1598,7 @@ void LLMeshUploadThread::generateHulls()
|
||||
|
||||
void LLMeshUploadThread::doWholeModelUpload()
|
||||
{
|
||||
mCurlRequest = new LLCurlRequest();
|
||||
mCurlRequest = new AICurlInterface::Request();
|
||||
|
||||
if (mWholeModelUploadURL.empty())
|
||||
{
|
||||
@@ -1614,6 +1613,7 @@ void LLMeshUploadThread::doWholeModelUpload()
|
||||
LLSD body = full_model_data["asset_resources"];
|
||||
dump_llsd_to_file(body,make_dump_name("whole_model_body_",dump_num));
|
||||
LLCurlRequest::headers_t headers;
|
||||
//FIXME: this might throw AICurlNoEasyHandle
|
||||
mCurlRequest->post(mWholeModelUploadURL, headers, body,
|
||||
new LLWholeModelUploadResponder(this, full_model_data, mUploadObserverHandle), mMeshUploadTimeOut);
|
||||
do
|
||||
@@ -1635,7 +1635,7 @@ void LLMeshUploadThread::requestWholeModelFee()
|
||||
{
|
||||
dump_num++;
|
||||
|
||||
mCurlRequest = new LLCurlRequest();
|
||||
mCurlRequest = new AICurlInterface::Request;
|
||||
|
||||
generateHulls();
|
||||
|
||||
@@ -1645,6 +1645,7 @@ void LLMeshUploadThread::requestWholeModelFee()
|
||||
|
||||
mPendingUploads++;
|
||||
LLCurlRequest::headers_t headers;
|
||||
//FIXME: this might throw AICurlNoEasyHandle
|
||||
mCurlRequest->post(mWholeModelFeeCapability, headers, model_data,
|
||||
new LLWholeModelFeeResponder(this,model_data, mFeeObserverHandle), mMeshUploadTimeOut);
|
||||
|
||||
@@ -1665,11 +1666,6 @@ void LLMeshUploadThread::requestWholeModelFee()
|
||||
|
||||
void LLMeshRepoThread::notifyLoadedMeshes()
|
||||
{//called via gMeshRepo.notifyLoadedMeshes(). mMutex already locked
|
||||
if (!mMutex)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (!mLoadedQ.empty())
|
||||
{
|
||||
mMutex->lock();
|
||||
@@ -2373,17 +2369,17 @@ void LLMeshRepository::notifyLoadedMeshes()
|
||||
|
||||
mInventoryQ.pop();
|
||||
}
|
||||
}
|
||||
|
||||
#endif //MESH_IMPORT
|
||||
|
||||
//call completed callbacks on finished decompositions
|
||||
mDecompThread->notifyCompleted();
|
||||
|
||||
if (!mThread->mWaiting)
|
||||
{ //curl thread is churning, wait for it to go idle
|
||||
if (!mThread->mSignal->tryLock())
|
||||
{
|
||||
// Curl thread is churning, wait for it to go idle.
|
||||
return;
|
||||
}
|
||||
mThread->mSignal->unlock();
|
||||
|
||||
static std::string region_name("never name a region this");
|
||||
|
||||
@@ -3329,6 +3325,7 @@ void LLPhysicsDecomp::run()
|
||||
mStageID[stages[i].mName] = i;
|
||||
}
|
||||
|
||||
mSignal->lock();
|
||||
while (!mQuitting)
|
||||
{
|
||||
mSignal->wait();
|
||||
@@ -3357,14 +3354,10 @@ void LLPhysicsDecomp::run()
|
||||
}
|
||||
}
|
||||
}
|
||||
mSignal->unlock();
|
||||
|
||||
decomp->quitThread();
|
||||
|
||||
if (mSignal->isLocked())
|
||||
{ //let go of mSignal's associated mutex
|
||||
mSignal->unlock();
|
||||
}
|
||||
|
||||
mDone = true;
|
||||
#endif //MESH_IMPORT
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "lluuid.h"
|
||||
#include "llviewertexture.h"
|
||||
#include "llvolume.h"
|
||||
#include "llcurlrequest.h"
|
||||
|
||||
#if MESH_IMPORT
|
||||
#define LLCONVEXDECOMPINTER_STATIC 1
|
||||
@@ -67,7 +68,6 @@ struct LLCDHull
|
||||
|
||||
class LLVOVolume;
|
||||
class LLMeshResponder;
|
||||
class LLCurlRequest;
|
||||
class LLMutex;
|
||||
class LLCondition;
|
||||
class LLVFS;
|
||||
@@ -246,13 +246,11 @@ public:
|
||||
static S32 sActiveLODRequests;
|
||||
static U32 sMaxConcurrentRequests;
|
||||
|
||||
LLCurlRequest* mCurlRequest;
|
||||
AICurlInterface::Request* mCurlRequest;
|
||||
LLMutex* mMutex;
|
||||
LLMutex* mHeaderMutex;
|
||||
LLCondition* mSignal;
|
||||
|
||||
bool mWaiting;
|
||||
|
||||
//map of known mesh headers
|
||||
typedef std::map<LLUUID, LLSD> mesh_header_map;
|
||||
mesh_header_map mMeshHeader;
|
||||
@@ -351,7 +349,7 @@ public:
|
||||
|
||||
void loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
|
||||
bool fetchMeshHeader(const LLVolumeParams& mesh_params, U32& count);
|
||||
bool fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, U32& count);
|
||||
void fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, U32& count);
|
||||
bool headerReceived(const LLVolumeParams& mesh_params, U8* data, S32 data_size);
|
||||
bool lodReceived(const LLVolumeParams& mesh_params, S32 lod, U8* data, S32 data_size);
|
||||
bool skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 data_size);
|
||||
|
||||
@@ -999,7 +999,7 @@ void LLPanelClassified::sendClassifiedClickMessage(const std::string& type)
|
||||
|
||||
std::string url = gAgent.getRegion()->getCapability("SearchStatTracking");
|
||||
llinfos << "LLPanelClassified::sendClassifiedClickMessage via capability" << llendl;
|
||||
LLHTTPClient::post(url, body, new LLHTTPClient::Responder());
|
||||
LLHTTPClient::post(url, body, new LLHTTPClient::ResponderIgnore);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -3589,6 +3589,7 @@ std::string LLStartUp::startupStateToString(EStartupState state)
|
||||
#define RTNENUM(E) case E: return #E
|
||||
switch(state){
|
||||
RTNENUM( STATE_FIRST );
|
||||
RTNENUM( STATE_BROWSER_INIT );
|
||||
RTNENUM( STATE_LOGIN_SHOW );
|
||||
RTNENUM( STATE_LOGIN_WAIT );
|
||||
RTNENUM( STATE_LOGIN_CLEANUP );
|
||||
@@ -3596,10 +3597,13 @@ std::string LLStartUp::startupStateToString(EStartupState state)
|
||||
RTNENUM( STATE_UPDATE_CHECK );
|
||||
RTNENUM( STATE_LOGIN_AUTH_INIT );
|
||||
RTNENUM( STATE_LOGIN_AUTHENTICATE );
|
||||
RTNENUM( STATE_WAIT_LEGACY_LOGIN );
|
||||
RTNENUM( STATE_XMLRPC_LEGACY_LOGIN );
|
||||
RTNENUM( STATE_LOGIN_NO_DATA_YET );
|
||||
RTNENUM( STATE_LOGIN_DOWNLOADING );
|
||||
RTNENUM( STATE_LOGIN_PROCESS_RESPONSE );
|
||||
RTNENUM( STATE_WORLD_INIT );
|
||||
RTNENUM( STATE_MULTIMEDIA_INIT );
|
||||
RTNENUM( STATE_FONT_INIT );
|
||||
RTNENUM( STATE_SEED_GRANTED_WAIT );
|
||||
RTNENUM( STATE_SEED_CAP_GRANTED );
|
||||
@@ -3612,10 +3616,10 @@ std::string LLStartUp::startupStateToString(EStartupState state)
|
||||
RTNENUM( STATE_WEARABLES_WAIT );
|
||||
RTNENUM( STATE_CLEANUP );
|
||||
RTNENUM( STATE_STARTED );
|
||||
default:
|
||||
return llformat("(state #%d)", state);
|
||||
}
|
||||
#undef RTNENUM
|
||||
// Never reached.
|
||||
return llformat("(state #%d)", state);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1319,8 +1319,15 @@ bool LLTextureFetchWorker::doWork(S32 param)
|
||||
// Will call callbackHttpGet when curl request completes
|
||||
std::vector<std::string> headers;
|
||||
headers.push_back("Accept: image/x-j2c");
|
||||
res = mFetcher->mCurlGetRequest->getByteRange(mUrl, headers, offset, mRequestedSize,
|
||||
new HTTPGetResponder(mFetcher, mID, LLTimer::getTotalTime(), mRequestedSize, offset, true));
|
||||
try
|
||||
{
|
||||
res = mFetcher->mCurlGetRequest->getByteRange(mUrl, headers, offset, mRequestedSize,
|
||||
new HTTPGetResponder(mFetcher, mID, LLTimer::getTotalTime(), mRequestedSize, offset, true));
|
||||
}
|
||||
catch(AICurlNoEasyHandle const& error)
|
||||
{
|
||||
llwarns << error.what() << llendl;
|
||||
}
|
||||
}
|
||||
if (!res)
|
||||
{
|
||||
@@ -2435,7 +2442,7 @@ void LLTextureFetch::shutDownImageDecodeThread()
|
||||
void LLTextureFetch::startThread()
|
||||
{
|
||||
// Construct mCurlGetRequest from Worker Thread
|
||||
mCurlGetRequest = new LLCurlRequest();
|
||||
mCurlGetRequest = new AICurlInterface::Request;
|
||||
}
|
||||
|
||||
// WORKER THREAD
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#include "llimage.h"
|
||||
#include "lluuid.h"
|
||||
#include "llworkerthread.h"
|
||||
#include "llcurl.h"
|
||||
#include "llcurlrequest.h"
|
||||
#include "lltextureinfo.h"
|
||||
#include "llapr.h"
|
||||
|
||||
@@ -107,7 +107,7 @@ public:
|
||||
LLViewerAssetStats * main_stats);
|
||||
void commandDataBreak();
|
||||
|
||||
LLCurlRequest & getCurlRequest() { return *mCurlGetRequest; }
|
||||
AICurlInterface::Request& getCurlRequest() { return *mCurlGetRequest; }
|
||||
|
||||
bool isQAMode() const { return mQAMode; }
|
||||
|
||||
@@ -178,7 +178,7 @@ private:
|
||||
|
||||
LLTextureCache* mTextureCache;
|
||||
LLImageDecodeThread* mImageDecodeThread;
|
||||
LLCurlRequest* mCurlGetRequest;
|
||||
AICurlInterface::Request* mCurlGetRequest;
|
||||
|
||||
// Map of all requests by UUID
|
||||
typedef std::map<LLUUID,LLTextureFetchWorker*> map_t;
|
||||
|
||||
@@ -462,7 +462,7 @@ void LLViewerParcelMedia::sendMediaNavigateMessage(const std::string& url)
|
||||
body["agent-id"] = gAgent.getID();
|
||||
body["local-id"] = LLViewerParcelMgr::getInstance()->getAgentParcel()->getLocalID();
|
||||
body["url"] = url;
|
||||
LLHTTPClient::post(region_url, body, new LLHTTPClient::Responder);
|
||||
LLHTTPClient::post(region_url, body, new LLHTTPClient::ResponderIgnore);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1310,7 +1310,7 @@ void LLViewerParcelMgr::sendParcelPropertiesUpdate(LLParcel* parcel, bool use_ag
|
||||
parcel->packMessage(body);
|
||||
llinfos << "Sending parcel properties update via capability to: "
|
||||
<< url << llendl;
|
||||
LLHTTPClient::post(url, body, new LLHTTPClient::Responder());
|
||||
LLHTTPClient::post(url, body, new LLHTTPClient::ResponderIgnore);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -111,7 +111,7 @@ public:
|
||||
} Status;
|
||||
|
||||
bool process();
|
||||
// run the request a little, returns true when done
|
||||
// Returns true when done.
|
||||
|
||||
Status status(int* curlCode);
|
||||
// return status, and extended CURL code, if code isn't null
|
||||
@@ -127,7 +127,7 @@ public:
|
||||
// retains ownership of the result object, don't free it
|
||||
|
||||
F64 transferRate();
|
||||
// only valid if StsatusComplete, otherwise 0.0
|
||||
// only valid if StatusComplete, otherwise 0.0
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
|
||||
@@ -5,7 +5,7 @@ project(statemachine)
|
||||
include(00-Common)
|
||||
include(LLCommon)
|
||||
include(LLPlugin)
|
||||
include(LLMessage) # This is needed by LLPlugin.
|
||||
include(LLMessage)
|
||||
include(LLMath)
|
||||
include(LLVFS)
|
||||
include(LLXML)
|
||||
@@ -38,6 +38,7 @@ include_directories(
|
||||
|
||||
set(statemachine_SOURCE_FILES
|
||||
aistatemachine.cpp
|
||||
aicurleasyrequeststatemachine.cpp
|
||||
aifilepicker.cpp
|
||||
aifetchinventoryfolder.cpp
|
||||
aievent.cpp
|
||||
@@ -47,6 +48,7 @@ set(statemachine_SOURCE_FILES
|
||||
set(statemachine_HEADER_FILES
|
||||
CMakeLists.txt
|
||||
aistatemachine.h
|
||||
aicurleasyrequeststatemachine.h
|
||||
aifilepicker.h
|
||||
aidirpicker.h
|
||||
aifetchinventoryfolder.h
|
||||
|
||||
152
indra/newview/statemachine/aicurleasyrequeststatemachine.cpp
Normal file
152
indra/newview/statemachine/aicurleasyrequeststatemachine.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* @file aicurleasyrequeststatemachine.cpp
|
||||
* @brief Implementation of AICurlEasyRequestStateMachine
|
||||
*
|
||||
* Copyright (c) 2012, Aleric Inglewood.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution.
|
||||
*
|
||||
* CHANGELOG
|
||||
* and additional copyright holders.
|
||||
*
|
||||
* 06/05/2012
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "aicurleasyrequeststatemachine.h"
|
||||
|
||||
enum curleasyrequeststatemachine_state_type {
|
||||
AICurlEasyRequestStateMachine_addRequest = AIStateMachine::max_state,
|
||||
AICurlEasyRequestStateMachine_waitAdded,
|
||||
AICurlEasyRequestStateMachine_waitFinished,
|
||||
AICurlEasyRequestStateMachine_finished
|
||||
};
|
||||
|
||||
char const* AICurlEasyRequestStateMachine::state_str_impl(state_type run_state) const
|
||||
{
|
||||
switch(run_state)
|
||||
{
|
||||
AI_CASE_RETURN(AICurlEasyRequestStateMachine_addRequest);
|
||||
AI_CASE_RETURN(AICurlEasyRequestStateMachine_waitAdded);
|
||||
AI_CASE_RETURN(AICurlEasyRequestStateMachine_waitFinished);
|
||||
AI_CASE_RETURN(AICurlEasyRequestStateMachine_finished);
|
||||
}
|
||||
return "UNKNOWN STATE";
|
||||
}
|
||||
|
||||
void AICurlEasyRequestStateMachine::initialize_impl(void)
|
||||
{
|
||||
{
|
||||
AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest);
|
||||
llassert(curlEasyRequest_w->is_finalized()); // Call finalizeRequest(url) before calling run().
|
||||
curlEasyRequest_w->send_events_to(this);
|
||||
}
|
||||
set_state(AICurlEasyRequestStateMachine_addRequest);
|
||||
}
|
||||
|
||||
// CURL-THREAD
|
||||
void AICurlEasyRequestStateMachine::added_to_multi_handle(AICurlEasyRequest_wat&)
|
||||
{
|
||||
set_state(AICurlEasyRequestStateMachine_waitFinished);
|
||||
}
|
||||
|
||||
// CURL-THREAD
|
||||
void AICurlEasyRequestStateMachine::finished(AICurlEasyRequest_wat&)
|
||||
{
|
||||
}
|
||||
|
||||
// CURL-THREAD
|
||||
void AICurlEasyRequestStateMachine::removed_from_multi_handle(AICurlEasyRequest_wat&)
|
||||
{
|
||||
set_state(AICurlEasyRequestStateMachine_finished);
|
||||
}
|
||||
|
||||
void AICurlEasyRequestStateMachine::multiplex_impl(void)
|
||||
{
|
||||
switch (mRunState)
|
||||
{
|
||||
case AICurlEasyRequestStateMachine_addRequest:
|
||||
{
|
||||
mCurlEasyRequest.addRequest();
|
||||
set_state(AICurlEasyRequestStateMachine_waitAdded);
|
||||
}
|
||||
case AICurlEasyRequestStateMachine_waitAdded:
|
||||
{
|
||||
idle(); // Wait till AICurlEasyRequestStateMachine::added_to_multi_handle() is called.
|
||||
break;
|
||||
}
|
||||
case AICurlEasyRequestStateMachine_waitFinished:
|
||||
{
|
||||
idle(); // Wait till AICurlEasyRequestStateMachine::finished() is called.
|
||||
break;
|
||||
}
|
||||
case AICurlEasyRequestStateMachine_finished:
|
||||
{
|
||||
if (mBuffered)
|
||||
{
|
||||
AICurlEasyRequest_wat easy_request_w(*mCurlEasyRequest);
|
||||
AICurlResponderBuffer_wat buffered_easy_request_w(*mCurlEasyRequest);
|
||||
buffered_easy_request_w->processOutput(easy_request_w);
|
||||
}
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AICurlEasyRequestStateMachine::abort_impl(void)
|
||||
{
|
||||
Dout(dc::curl, "AICurlEasyRequestStateMachine::abort_impl called for = " << (void*)mCurlEasyRequest.get());
|
||||
// We must first revoke the events, or the curl thread might change mRunState still.
|
||||
{
|
||||
AICurlEasyRequest_wat curl_easy_request_w(*mCurlEasyRequest);
|
||||
curl_easy_request_w->send_events_to(NULL);
|
||||
curl_easy_request_w->revokeCallbacks();
|
||||
}
|
||||
if (mRunState >= AICurlEasyRequestStateMachine_waitAdded && mRunState < AICurlEasyRequestStateMachine_finished)
|
||||
{
|
||||
// Revert call to addRequest().
|
||||
// Note that it's safe to call this even if the curl thread already removed it, or will removes it
|
||||
// after we called this, before processing the remove command; only the curl thread calls
|
||||
// MultiHandle::remove_easy_request, which is a no-op when called twice for the same easy request.
|
||||
mCurlEasyRequest.removeRequest();
|
||||
}
|
||||
}
|
||||
|
||||
void AICurlEasyRequestStateMachine::finish_impl(void)
|
||||
{
|
||||
Dout(dc::curl, "AICurlEasyRequestStateMachine::finish_impl called for = " << (void*)mCurlEasyRequest.get());
|
||||
if (!aborted())
|
||||
{
|
||||
AICurlEasyRequest_wat curl_easy_request_w(*mCurlEasyRequest);
|
||||
curl_easy_request_w->send_events_to(NULL);
|
||||
curl_easy_request_w->revokeCallbacks();
|
||||
}
|
||||
}
|
||||
|
||||
AICurlEasyRequestStateMachine::AICurlEasyRequestStateMachine(bool buffered) : mBuffered(buffered), mCurlEasyRequest(buffered)
|
||||
{
|
||||
Dout(dc::statemachine, "Calling AICurlEasyRequestStateMachine(" << (buffered ? "true" : "false") << ") [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]");
|
||||
}
|
||||
|
||||
AICurlEasyRequestStateMachine::~AICurlEasyRequestStateMachine()
|
||||
{
|
||||
Dout(dc::statemachine, "Calling ~AICurlEasyRequestStateMachine() [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]");
|
||||
}
|
||||
|
||||
96
indra/newview/statemachine/aicurleasyrequeststatemachine.h
Normal file
96
indra/newview/statemachine/aicurleasyrequeststatemachine.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* @file aicurleasyrequest.h
|
||||
* @brief Perform a curl easy request.
|
||||
*
|
||||
* Copyright (c) 2012, Aleric Inglewood.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution.
|
||||
*
|
||||
* CHANGELOG
|
||||
* and additional copyright holders.
|
||||
*
|
||||
* 06/05/2012
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
#ifndef AICURLEASYREQUEST_H
|
||||
#define AICURLEASYREQUEST_H
|
||||
|
||||
#include "aistatemachine.h"
|
||||
#include "aicurl.h"
|
||||
|
||||
// A curl easy request state machine.
|
||||
//
|
||||
// Before calling cersm.run() initialize the object (cersm) as follows:
|
||||
//
|
||||
// AICurlEasyRequest_wat cersm_w(cersm);
|
||||
// cersm_w->setopt(...); // etc, see the interface of AICurlPrivate::CurlEasyRequest and it's base class AICurlPrivate::CurlEasyHandle.
|
||||
//
|
||||
// When the state machine finishes, call aborted() to check
|
||||
// whether or not the statemachine succeeded in fetching
|
||||
// the URL or not.
|
||||
//
|
||||
// Objects of this type can be reused multiple times, see
|
||||
// also the documentation of AIStateMachine.
|
||||
//
|
||||
// Construction of a AICurlEasyRequestStateMachine might throw AICurlNoEasyHandle.
|
||||
class AICurlEasyRequestStateMachine : public AIStateMachine, public AICurlEasyHandleEvents {
|
||||
public:
|
||||
AICurlEasyRequestStateMachine(bool buffered);
|
||||
|
||||
// Transparent access.
|
||||
AICurlEasyRequest mCurlEasyRequest;
|
||||
|
||||
private:
|
||||
bool mBuffered; // Argument used for construction of mCurlEasyRequest.
|
||||
|
||||
protected:
|
||||
// AICurlEasyRequest Events.
|
||||
|
||||
// Called when this curl easy handle was added to a multi handle.
|
||||
/*virtual*/ void added_to_multi_handle(AICurlEasyRequest_wat&);
|
||||
|
||||
// Called when this curl easy handle finished processing (right before it is removed from the multi handle).
|
||||
/*virtual*/ void finished(AICurlEasyRequest_wat&);
|
||||
|
||||
// Called after this curl easy handle was removed from a multi handle.
|
||||
/*virtual*/ void removed_from_multi_handle(AICurlEasyRequest_wat&);
|
||||
|
||||
protected:
|
||||
// AIStateMachine implementations.
|
||||
|
||||
// Call finish() (or abort()), not delete.
|
||||
/*virtual*/ ~AICurlEasyRequestStateMachine();
|
||||
|
||||
// Handle initializing the object.
|
||||
/*virtual*/ void initialize_impl(void);
|
||||
|
||||
// Handle mRunState.
|
||||
/*virtual*/ void multiplex_impl(void);
|
||||
|
||||
// Handle aborting from current bs_run state.
|
||||
/*virtual*/ void abort_impl(void);
|
||||
|
||||
// Handle cleaning up from initialization (or post abort) state.
|
||||
/*virtual*/ void finish_impl(void);
|
||||
|
||||
// Implemenation of state_str for run states.
|
||||
/*virtual*/ char const* state_str_impl(state_type run_state) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -237,7 +237,7 @@ class AIStateMachine {
|
||||
|
||||
protected:
|
||||
//! The user should call 'kill()', not delete a AIStateMachine (derived) directly.
|
||||
virtual ~AIStateMachine() { llassert(mState == bs_killed && mActive == as_idle); }
|
||||
virtual ~AIStateMachine() { llassert((mState == bs_killed && mActive == as_idle) || mState == bs_initialize); }
|
||||
|
||||
public:
|
||||
//! Halt the state machine until cont() is called.
|
||||
|
||||
Reference in New Issue
Block a user