diff options
| -rwxr-xr-x | indra/llcorehttp/_httpoperation.cpp | 6 | ||||
| -rwxr-xr-x | indra/llcorehttp/_httpoprequest.cpp | 156 | ||||
| -rwxr-xr-x | indra/llcorehttp/httpcommon.cpp | 3 | ||||
| -rwxr-xr-x | indra/llcorehttp/httpcommon.h | 5 | ||||
| -rwxr-xr-x | indra/llmessage/llcurl.cpp | 11 | ||||
| -rwxr-xr-x | indra/newview/llmeshrepository.cpp | 101 | ||||
| -rwxr-xr-x | indra/newview/llmeshrepository.h | 19 | 
7 files changed, 214 insertions, 87 deletions
| diff --git a/indra/llcorehttp/_httpoperation.cpp b/indra/llcorehttp/_httpoperation.cpp index 7acd728bbd..5bb0654652 100755 --- a/indra/llcorehttp/_httpoperation.cpp +++ b/indra/llcorehttp/_httpoperation.cpp @@ -94,7 +94,7 @@ void HttpOperation::stageFromRequest(HttpService *)  	// Default implementation should never be called.  This  	// indicates an operation making a transition that isn't  	// defined. -	LL_ERRS("HttpCore") << "Default stageFromRequest method may not be called." +	LL_ERRS("CoreHttp") << "Default stageFromRequest method may not be called."  						<< LL_ENDL;  } @@ -104,7 +104,7 @@ void HttpOperation::stageFromReady(HttpService *)  	// Default implementation should never be called.  This  	// indicates an operation making a transition that isn't  	// defined. -	LL_ERRS("HttpCore") << "Default stageFromReady method may not be called." +	LL_ERRS("CoreHttp") << "Default stageFromReady method may not be called."  						<< LL_ENDL;  } @@ -114,7 +114,7 @@ void HttpOperation::stageFromActive(HttpService *)  	// Default implementation should never be called.  This  	// indicates an operation making a transition that isn't  	// defined. -	LL_ERRS("HttpCore") << "Default stageFromActive method may not be called." +	LL_ERRS("CoreHttp") << "Default stageFromActive method may not be called."  						<< LL_ENDL;  } diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp index d72f8f6119..63c4e71258 100755 --- a/indra/llcorehttp/_httpoprequest.cpp +++ b/indra/llcorehttp/_httpoprequest.cpp @@ -90,6 +90,10 @@ char * os_strtrim(char * str);  char * os_strltrim(char * str);  void os_strlower(char * str); +// Error testing and reporting for libcurl status codes +void check_curl_easy_code(CURLcode code); +void check_curl_easy_code(CURLcode code, int curl_setopt_option); +  } // end anonymous namespace @@ -373,6 +377,8 @@ void HttpOpRequest::setupCommon(HttpRequest::policy_t policy_id,  //  HttpStatus HttpOpRequest::prepareRequest(HttpService * service)  { +	CURLcode code; +	  	// Scrub transport and result data for retried op case  	mCurlActive = false;  	mCurlHandle = NULL; @@ -406,12 +412,25 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)  	HttpPolicyGlobal & policy(service->getPolicy().getGlobalOptions());  	mCurlHandle = curl_easy_init(); -	curl_easy_setopt(mCurlHandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); -	curl_easy_setopt(mCurlHandle, CURLOPT_NOSIGNAL, 1); -	curl_easy_setopt(mCurlHandle, CURLOPT_NOPROGRESS, 1); -	curl_easy_setopt(mCurlHandle, CURLOPT_URL, mReqURL.c_str()); -	curl_easy_setopt(mCurlHandle, CURLOPT_PRIVATE, this); -	curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, ""); +	if (! mCurlHandle) +	{ +		// We're in trouble.  We'll continue but it won't go well. +		LL_WARNS("CoreHttp") << "Failed to allocate libcurl easy handle.  Continuing." +							 << LL_ENDL; +		return HttpStatus(HttpStatus::LLCORE, HE_BAD_ALLOC); +	} +	code = curl_easy_setopt(mCurlHandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); +	check_curl_easy_code(code, CURLOPT_IPRESOLVE); +	code = curl_easy_setopt(mCurlHandle, CURLOPT_NOSIGNAL, 1); +	check_curl_easy_code(code, CURLOPT_NOSIGNAL); +	code = curl_easy_setopt(mCurlHandle, CURLOPT_NOPROGRESS, 1); +	check_curl_easy_code(code, CURLOPT_NOPROGRESS); +	code = curl_easy_setopt(mCurlHandle, CURLOPT_URL, mReqURL.c_str()); +	check_curl_easy_code(code, CURLOPT_URL); +	code = curl_easy_setopt(mCurlHandle, CURLOPT_PRIVATE, this); +	check_curl_easy_code(code, CURLOPT_PRIVATE); +	code = curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, ""); +	check_curl_easy_code(code, CURLOPT_ENCODING);  	if (HTTP_ENABLE_LINKSYS_WRT54G_V5_DNS_FIX)  	{ @@ -421,7 +440,8 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)  		// about 700 or so requests and starts issuing TCP RSTs to  		// new connections.  Reuse the DNS lookups for even a few  		// seconds and no RSTs. -		curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, 15); +		code = curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, 15); +		check_curl_easy_code(code, CURLOPT_DNS_CACHE_TIMEOUT);  	}  	else  	{ @@ -429,17 +449,27 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)  		// I don't think this is valid anymore, the Multi shared DNS  		// cache is working well.  For the case of naked easy handles,  		// consider using a shared DNS object. -		curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0); +		code = curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0); +		check_curl_easy_code(code, CURLOPT_DNS_CACHE_TIMEOUT);  	} -	curl_easy_setopt(mCurlHandle, CURLOPT_AUTOREFERER, 1); -	curl_easy_setopt(mCurlHandle, CURLOPT_FOLLOWLOCATION, 1); -	curl_easy_setopt(mCurlHandle, CURLOPT_MAXREDIRS, HTTP_REDIRECTS_DEFAULT); -	curl_easy_setopt(mCurlHandle, CURLOPT_WRITEFUNCTION, writeCallback); -	curl_easy_setopt(mCurlHandle, CURLOPT_WRITEDATA, this); -	curl_easy_setopt(mCurlHandle, CURLOPT_READFUNCTION, readCallback); -	curl_easy_setopt(mCurlHandle, CURLOPT_READDATA, this); -	curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYPEER, 1); -	curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYHOST, 0); +	code = curl_easy_setopt(mCurlHandle, CURLOPT_AUTOREFERER, 1); +	check_curl_easy_code(code, CURLOPT_AUTOREFERER); +	code = curl_easy_setopt(mCurlHandle, CURLOPT_FOLLOWLOCATION, 1); +	check_curl_easy_code(code, CURLOPT_FOLLOWLOCATION); +	code = curl_easy_setopt(mCurlHandle, CURLOPT_MAXREDIRS, HTTP_REDIRECTS_DEFAULT); +	check_curl_easy_code(code, CURLOPT_MAXREDIRS); +	code = curl_easy_setopt(mCurlHandle, CURLOPT_WRITEFUNCTION, writeCallback); +	check_curl_easy_code(code, CURLOPT_WRITEFUNCTION); +	code = curl_easy_setopt(mCurlHandle, CURLOPT_WRITEDATA, this); +	check_curl_easy_code(code, CURLOPT_WRITEDATA); +	code = curl_easy_setopt(mCurlHandle, CURLOPT_READFUNCTION, readCallback); +	check_curl_easy_code(code, CURLOPT_READFUNCTION); +	code = curl_easy_setopt(mCurlHandle, CURLOPT_READDATA, this); +	check_curl_easy_code(code, CURLOPT_READDATA); +	code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYPEER, 1); +	check_curl_easy_code(code, CURLOPT_SSL_VERIFYPEER); +	code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYHOST, 0); +	check_curl_easy_code(code, CURLOPT_SSL_VERIFYHOST);  	if (policy.mUseLLProxy)  	{ @@ -452,37 +482,46 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)  	{  		// *TODO:  This is fine for now but get fuller socks5/  		// authentication thing going later.... -		curl_easy_setopt(mCurlHandle, CURLOPT_PROXY, policy.mHttpProxy.c_str()); -		curl_easy_setopt(mCurlHandle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP); +		code = curl_easy_setopt(mCurlHandle, CURLOPT_PROXY, policy.mHttpProxy.c_str()); +		check_curl_easy_code(code, CURLOPT_PROXY); +		code = curl_easy_setopt(mCurlHandle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP); +		check_curl_easy_code(code, CURLOPT_PROXYTYPE);  	}  	if (policy.mCAPath.size())  	{ -		curl_easy_setopt(mCurlHandle, CURLOPT_CAPATH, policy.mCAPath.c_str()); +		code = curl_easy_setopt(mCurlHandle, CURLOPT_CAPATH, policy.mCAPath.c_str()); +		check_curl_easy_code(code, CURLOPT_CAPATH);  	}  	if (policy.mCAFile.size())  	{ -		curl_easy_setopt(mCurlHandle, CURLOPT_CAINFO, policy.mCAFile.c_str()); +		code = curl_easy_setopt(mCurlHandle, CURLOPT_CAINFO, policy.mCAFile.c_str()); +		check_curl_easy_code(code, CURLOPT_CAINFO);  	}  	switch (mReqMethod)  	{  	case HOR_GET: -		curl_easy_setopt(mCurlHandle, CURLOPT_HTTPGET, 1); +		code = curl_easy_setopt(mCurlHandle, CURLOPT_HTTPGET, 1); +		check_curl_easy_code(code, CURLOPT_HTTPGET);  		mCurlHeaders = curl_slist_append(mCurlHeaders, "Connection: keep-alive");  		mCurlHeaders = curl_slist_append(mCurlHeaders, "Keep-alive: 300");  		break;  	case HOR_POST:  		{ -			curl_easy_setopt(mCurlHandle, CURLOPT_POST, 1); -			curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, ""); +			code = curl_easy_setopt(mCurlHandle, CURLOPT_POST, 1); +			check_curl_easy_code(code, CURLOPT_POST); +			code = curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, ""); +			check_curl_easy_code(code, CURLOPT_ENCODING);  			long data_size(0);  			if (mReqBody)  			{  				data_size = mReqBody->size();  			} -			curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDS, static_cast<void *>(NULL)); -			curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDSIZE, data_size); +			code = curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDS, static_cast<void *>(NULL)); +			check_curl_easy_code(code, CURLOPT_POSTFIELDS); +			code = curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDSIZE, data_size); +			check_curl_easy_code(code, CURLOPT_POSTFIELDSIZE);  			mCurlHeaders = curl_slist_append(mCurlHeaders, "Expect:");  			mCurlHeaders = curl_slist_append(mCurlHeaders, "Connection: keep-alive");  			mCurlHeaders = curl_slist_append(mCurlHeaders, "Keep-alive: 300"); @@ -491,14 +530,17 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)  	case HOR_PUT:  		{ -			curl_easy_setopt(mCurlHandle, CURLOPT_UPLOAD, 1); +			code = curl_easy_setopt(mCurlHandle, CURLOPT_UPLOAD, 1); +			check_curl_easy_code(code, CURLOPT_UPLOAD);  			long data_size(0);  			if (mReqBody)  			{  				data_size = mReqBody->size();  			} -			curl_easy_setopt(mCurlHandle, CURLOPT_INFILESIZE, data_size); -			curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDS, (void *) NULL); +			code = curl_easy_setopt(mCurlHandle, CURLOPT_INFILESIZE, data_size); +			check_curl_easy_code(code, CURLOPT_INFILESIZE); +			code = curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDS, (void *) NULL); +			check_curl_easy_code(code, CURLOPT_POSTFIELDS);  			mCurlHeaders = curl_slist_append(mCurlHeaders, "Expect:");  			mCurlHeaders = curl_slist_append(mCurlHeaders, "Connection: keep-alive");  			mCurlHeaders = curl_slist_append(mCurlHeaders, "Keep-alive: 300"); @@ -515,9 +557,12 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)  	// Tracing  	if (mTracing >= HTTP_TRACE_CURL_HEADERS)  	{ -		curl_easy_setopt(mCurlHandle, CURLOPT_VERBOSE, 1); -		curl_easy_setopt(mCurlHandle, CURLOPT_DEBUGDATA, this); -		curl_easy_setopt(mCurlHandle, CURLOPT_DEBUGFUNCTION, debugCallback); +		code = curl_easy_setopt(mCurlHandle, CURLOPT_VERBOSE, 1); +		check_curl_easy_code(code, CURLOPT_VERBOSE); +		code = curl_easy_setopt(mCurlHandle, CURLOPT_DEBUGDATA, this); +		check_curl_easy_code(code, CURLOPT_DEBUGDATA); +		code = curl_easy_setopt(mCurlHandle, CURLOPT_DEBUGFUNCTION, debugCallback); +		check_curl_easy_code(code, CURLOPT_DEBUGFUNCTION);  	}  	// There's a CURLOPT for this now... @@ -557,8 +602,10 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)  	{  		xfer_timeout = timeout;  	} -	curl_easy_setopt(mCurlHandle, CURLOPT_TIMEOUT, xfer_timeout); -	curl_easy_setopt(mCurlHandle, CURLOPT_CONNECTTIMEOUT, timeout); +	code = curl_easy_setopt(mCurlHandle, CURLOPT_TIMEOUT, xfer_timeout); +	check_curl_easy_code(code, CURLOPT_TIMEOUT); +	code = curl_easy_setopt(mCurlHandle, CURLOPT_CONNECTTIMEOUT, timeout); +	check_curl_easy_code(code, CURLOPT_CONNECTTIMEOUT);  	// Request headers  	if (mReqHeaders) @@ -566,12 +613,15 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)  		// Caller's headers last to override  		mCurlHeaders = append_headers_to_slist(mReqHeaders, mCurlHeaders);  	} -	curl_easy_setopt(mCurlHandle, CURLOPT_HTTPHEADER, mCurlHeaders); +	code = curl_easy_setopt(mCurlHandle, CURLOPT_HTTPHEADER, mCurlHeaders); +	check_curl_easy_code(code, CURLOPT_HTTPHEADER);  	if (mProcFlags & (PF_SCAN_RANGE_HEADER | PF_SAVE_HEADERS | PF_USE_RETRY_AFTER))  	{ -		curl_easy_setopt(mCurlHandle, CURLOPT_HEADERFUNCTION, headerCallback); -		curl_easy_setopt(mCurlHandle, CURLOPT_HEADERDATA, this); +		code = curl_easy_setopt(mCurlHandle, CURLOPT_HEADERFUNCTION, headerCallback); +		check_curl_easy_code(code, CURLOPT_HEADERFUNCTION); +		code = curl_easy_setopt(mCurlHandle, CURLOPT_HEADERDATA, this); +		check_curl_easy_code(code, CURLOPT_HEADERDATA);  	}  	if (status) @@ -612,7 +662,7 @@ size_t HttpOpRequest::readCallback(void * data, size_t size, size_t nmemb, void  		{  			// Warn but continue if the read position moves beyond end-of-body  			// for some reason. -			LL_WARNS("HttpCore") << "Request body position beyond body size.  Truncating request body." +			LL_WARNS("CoreHttp") << "Request body position beyond body size.  Truncating request body."  								 << LL_ENDL;  		}  		return 0; @@ -1046,6 +1096,32 @@ char * os_strltrim(char * lstr)  } -}  // end anonymous namespace +void check_curl_easy_code(CURLcode code, int curl_setopt_option) +{ +	if (CURLE_OK != code) +	{ +		// Comment from old llcurl code which may no longer apply: +		// +		// linux appears to throw a curl error once per session for a bad initialization +		// at a pretty random time (when enabling cookies). +		LL_WARNS("CoreHttp") << "libcurl error detected:  " << curl_easy_strerror(code) +							 << ", curl_easy_setopt option:  " << curl_setopt_option +							 << LL_ENDL; +	} +} -		 + +void check_curl_easy_code(CURLcode code) +{ +	if (CURLE_OK != code) +	{ +		// Comment from old llcurl code which may no longer apply: +		// +		// linux appears to throw a curl error once per session for a bad initialization +		// at a pretty random time (when enabling cookies). +		LL_WARNS("CoreHttp") << "libcurl error detected:  " << curl_easy_strerror(code) +							 << LL_ENDL; +	} +} + +}  // end anonymous namespace diff --git a/indra/llcorehttp/httpcommon.cpp b/indra/llcorehttp/httpcommon.cpp index ca57a18578..0cf415223e 100755 --- a/indra/llcorehttp/httpcommon.cpp +++ b/indra/llcorehttp/httpcommon.cpp @@ -70,7 +70,8 @@ std::string HttpStatus::toString() const  			"Invalid datatype for argument or option",  			"Option has not been explicitly set",  			"Option is not dynamic and must be set early", -			"Invalid HTTP status code received from server" +			"Invalid HTTP status code received from server", +			"Could not allocate required resource"  		};  	static const int llcore_errors_count(sizeof(llcore_errors) / sizeof(llcore_errors[0])); diff --git a/indra/llcorehttp/httpcommon.h b/indra/llcorehttp/httpcommon.h index a04b344a9e..3a0bd68108 100755 --- a/indra/llcorehttp/httpcommon.h +++ b/indra/llcorehttp/httpcommon.h @@ -246,7 +246,10 @@ enum HttpError  	HE_OPT_NOT_DYNAMIC = 8,  	// Invalid HTTP status code returned by server -	HE_INVALID_HTTP_STATUS = 9 +	HE_INVALID_HTTP_STATUS = 9, +	 +	// Couldn't allocate resource, typically libcurl handle +	HE_BAD_ALLOC = 10  }; // end enum HttpError diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index f2a3e059ef..5193799ade 100755 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -6,7 +6,7 @@   *   * $LicenseInfo:firstyear=2006&license=viewerlgpl$   * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2010-2013, Linden Research, Inc.   *    * This library is free software; you can redistribute it and/or   * modify it under the terms of the GNU Lesser General Public @@ -293,9 +293,12 @@ LLCurl::Easy* LLCurl::Easy::getEasy()  		return NULL;  	} -	// set no DNS caching as default for all easy handles. This prevents them adopting a -	// multi handles cache if they are added to one. -	CURLcode result = curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0); +	// Enable a brief cache period for now.  This was zero for the longest time +	// which caused some routers grief and generated unneeded traffic.  For the +	// threded resolver, we're using system resolution libraries and non-zero values +	// are preferred.  The c-ares resolver is another matter and it might not +	// track server changes as well. +	CURLcode result = curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_DNS_CACHE_TIMEOUT, 15);  	check_curl_code(result);  	result = curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);  	check_curl_code(result); diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index b55ba758e1..42952909d7 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -78,8 +78,6 @@  #include "netdb.h"  #endif -#include <queue> -  // Purpose  // @@ -235,8 +233,7 @@  //     mUploadWaitList                 none            rw.main.none (upload thread accessing objects)  //     mInventoryQ                     mMeshMutex [4]  rw.main.mMeshMutex, ro.main.none [5]  //     mUploadErrorQ                   mMeshMutex      rw.main.mMeshMutex, rw.any.mMeshMutex -//     mGetMeshCapability              none            rw.main.none [0], ro.any.none -//     mGetMesh2Capability             none            rw.main.none [0], ro.any.none +//     mGetMeshVersion                 none            rw.main.none  //  //   LLMeshRepoThread:  // @@ -255,6 +252,9 @@  //     mUnavailableQ            mMutex        rw.repo.none [0], ro.main.none [5], rw.main.mMutex  //     mLoadedQ                 mMutex        rw.repo.mMutex, ro.main.none [5], rw.main.mMutex  //     mPendingLOD              mMutex        rw.repo.mMutex, rw.any.mMutex +//     mGetMeshCapability       mMutex        rw.main.mMutex, ro.repo.mMutex (was:  [0]) +//     mGetMesh2Capability      mMutex        rw.main.mMutex, ro.repo.mMutex (was:  [0]) +//     mGetMeshVersion          mMutex        rw.main.mMutex, ro.repo.mMutex  //     mHttp*                   none          rw.repo.none  //  // QA/Development Testing @@ -304,7 +304,10 @@  // With this instrumentation enabled, a stall will appear  // under the 'Mesh Fetch' timer which will be either top-level  // or under 'Render' time. + +#ifndef	LL_MESH_FASTTIMER_ENABLE  #define LL_MESH_FASTTIMER_ENABLE		1 +#endif  #if LL_MESH_FASTTIMER_ENABLE  static LLFastTimer::DeclareTimer FTM_MESH_FETCH("Mesh Fetch"); @@ -381,7 +384,6 @@ static S32 dump_num = 0;  std::string make_dump_name(std::string prefix, S32 num)  {  	return prefix + boost::lexical_cast<std::string>(num) + std::string(".xml"); -	  }  void dump_llsd_to_file(const LLSD& content, std::string filename);  LLSD llsd_from_file(std::string filename); @@ -740,7 +742,8 @@ LLMeshRepoThread::LLMeshRepoThread()    mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID),    mHttpLegacyPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID),    mHttpLargePolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID), -  mHttpPriority(0) +  mHttpPriority(0), +  mGetMeshVersion(2)  {   	mMutex = new LLMutex(NULL);  	mHeaderMutex = new LLMutex(NULL); @@ -1047,30 +1050,50 @@ void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod)  	}  } +// Mutex:  must be holding mMutex when called +void LLMeshRepoThread::setGetMeshCaps(const std::string & get_mesh1, +									  const std::string & get_mesh2, +									  int pref_version) +{ +	mGetMeshCapability = get_mesh1; +	mGetMesh2Capability = get_mesh2; +	mGetMeshVersion = pref_version; +} + +  // Constructs a Cap URL for the mesh.  Prefers a GetMesh2 cap  // over a GetMesh cap.  // -//static  -std::string LLMeshRepoThread::constructUrl(LLUUID mesh_id) +// Mutex:  acquires mMutex +void LLMeshRepoThread::constructUrl(LLUUID mesh_id, std::string * url, int * version)  { -	std::string http_url; +	std::string res_url; +	int res_version(2);  	if (gAgent.getRegion())  	{ -		if (! gMeshRepo.mGetMesh2Capability.empty() && gMeshRepo.mGetMeshVersion > 1) +		LLMutexLock lock(mMutex); + +		// Get a consistent pair of (cap string, version).  The +		// locking could be eliminated here without loss of safety +		// by using a set of staging values in setGetMeshCaps(). +		 +		if (! mGetMesh2Capability.empty() && mGetMeshVersion > 1)  		{ -			http_url = gMeshRepo.mGetMesh2Capability; +			res_url = mGetMesh2Capability; +			res_version = 2;  		}  		else  		{ -			http_url = gMeshRepo.mGetMeshCapability; +			res_url = mGetMeshCapability; +			res_version = 1;  		}  	} -	if (!http_url.empty()) +	if (! res_url.empty())  	{ -		http_url += "/?mesh_id="; -		http_url += mesh_id.asString().c_str(); +		res_url += "/?mesh_id="; +		res_url += mesh_id.asString().c_str();  	}  	else  	{ @@ -1078,7 +1101,8 @@ std::string LLMeshRepoThread::constructUrl(LLUUID mesh_id)  								<< mesh_id << ".mesh" << LL_ENDL;  	} -	return http_url; +	*url = res_url; +	*version = res_version;  }  // Issue an HTTP GET request with byte range using the right @@ -1200,8 +1224,10 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)  			}  			//reading from VFS failed for whatever reason, fetch from sim -			int cap_version(gMeshRepo.mGetMeshVersion); -			std::string http_url = constructUrl(mesh_id); +			int cap_version(2); +			std::string http_url; +			constructUrl(mesh_id, &http_url, &cap_version); +  			if (!http_url.empty())  			{  				LLMeshSkinInfoHandler * handler = new LLMeshSkinInfoHandler(mesh_id, offset, size); @@ -1293,8 +1319,10 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)  			}  			//reading from VFS failed for whatever reason, fetch from sim -			int cap_version(gMeshRepo.mGetMeshVersion); -			std::string http_url = constructUrl(mesh_id); +			int cap_version(2); +			std::string http_url; +			constructUrl(mesh_id, &http_url, &cap_version); +			  			if (!http_url.empty())  			{  				LLMeshDecompositionHandler * handler = new LLMeshDecompositionHandler(mesh_id, offset, size); @@ -1384,8 +1412,10 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)  			}  			//reading from VFS failed for whatever reason, fetch from sim -			int cap_version(gMeshRepo.mGetMeshVersion); -			std::string http_url = constructUrl(mesh_id); +			int cap_version(2); +			std::string http_url; +			constructUrl(mesh_id, &http_url, &cap_version); +			  			if (!http_url.empty())  			{  				LLMeshPhysicsShapeHandler * handler = new LLMeshPhysicsShapeHandler(mesh_id, offset, size); @@ -1477,8 +1507,10 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params)  	//either cache entry doesn't exist or is corrupt, request header from simulator	  	bool retval = true; -	int cap_version(gMeshRepo.mGetMeshVersion); -	std::string http_url = constructUrl(mesh_params.getSculptID()); +	int cap_version(2); +	std::string http_url; +	constructUrl(mesh_params.getSculptID(), &http_url, &cap_version); +	  	if (!http_url.empty())  	{  		//grab first 4KB if we're going to bother with a fetch.  Cache will prevent future fetches if a full mesh fits @@ -1563,8 +1595,10 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod)  			}  			//reading from VFS failed for whatever reason, fetch from sim -			int cap_version(gMeshRepo.mGetMeshVersion); -			std::string http_url = constructUrl(mesh_id); +			int cap_version(2); +			std::string http_url; +			constructUrl(mesh_id, &http_url, &cap_version); +			  			if (!http_url.empty())  			{  				LLMeshLODHandler * handler = new LLMeshLODHandler(mesh_params, lod, offset, size); @@ -1812,7 +1846,6 @@ bool LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32  	return true;  } -  LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, LLVector3& scale, bool upload_textures,  									   bool upload_skin, bool upload_joints, const std::string & upload_url, bool do_upload,  									   LLHandle<LLWholeModelFeeObserver> fee_observer, @@ -3249,15 +3282,15 @@ void LLMeshRepository::notifyLoadedMeshes()  			if (gAgent.getRegion()->getName() != region_name && gAgent.getRegion()->capabilitiesReceived())  			{ -				const bool use_v1(gSavedSettings.getBOOL("MeshUseGetMesh1")); -  				region_name = gAgent.getRegion()->getName(); -				mGetMeshCapability = gAgent.getRegion()->getCapability("GetMesh"); -				mGetMesh2Capability = gAgent.getRegion()->getCapability("GetMesh2"); -				mGetMeshVersion = (mGetMesh2Capability.empty() || use_v1) ? 1 : 2; +				const bool use_v1(gSavedSettings.getBOOL("MeshUseGetMesh1")); +				const std::string mesh1(gAgent.getRegion()->getCapability("GetMesh")); +				const std::string mesh2(gAgent.getRegion()->getCapability("GetMesh2")); +				mGetMeshVersion = (mesh2.empty() || use_v1) ? 1 : 2; +				mThread->setGetMeshCaps(mesh1, mesh2, mGetMeshVersion);  				LL_DEBUGS(LOG_MESH) << "Retrieving caps for region '" << region_name -									<< "', GetMesh2:  " << mGetMesh2Capability -									<< ", GetMesh:  " << mGetMeshCapability +									<< "', GetMesh2:  " << mesh2 +									<< ", GetMesh:  " << mesh1  									<< ", using version:  " << mGetMeshVersion  									<< LL_ENDL;  			} diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index e09f39f7a8..9d8b102110 100755 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -333,7 +333,9 @@ public:  	typedef std::set<LLCore::HttpHandler *> http_request_set;  	http_request_set					mHttpRequestSet;			// Outstanding HTTP requests -	static std::string constructUrl(LLUUID mesh_id); +	std::string mGetMeshCapability; +	std::string mGetMesh2Capability; +	int mGetMeshVersion;  	LLMeshRepoThread();  	~LLMeshRepoThread(); @@ -376,6 +378,17 @@ public:  	static void incActiveHeaderRequests();  	static void decActiveHeaderRequests(); +	// Set the caps strings and preferred version for constructing +	// mesh fetch URLs. +	// +	// Mutex:  must be holding mMutex when called +	void setGetMeshCaps(const std::string & get_mesh1, +						const std::string & get_mesh2, +						int pref_version); + +	// Mutex:  acquires mMutex +	void constructUrl(LLUUID mesh_id, std::string * url, int * version); +  private:  	// Issue a GET request to a URL with 'Range' header using  	// the correct policy class and other attributes.  If an invalid @@ -613,9 +626,7 @@ public:  	void uploadError(LLSD& args);  	void updateInventory(inventory_data data); -	std::string mGetMeshCapability; -	std::string mGetMesh2Capability; -	int mGetMeshVersion; +	int mGetMeshVersion;		// Shadows value in LLMeshRepoThread  };  extern LLMeshRepository gMeshRepo; | 
