Conflicts:
	indra/newview/llfloateravatarpicker.cpp - Includes to v-d style, since plain alphabetical just won't cut it. Shyotl's changes for name system, here.
	indra/newview/llpanelgroupinvite.cpp - Shyotl's changes for name system, here.

Also corrected new README to have less typos and be slightly more accurate.
This commit is contained in:
Lirusaito
2012-12-10 11:24:25 -05:00
333 changed files with 11005 additions and 6945 deletions

View File

@@ -418,6 +418,7 @@ void cleanupCurl(void)
if (CurlMultiHandle::getTotalMultiHandles() != 0)
llwarns << "Not all CurlMultiHandle objects were destroyed!" << llendl;
AIStateMachine::flush();
clearCommandQueue();
Stats::print();
ssl_cleanup();
@@ -491,12 +492,10 @@ void Stats::print(void)
// Even more strict, BufferedCurlEasyRequest may not be created directly either, only as
// base class of ThreadSafeBufferedCurlEasyRequest.
llassert(BufferedCurlEasyRequest_count == ThreadSafeBufferedCurlEasyRequest_count);
// Each AICurlEasyRequestStateMachine is responsible for exactly one easy handle.
llassert(easy_handles >= AICurlEasyRequest_count);
// Each AICurlEasyRequestStateMachine has one AICurlEasyRequest member.
llassert(AICurlEasyRequest_count >= AICurlEasyRequestStateMachine_count);
// AIFIXME: is this really always the case? And why?
llassert(easy_handles <= ResponderBase_count);
llassert(easy_handles <= S32(ResponderBase_count));
}
} // namespace AICurlInterface
@@ -1348,11 +1347,22 @@ void BufferedCurlEasyRequest::prepRequest(AICurlEasyRequest_wat& curl_easy_reque
curl_easy_request_w->setReadCallback(&curlReadCallback, lockobj);
curl_easy_request_w->setHeaderCallback(&curlHeaderCallback, lockobj);
bool allow_cookies = headers.hasHeader("Cookie");
// Allow up to ten redirects.
if (responder->followRedir())
{
curl_easy_request_w->setopt(CURLOPT_FOLLOWLOCATION, 1);
curl_easy_request_w->setopt(CURLOPT_MAXREDIRS, HTTP_REDIRECTS_DEFAULT);
// This is needed (at least) for authentication after temporary redirection
// to id.secondlife.com for marketplace.secondlife.com.
allow_cookies = true;
}
if (allow_cookies)
{
// Given an empty or non-existing file or by passing the empty string (""),
// this option will enable cookies for this curl handle, making it understand
// and parse received cookies and then use matching cookies in future requests.
curl_easy_request_w->setopt(CURLOPT_COOKIEFILE, "");
}
// Keep responder alive.

View File

@@ -56,12 +56,17 @@ PerHostRequestQueuePtr PerHostRequestQueue::instance(std::string const& hostname
//static
void PerHostRequestQueue::release(PerHostRequestQueuePtr& instance)
{
if (instance->lastone())
if (instance->exactly_two_left()) // Being 'instance' and the one in sInstanceMap.
{
// The viewer can be have left main() we can't access the global sInstanceMap anymore.
if (LLApp::isStopped())
{
return;
}
instance_map_wat instance_map_w(sInstanceMap);
// It is possible that 'lastone' is not up to date anymore.
// It is possible that 'exactly_two_left' is not up to date anymore.
// Therefore, recheck the condition now that we have locked sInstanceMap.
if (!instance->lastone())
if (!instance->exactly_two_left())
{
// Some other thread added this host in the meantime.
return;
@@ -87,13 +92,13 @@ void PerHostRequestQueue::release(PerHostRequestQueuePtr& instance)
bool PerHostRequestQueue::throttled() const
{
llassert(mAdded <= curl_concurrent_connections_per_host);
return mAdded == curl_concurrent_connections_per_host;
llassert(mAdded <= int(curl_concurrent_connections_per_host));
return mAdded == int(curl_concurrent_connections_per_host);
}
void PerHostRequestQueue::added_to_multi_handle(void)
{
llassert(mAdded < curl_concurrent_connections_per_host);
llassert(mAdded < int(curl_concurrent_connections_per_host));
++mAdded;
}

View File

@@ -118,7 +118,7 @@ class PerHostRequestQueue {
class RefCountedThreadSafePerHostRequestQueue : public threadsafe_PerHostRequestQueue {
public:
RefCountedThreadSafePerHostRequestQueue(void) : mReferenceCount(0) { }
bool lastone(void) const { llassert(mReferenceCount >= 2); return mReferenceCount == 2; }
bool exactly_two_left(void) const { return mReferenceCount == 2; }
private:
// Used by PerHostRequestQueuePtr. Object is deleted when reference count reaches zero.

View File

@@ -119,6 +119,7 @@ inline CURLMcode check_multi_code(CURLMcode code) { AICurlInterface::Stats::mult
bool curlThreadIsRunning(void);
void wakeUpCurlThread(void);
void stopCurlThread(void);
void clearCommandQueue(void);
#define DECLARE_SETOPT(param_type) \
CURLcode setopt(CURLoption option, param_type parameter)

View File

@@ -1065,6 +1065,10 @@ void AICurlThread::wakeup_thread(void)
DoutEntering(dc::curl, "AICurlThread::wakeup_thread");
llassert(is_main_thread());
// If we are already exiting the viewer then return immediately.
if (!mRunning)
return;
// Try if curl thread is still awake and if so, pass the new commands directly.
if (mWakeUpMutex.tryLock())
{
@@ -1609,7 +1613,9 @@ CURLMcode MultiHandle::remove_easy_request(addedEasyRequests_type::iterator cons
ThreadSafeBufferedCurlEasyRequest* lockobj = iter->get_ptr().get();
#endif
mAddedEasyRequests.erase(iter);
#if CWDEBUG
Dout(dc::curl, "MultiHandle::remove_easy_request: Removed AICurlEasyRequest " << (void*)lockobj << "; now processing " << mAddedEasyRequests.size() << " easy handles.");
#endif
// Attempt to add a queued request, if any.
PerHostRequestQueue_wat(*per_host)->add_queued_to(this);
@@ -2148,10 +2154,14 @@ void stopCurlThread(void)
ms_sleep(10);
}
Dout(dc::curl, "Curl thread" << (curlThreadIsRunning() ? " not" : "") << " stopped after " << ((100 - count) * 10) << "ms.");
// Clear the command queue, for a cleaner cleanup.
}
}
void clearCommandQueue(void)
{
// Clear the command queue now in order to avoid the global deinitialization order fiasco.
command_queue_wat command_queue_w(command_queue);
command_queue_w->clear();
}
}
//-----------------------------------------------------------------------------
@@ -2162,6 +2172,12 @@ void BufferedCurlEasyRequest::setStatusAndReason(U32 status, std::string const&
mStatus = status;
mReason = reason;
AICurlInterface::Stats::status_count[AICurlInterface::Stats::status2index(mStatus)]++;
// Sanity check. If the server replies with a redirect status then we better have that option turned on!
if ((status >= 300 && status < 400) && mResponder && !mResponder->followRedir())
{
llerrs << "Received " << status << " (" << reason << ") for responder \"" << mTimeoutPolicy->name() << "\" which has no followRedir()!" << llendl;
}
}
void BufferedCurlEasyRequest::processOutput(void)
@@ -2353,10 +2369,10 @@ size_t BufferedCurlEasyRequest::curlHeaderCallback(char* data, size_t size, size
#if defined(CWDEBUG) || defined(DEBUG_CURLIO)
int debug_callback(CURL*, curl_infotype infotype, char* buf, size_t size, void* user_ptr)
{
BufferedCurlEasyRequest* request = (BufferedCurlEasyRequest*)user_ptr;
#ifdef CWDEBUG
using namespace ::libcwd;
BufferedCurlEasyRequest* request = (BufferedCurlEasyRequest*)user_ptr;
std::ostringstream marker;
marker << (void*)request->get_lockobj();
libcw_do.push_marker();

View File

@@ -820,6 +820,7 @@ P(accountingCostResponder);
P(agentStateResponder);
P(assetUploadResponder);
P(asyncConsoleResponder);
P(avatarPickerResponder);
P(authHandler);
P(avatarNameResponder);
P2(baseCapabilitiesComplete, transfer_18s);
@@ -890,6 +891,7 @@ P(viewerStatsResponder);
P(viewerVoiceAccountProvisionResponder);
P(voiceCallCapResponder);
P(voiceClientCapResponder);
P(webProfileResponders);
P(wholeModelFeeResponder);
P(wholeModelUploadResponder);
P2(XMLRPCResponder, connect_40s);

View File

@@ -624,7 +624,7 @@ void debug_curl_easy_reset(CURL* handle)
CURLcode debug_curl_easy_setopt(CURL* handle, CURLoption option, ...)
{
CURLcode ret;
CURLcode ret = CURLE_UNKNOWN_OPTION; // Suppress compiler warning.
va_list ap;
union param_type {
long along;
@@ -841,7 +841,7 @@ CURLMcode debug_curl_multi_remove_handle(CURLM* multi_handle, CURL* easy_handle)
CURLMcode debug_curl_multi_setopt(CURLM* multi_handle, CURLMoption option, ...)
{
CURLMcode ret;
CURLMcode ret = CURLM_UNKNOWN_OPTION; // Suppress compiler warning.
va_list ap;
union param_type {
long along;

View File

@@ -93,6 +93,9 @@ namespace LLAvatarNameCache
/// Time when unrefreshed cached names were checked last
static F64 sLastExpireCheck;
/// Time-to-live for a temp cache entry.
const F64 TEMP_CACHE_ENTRY_LIFETIME = 60.0;
//-----------------------------------------------------------------------
// Internal methods
//-----------------------------------------------------------------------
@@ -291,13 +294,14 @@ void LLAvatarNameCache::handleAgentError(const LLUUID& agent_id)
// Clear this agent from the pending list
LLAvatarNameCache::sPendingQueue.erase(agent_id);
const LLAvatarName& av_name = existing->second;
LLAvatarName& av_name = existing->second;
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache use cache for agent "
<< agent_id
<< "user '" << av_name.mUsername << "' "
<< "display '" << av_name.mDisplayName << "' "
<< "expires in " << av_name.mExpires - LLFrameTimer::getTotalSeconds() << " seconds"
<< LL_ENDL;
av_name.mExpires = LLFrameTimer::getTotalSeconds() + TEMP_CACHE_ENTRY_LIFETIME; // reset expiry time so we don't constantly rerequest.
}
}
@@ -342,19 +346,23 @@ void LLAvatarNameCache::requestNamesViaCapability()
// http://pdp60.lindenlab.com:8000/agents/?ids=3941037e-78ab-45f0-b421-bd6e77c1804d&ids=0012809d-7d2d-4c24-9609-af1230a37715&ids=0019aaba-24af-4f0a-aa72-6457953cf7f0
//
// Apache can handle URLs of 4096 chars, but let's be conservative
const U32 NAME_URL_MAX = 4096;
const U32 NAME_URL_SEND_THRESHOLD = 3000;
static const U32 NAME_URL_MAX = 4096;
static const U32 NAME_URL_SEND_THRESHOLD = 3500;
std::string url;
url.reserve(NAME_URL_MAX);
std::vector<LLUUID> agent_ids;
agent_ids.reserve(128);
U32 id_total = sAskQueue.size();
U32 ids = 0;
ask_queue_t::const_iterator it = sAskQueue.begin();
for ( ; it != sAskQueue.end(); ++it)
ask_queue_t::const_iterator it;
while(!sAskQueue.empty())
{
it = sAskQueue.begin();
const LLUUID& agent_id = *it;
sAskQueue.erase(it);
if (url.empty())
{
@@ -377,27 +385,17 @@ void LLAvatarNameCache::requestNamesViaCapability()
if (url.size() > NAME_URL_SEND_THRESHOLD)
{
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability first "
<< ids << " ids"
<< LL_ENDL;
LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids));
url.clear();
agent_ids.clear();
break;
}
}
if (!url.empty())
{
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability all "
<< ids << " ids"
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability requested "
<< ids << "/" << id_total << "ids "
<< LL_ENDL;
LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids));
url.clear();
agent_ids.clear();
}
// We've moved all asks to the pending request queue
sAskQueue.clear();
}
void LLAvatarNameCache::legacyNameCallback(const LLUUID& agent_id,
@@ -414,20 +412,25 @@ void LLAvatarNameCache::legacyNameCallback(const LLUUID& agent_id,
<< LL_ENDL;
buildLegacyName(full_name, &av_name);
// Don't add to cache, the data already exists in the legacy name system
// cache and we don't want or need duplicate storage, because keeping the
// two copies in sync is complex.
processName(agent_id, av_name, false);
// Add to cache, because if we don't we'll keep rerequesting the
// same record forever. buildLegacyName should always guarantee
// that these records expire reasonably soon
// (in TEMP_CACHE_ENTRY_LIFETIME seconds), so if the failure was due
// to something temporary we will eventually request and get the right data.
processName(agent_id, av_name, true);
}
void LLAvatarNameCache::requestNamesViaLegacy()
{
static const S32 MAX_REQUESTS = 100;
F64 now = LLFrameTimer::getTotalSeconds();
std::string full_name;
ask_queue_t::const_iterator it = sAskQueue.begin();
for (; it != sAskQueue.end(); ++it)
ask_queue_t::const_iterator it;
for (S32 requests = 0; !sAskQueue.empty() && requests < MAX_REQUESTS; ++requests)
{
it = sAskQueue.begin();
const LLUUID& agent_id = *it;
sAskQueue.erase(it);
// Mark as pending first, just in case the callback is immediately
// invoked below. This should never happen in practice.
@@ -439,10 +442,6 @@ void LLAvatarNameCache::requestNamesViaLegacy()
boost::bind(&LLAvatarNameCache::legacyNameCallback,
_1, _2, _3));
}
// We've either answered immediately or moved all asks to the
// pending queue
sAskQueue.clear();
}
void LLAvatarNameCache::initClass(bool running)
@@ -519,11 +518,11 @@ void LLAvatarNameCache::idle()
// *TODO: Possibly re-enabled this based on People API load measurements
// 100 ms is the threshold for "user speed" operations, so we can
// stall for about that long to batch up requests.
//const F32 SECS_BETWEEN_REQUESTS = 0.1f;
//if (!sRequestTimer.checkExpirationAndReset(SECS_BETWEEN_REQUESTS))
//{
// return;
//}
const F32 SECS_BETWEEN_REQUESTS = 0.1f;
if (!sRequestTimer.hasExpired())
{
return;
}
if (!sAskQueue.empty())
{
@@ -538,6 +537,12 @@ void LLAvatarNameCache::idle()
}
}
if (sAskQueue.empty())
{
// cleared the list, reset the request timer.
sRequestTimer.reset(SECS_BETWEEN_REQUESTS);
}
// erase anything that has not been refreshed for more than MAX_UNREFRESHED_TIME
eraseUnrefreshed();
}
@@ -595,7 +600,7 @@ void LLAvatarNameCache::buildLegacyName(const std::string& full_name,
av_name->mDisplayName = full_name;
av_name->mIsDisplayNameDefault = true;
av_name->mIsTemporaryName = true;
av_name->mExpires = F64_MAX; // not used because these are not cached
av_name->mExpires = LLFrameTimer::getTotalSeconds() + TEMP_CACHE_ENTRY_LIFETIME;
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::buildLegacyName "
<< full_name
<< LL_ENDL;
@@ -695,8 +700,10 @@ void LLAvatarNameCache::fireSignal(const LLUUID& agent_id,
signal(agent_id, av_name);
}
void LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot)
LLAvatarNameCache::callback_connection_t LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot)
{
callback_connection_t connection;
if (sRunning)
{
// ...only do immediate lookups when cache is running
@@ -712,7 +719,7 @@ void LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot)
{
// ...name already exists in cache, fire callback now
fireSignal(agent_id, slot, av_name);
return;
return connection;
}
}
}
@@ -725,7 +732,7 @@ void LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot)
LLAvatarName av_name;
buildLegacyName(full_name, &av_name);
fireSignal(agent_id, slot, av_name);
return;
return connection;
}
}
}
@@ -742,15 +749,17 @@ void LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot)
{
// ...new callback for this id
callback_signal_t* signal = new callback_signal_t();
signal->connect(slot);
connection = signal->connect(slot);
sSignalMap[agent_id] = signal;
}
else
{
// ...existing callback, bind additional slot
callback_signal_t* signal = sig_it->second;
signal->connect(slot);
connection = signal->connect(slot);
}
return connection;
}
// [RLVa:KB] - Checked: 2010-12-08 (RLVa-1.4.0a) | Added: RLVa-1.2.2c
@@ -796,12 +805,6 @@ void LLAvatarNameCache::erase(const LLUUID& agent_id)
sCache.erase(agent_id);
}
void LLAvatarNameCache::fetch(const LLUUID& agent_id)
{
// re-request, even if request is already pending
sAskQueue.insert(agent_id);
}
void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_name)
{
// *TODO: update timestamp if zero?
@@ -810,26 +813,35 @@ void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_na
F64 LLAvatarNameCache::nameExpirationFromHeaders(AIHTTPReceivedHeaders const& headers)
{
F64 expires;
expirationFromCacheControl(headers, &expires);
return expires;
F64 expires = 0.0;
if (expirationFromCacheControl(headers, &expires))
{
return expires;
}
else
{
// With no expiration info, default to an hour
const F64 DEFAULT_EXPIRES = 60.0 * 60.0;
F64 now = LLFrameTimer::getTotalSeconds();
return now + DEFAULT_EXPIRES;
}
}
bool LLAvatarNameCache::expirationFromCacheControl(AIHTTPReceivedHeaders const& headers, F64* expires)
{
bool fromCacheControl = false;
S32 max_age = 3600; // With no expiration info, default to an hour.
F64 now = LLFrameTimer::getTotalSeconds();
// Allow the header to override the default
std::string cache_control;
if (headers.getFirstValue("cache-control", cache_control))
{
S32 max_age = 0;
if (max_age_from_cache_control(cache_control, &max_age))
{
*expires = now + (F64)max_age;
fromCacheControl = true;
}
}
*expires = now + (F64)max_age;
LL_DEBUGS("AvNameCache")
<< ( fromCacheControl ? "expires based on cache control " : "default expiration " )
<< "in " << *expires - now << " seconds"

View File

@@ -77,10 +77,11 @@ namespace LLAvatarNameCache
void (const LLUUID& agent_id, const LLAvatarName& av_name)>
callback_signal_t;
typedef callback_signal_t::slot_type callback_slot_t;
typedef boost::signals2::connection callback_connection_t;
// Fetches name information and calls callback.
// If name information is in cache, callback will be called immediately.
void get(const LLUUID& agent_id, callback_slot_t slot);
callback_connection_t get(const LLUUID& agent_id, callback_slot_t slot);
// Allow display names to be explicitly disabled for testing.
void setUseDisplayNames(bool use);
@@ -96,10 +97,6 @@ namespace LLAvatarNameCache
/// Provide some fallback for agents that return errors
void handleAgentError(const LLUUID& agent_id);
// Force a re-fetch of the most recent data, but keep the current
// data in cache
void fetch(const LLUUID& agent_id);
void insert(const LLUUID& agent_id, const LLAvatarName& av_name);
// Compute name expiration time from HTTP Cache-Control header,

View File

@@ -161,7 +161,7 @@ public:
// A derived class should return true if curl should follow redirections.
// The default is not to follow redirections.
virtual bool followRedir(void) { return false; }
virtual bool followRedir(void) const { return false; }
// Timeout policy to use.
virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const = 0;
@@ -188,6 +188,7 @@ public:
class ResponderHeadersOnly : public ResponderBase {
private:
/*virtual*/ bool needsHeaders(void) const { return true; }
/*virtual*/ bool followRedir(void) const { return true; }
protected:
// ResponderBase event

View File

@@ -85,11 +85,6 @@ LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, std::string cons
void LLURLRequest::initialize_impl(void)
{
if (mHeaders.hasHeader("Cookie"))
{
allowCookies();
}
// If the header is "Pragma" with no value, the caller intends to
// force libcurl to drop the Pragma header it so gratuitously inserts.
// Before inserting the header, force libcurl to not use the proxy.
@@ -105,7 +100,7 @@ void LLURLRequest::initialize_impl(void)
// but if they did not specify a Content-Type, then ask the injector.
mHeaders.addHeader("Content-Type", mBody->contentType(), AIHTTPHeaders::keep_existing_header);
}
else
else if (mAction != HTTP_HEAD)
{
// Check to see if we have already set Accept or not. If no one
// set it, set it to application/llsd+xml since that's what we
@@ -199,12 +194,6 @@ void LLURLRequest::useProxy(const std::string &proxy)
}
#endif
void LLURLRequest::allowCookies()
{
AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest);
curlEasyRequest_w->setoptString(CURLOPT_COOKIEFILE, "");
}
bool LLURLRequest::configure(AICurlEasyRequest_wat const& curlEasyRequest_w)
{
bool rv = false;
@@ -213,13 +202,11 @@ bool LLURLRequest::configure(AICurlEasyRequest_wat const& curlEasyRequest_w)
{
case HTTP_HEAD:
curlEasyRequest_w->setopt(CURLOPT_NOBODY, 1);
curlEasyRequest_w->setopt(CURLOPT_FOLLOWLOCATION, 1);
rv = true;
break;
case HTTP_GET:
curlEasyRequest_w->setopt(CURLOPT_HTTPGET, 1);
curlEasyRequest_w->setopt(CURLOPT_FOLLOWLOCATION, 1);
// Set Accept-Encoding to allow response compression
curlEasyRequest_w->setoptString(CURLOPT_ENCODING, mNoCompression ? "identity" : "");

View File

@@ -84,11 +84,6 @@ class LLURLRequest : public AICurlEasyRequestStateMachine {
/*virtual*/ ~LLURLRequest() { }
public:
/**
* @brief Turn on cookie handling for this request with CURLOPT_COOKIEFILE.
*/
void allowCookies(void);
/**
* @ brief Turn off (or on) the CURLOPT_PROXY header.
*/