PageRenderTime 127ms CodeModel.GetById 33ms app.highlight 84ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llmessage/llcurl.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1587 lines | 1217 code | 242 blank | 128 comment | 155 complexity | bcd73087808e9db48ade5837b22e3515 MD5 | raw file
   1/**
   2 * @file llcurl.cpp
   3 * @author Zero / Donovan
   4 * @date 2006-10-15
   5 * @brief Implementation of wrapper around libcurl.
   6 *
   7 * $LicenseInfo:firstyear=2006&license=viewerlgpl$
   8 * Second Life Viewer Source Code
   9 * Copyright (C) 2010, Linden Research, Inc.
  10 * 
  11 * This library is free software; you can redistribute it and/or
  12 * modify it under the terms of the GNU Lesser General Public
  13 * License as published by the Free Software Foundation;
  14 * version 2.1 of the License only.
  15 * 
  16 * This library is distributed in the hope that it will be useful,
  17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  19 * Lesser General Public License for more details.
  20 * 
  21 * You should have received a copy of the GNU Lesser General Public
  22 * License along with this library; if not, write to the Free Software
  23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  24 * 
  25 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  26 * $/LicenseInfo$
  27 */
  28
  29#if LL_WINDOWS
  30#define SAFE_SSL 1
  31#elif LL_DARWIN
  32#define SAFE_SSL 1
  33#else
  34#define SAFE_SSL 1
  35#endif
  36
  37#include "linden_common.h"
  38
  39#include "llcurl.h"
  40
  41#include <algorithm>
  42#include <iomanip>
  43#include <curl/curl.h>
  44#if SAFE_SSL
  45#include <openssl/crypto.h>
  46#endif
  47
  48#include "llbufferstream.h"
  49#include "llproxy.h"
  50#include "llsdserialize.h"
  51#include "llstl.h"
  52#include "llthread.h"
  53#include "lltimer.h"
  54
  55//////////////////////////////////////////////////////////////////////////////
  56/*
  57	The trick to getting curl to do keep-alives is to reuse the
  58	same easy handle for the requests.  It appears that curl
  59	keeps a pool of connections alive for each easy handle, but
  60	doesn't share them between easy handles.  Therefore it is
  61	important to keep a pool of easy handles and reuse them,
  62	rather than create and destroy them with each request.  This
  63	code does this.
  64
  65	Furthermore, it would behoove us to keep track of which
  66	hosts an easy handle was used for and pick an easy handle
  67	that matches the next request.  This code does not current
  68	do this.
  69 */
  70
  71//////////////////////////////////////////////////////////////////////////////
  72
  73static const U32 EASY_HANDLE_POOL_SIZE		= 5;
  74static const S32 MULTI_PERFORM_CALL_REPEAT	= 5;
  75static const S32 CURL_REQUEST_TIMEOUT = 30; // seconds per operation
  76static const S32 MAX_ACTIVE_REQUEST_COUNT = 100;
  77
  78// DEBUG //
  79S32 gCurlEasyCount = 0;
  80S32 gCurlMultiCount = 0;
  81
  82//////////////////////////////////////////////////////////////////////////////
  83
  84//static
  85std::vector<LLMutex*> LLCurl::sSSLMutex;
  86std::string LLCurl::sCAPath;
  87std::string LLCurl::sCAFile;
  88LLCurlThread* LLCurl::sCurlThread = NULL ;
  89LLMutex* LLCurl::sHandleMutexp = NULL ;
  90S32      LLCurl::sTotalHandles = 0 ;
  91bool     LLCurl::sNotQuitting = true;
  92F32      LLCurl::sCurlRequestTimeOut = 120.f; //seonds
  93S32      LLCurl::sMaxHandles = 256; //max number of handles, (multi handles and easy handles combined).
  94
  95void check_curl_code(CURLcode code)
  96{
  97	if (code != CURLE_OK)
  98	{
  99		// linux appears to throw a curl error once per session for a bad initialization
 100		// at a pretty random time (when enabling cookies).
 101		llinfos << "curl error detected: " << curl_easy_strerror(code) << llendl;
 102	}
 103}
 104
 105void check_curl_multi_code(CURLMcode code) 
 106{
 107	if (code != CURLM_OK)
 108	{
 109		// linux appears to throw a curl error once per session for a bad initialization
 110		// at a pretty random time (when enabling cookies).
 111		llinfos << "curl multi error detected: " << curl_multi_strerror(code) << llendl;
 112	}
 113}
 114
 115//static
 116void LLCurl::setCAPath(const std::string& path)
 117{
 118	sCAPath = path;
 119}
 120
 121//static
 122void LLCurl::setCAFile(const std::string& file)
 123{
 124	sCAFile = file;
 125}
 126
 127//static
 128std::string LLCurl::getVersionString()
 129{
 130	return std::string(curl_version());
 131}
 132
 133//////////////////////////////////////////////////////////////////////////////
 134
 135LLCurl::Responder::Responder()
 136	: mReferenceCount(0)
 137{
 138}
 139
 140LLCurl::Responder::~Responder()
 141{
 142}
 143
 144// virtual
 145void LLCurl::Responder::errorWithContent(
 146	U32 status,
 147	const std::string& reason,
 148	const LLSD&)
 149{
 150	error(status, reason);
 151}
 152
 153// virtual
 154void LLCurl::Responder::error(U32 status, const std::string& reason)
 155{
 156	llinfos << mURL << " [" << status << "]: " << reason << llendl;
 157}
 158
 159// virtual
 160void LLCurl::Responder::result(const LLSD& content)
 161{
 162}
 163
 164void LLCurl::Responder::setURL(const std::string& url)
 165{
 166	mURL = url;
 167}
 168
 169// virtual
 170void LLCurl::Responder::completedRaw(
 171	U32 status,
 172	const std::string& reason,
 173	const LLChannelDescriptors& channels,
 174	const LLIOPipe::buffer_ptr_t& buffer)
 175{
 176	LLSD content;
 177	LLBufferStream istr(channels, buffer.get());
 178	if (!LLSDSerialize::fromXML(content, istr))
 179	{
 180		llinfos << "Failed to deserialize LLSD. " << mURL << " [" << status << "]: " << reason << llendl;
 181	}
 182
 183	completed(status, reason, content);
 184}
 185
 186// virtual
 187void LLCurl::Responder::completed(U32 status, const std::string& reason, const LLSD& content)
 188{
 189	if (isGoodStatus(status))
 190	{
 191		result(content);
 192	}
 193	else
 194	{
 195		errorWithContent(status, reason, content);
 196	}
 197}
 198
 199//virtual
 200void LLCurl::Responder::completedHeader(U32 status, const std::string& reason, const LLSD& content)
 201{
 202
 203}
 204
 205namespace boost
 206{
 207	void intrusive_ptr_add_ref(LLCurl::Responder* p)
 208	{
 209		++p->mReferenceCount;
 210	}
 211	
 212	void intrusive_ptr_release(LLCurl::Responder* p)
 213	{
 214		if (p && 0 == --p->mReferenceCount)
 215		{
 216			delete p;
 217		}
 218	}
 219};
 220
 221
 222//////////////////////////////////////////////////////////////////////////////
 223
 224std::set<CURL*> LLCurl::Easy::sFreeHandles;
 225std::set<CURL*> LLCurl::Easy::sActiveHandles;
 226LLMutex* LLCurl::Easy::sHandleMutexp = NULL ;
 227
 228//static
 229CURL* LLCurl::Easy::allocEasyHandle()
 230{
 231	llassert(LLCurl::getCurlThread()) ;
 232
 233	CURL* ret = NULL;
 234
 235	LLMutexLock lock(sHandleMutexp) ;
 236
 237	if (sFreeHandles.empty())
 238	{
 239		ret = LLCurl::newEasyHandle();
 240	}
 241	else
 242	{
 243		ret = *(sFreeHandles.begin());
 244		sFreeHandles.erase(ret);
 245		curl_easy_reset(ret);
 246	}
 247
 248	if (ret)
 249	{
 250		sActiveHandles.insert(ret);
 251	}
 252
 253	return ret;
 254}
 255
 256//static
 257void LLCurl::Easy::releaseEasyHandle(CURL* handle)
 258{
 259	static const S32 MAX_NUM_FREE_HANDLES = 32 ;
 260
 261	if (!handle)
 262	{
 263		return ; //handle allocation failed.
 264		//llerrs << "handle cannot be NULL!" << llendl;
 265	}
 266
 267	LLMutexLock lock(sHandleMutexp) ;
 268	if (sActiveHandles.find(handle) != sActiveHandles.end())
 269	{
 270		sActiveHandles.erase(handle);
 271
 272		if(sFreeHandles.size() < MAX_NUM_FREE_HANDLES)
 273		{
 274			sFreeHandles.insert(handle);
 275		}
 276		else
 277		{
 278			LLCurl::deleteEasyHandle(handle) ;
 279		}
 280	}
 281	else
 282	{
 283		llerrs << "Invalid handle." << llendl;
 284	}
 285}
 286
 287LLCurl::Easy::Easy()
 288	: mHeaders(NULL),
 289	  mCurlEasyHandle(NULL)
 290{
 291	mErrorBuffer[0] = 0;
 292}
 293
 294LLCurl::Easy* LLCurl::Easy::getEasy()
 295{
 296	Easy* easy = new Easy();
 297	easy->mCurlEasyHandle = allocEasyHandle(); 
 298	
 299	if (!easy->mCurlEasyHandle)
 300	{
 301		// this can happen if we have too many open files (fails in c-ares/ares_init.c)
 302		llwarns << "allocEasyHandle() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << llendl;
 303		delete easy;
 304		return NULL;
 305	}
 306	
 307	// set no DNS caching as default for all easy handles. This prevents them adopting a
 308	// multi handles cache if they are added to one.
 309	CURLcode result = curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0);
 310	check_curl_code(result);
 311	
 312	++gCurlEasyCount;
 313	return easy;
 314}
 315
 316LLCurl::Easy::~Easy()
 317{
 318	releaseEasyHandle(mCurlEasyHandle);
 319	--gCurlEasyCount;
 320	curl_slist_free_all(mHeaders);
 321	for_each(mStrings.begin(), mStrings.end(), DeletePointerArray());
 322
 323	if (mResponder && LLCurl::sNotQuitting) //aborted
 324	{	
 325		std::string reason("Request timeout, aborted.") ;
 326		mResponder->completedRaw(408, //HTTP_REQUEST_TIME_OUT, timeout, abort
 327			reason, mChannels, mOutput);		
 328	}
 329	mResponder = NULL;
 330}
 331
 332void LLCurl::Easy::resetState()
 333{
 334 	curl_easy_reset(mCurlEasyHandle);
 335
 336	if (mHeaders)
 337	{
 338		curl_slist_free_all(mHeaders);
 339		mHeaders = NULL;
 340	}
 341
 342	mRequest.str("");
 343	mRequest.clear();
 344
 345	mOutput.reset();
 346	
 347	mInput.str("");
 348	mInput.clear();
 349	
 350	mErrorBuffer[0] = 0;
 351	
 352	mHeaderOutput.str("");
 353	mHeaderOutput.clear();
 354}
 355
 356void LLCurl::Easy::setErrorBuffer()
 357{
 358	setopt(CURLOPT_ERRORBUFFER, &mErrorBuffer);
 359}
 360
 361const char* LLCurl::Easy::getErrorBuffer()
 362{
 363	return mErrorBuffer;
 364}
 365
 366void LLCurl::Easy::setCA()
 367{
 368	if (!sCAPath.empty())
 369	{
 370		setoptString(CURLOPT_CAPATH, sCAPath);
 371	}
 372	if (!sCAFile.empty())
 373	{
 374		setoptString(CURLOPT_CAINFO, sCAFile);
 375	}
 376}
 377
 378void LLCurl::Easy::setHeaders()
 379{
 380	setopt(CURLOPT_HTTPHEADER, mHeaders);
 381}
 382
 383void LLCurl::Easy::getTransferInfo(LLCurl::TransferInfo* info)
 384{
 385	check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SIZE_DOWNLOAD, &info->mSizeDownload));
 386	check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_TOTAL_TIME, &info->mTotalTime));
 387	check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SPEED_DOWNLOAD, &info->mSpeedDownload));
 388}
 389
 390U32 LLCurl::Easy::report(CURLcode code)
 391{
 392	U32 responseCode = 0;	
 393	std::string responseReason;
 394	
 395	if (code == CURLE_OK)
 396	{
 397		check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_RESPONSE_CODE, &responseCode));
 398		//*TODO: get reason from first line of mHeaderOutput
 399	}
 400	else
 401	{
 402		responseCode = 499;
 403		responseReason = strerror(code) + " : " + mErrorBuffer;
 404		setopt(CURLOPT_FRESH_CONNECT, TRUE);
 405	}
 406
 407	if (mResponder)
 408	{	
 409		mResponder->completedRaw(responseCode, responseReason, mChannels, mOutput);
 410		mResponder = NULL;
 411	}
 412	
 413	resetState();
 414	return responseCode;
 415}
 416
 417// Note: these all assume the caller tracks the value (i.e. keeps it persistant)
 418void LLCurl::Easy::setopt(CURLoption option, S32 value)
 419{
 420	CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, value);
 421	check_curl_code(result);
 422}
 423
 424void LLCurl::Easy::setopt(CURLoption option, void* value)
 425{
 426	CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, value);
 427	check_curl_code(result);
 428}
 429
 430void LLCurl::Easy::setopt(CURLoption option, char* value)
 431{
 432	CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, value);
 433	check_curl_code(result);
 434}
 435
 436// Note: this copies the string so that the caller does not have to keep it around
 437void LLCurl::Easy::setoptString(CURLoption option, const std::string& value)
 438{
 439	char* tstring = new char[value.length()+1];
 440	strcpy(tstring, value.c_str());
 441	mStrings.push_back(tstring);
 442	CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, tstring);
 443	check_curl_code(result);
 444}
 445
 446void LLCurl::Easy::slist_append(const char* str)
 447{
 448	mHeaders = curl_slist_append(mHeaders, str);
 449}
 450
 451size_t curlReadCallback(char* data, size_t size, size_t nmemb, void* user_data)
 452{
 453	LLCurl::Easy* easy = (LLCurl::Easy*)user_data;
 454	
 455	S32 n = size * nmemb;
 456	S32 startpos = easy->getInput().tellg();
 457	easy->getInput().seekg(0, std::ios::end);
 458	S32 endpos = easy->getInput().tellg();
 459	easy->getInput().seekg(startpos, std::ios::beg);
 460	S32 maxn = endpos - startpos;
 461	n = llmin(n, maxn);
 462	easy->getInput().read((char*)data, n);
 463
 464	return n;
 465}
 466
 467size_t curlWriteCallback(char* data, size_t size, size_t nmemb, void* user_data)
 468{
 469	LLCurl::Easy* easy = (LLCurl::Easy*)user_data;
 470	
 471	S32 n = size * nmemb;
 472	easy->getOutput()->append(easy->getChannels().in(), (const U8*)data, n);
 473
 474	return n;
 475}
 476
 477size_t curlHeaderCallback(void* data, size_t size, size_t nmemb, void* user_data)
 478{
 479	LLCurl::Easy* easy = (LLCurl::Easy*)user_data;
 480	
 481	size_t n = size * nmemb;
 482	easy->getHeaderOutput().write((const char*)data, n);
 483
 484	return n;
 485}
 486
 487void LLCurl::Easy::prepRequest(const std::string& url,
 488							   const std::vector<std::string>& headers,
 489							   ResponderPtr responder, S32 time_out, bool post)
 490{
 491	resetState();
 492	
 493	if (post) setoptString(CURLOPT_ENCODING, "");
 494
 495	//setopt(CURLOPT_VERBOSE, 1); // useful for debugging
 496	setopt(CURLOPT_NOSIGNAL, 1);
 497
 498	// Set the CURL options for either Socks or HTTP proxy
 499	LLProxy::getInstance()->applyProxySettings(this);
 500
 501	mOutput.reset(new LLBufferArray);
 502	mOutput->setThreaded(true);
 503	setopt(CURLOPT_WRITEFUNCTION, (void*)&curlWriteCallback);
 504	setopt(CURLOPT_WRITEDATA, (void*)this);
 505
 506	setopt(CURLOPT_READFUNCTION, (void*)&curlReadCallback);
 507	setopt(CURLOPT_READDATA, (void*)this);
 508	
 509	setopt(CURLOPT_HEADERFUNCTION, (void*)&curlHeaderCallback);
 510	setopt(CURLOPT_HEADERDATA, (void*)this);
 511
 512	// Allow up to five redirects
 513	if (responder && responder->followRedir())
 514	{
 515		setopt(CURLOPT_FOLLOWLOCATION, 1);
 516		setopt(CURLOPT_MAXREDIRS, MAX_REDIRECTS);
 517	}
 518
 519	setErrorBuffer();
 520	setCA();
 521
 522	setopt(CURLOPT_SSL_VERIFYPEER, true);
 523	
 524	//don't verify host name so urls with scrubbed host names will work (improves DNS performance)
 525	setopt(CURLOPT_SSL_VERIFYHOST, 0);
 526	setopt(CURLOPT_TIMEOUT, llmax(time_out, CURL_REQUEST_TIMEOUT));
 527
 528	setoptString(CURLOPT_URL, url);
 529
 530	mResponder = responder;
 531
 532	if (!post)
 533	{
 534		slist_append("Connection: keep-alive");
 535		slist_append("Keep-alive: 300");
 536		// Accept and other headers
 537		for (std::vector<std::string>::const_iterator iter = headers.begin();
 538			 iter != headers.end(); ++iter)
 539		{
 540			slist_append((*iter).c_str());
 541		}
 542	}
 543}
 544
 545////////////////////////////////////////////////////////////////////////////
 546LLCurl::Multi::Multi(F32 idle_time_out)
 547	: mQueued(0),
 548	  mErrorCount(0),
 549	  mState(STATE_READY),
 550	  mDead(FALSE),
 551	  mMutexp(NULL),
 552	  mDeletionMutexp(NULL),
 553	  mEasyMutexp(NULL)
 554{
 555	mCurlMultiHandle = LLCurl::newMultiHandle();
 556	if (!mCurlMultiHandle)
 557	{
 558		llwarns << "curl_multi_init() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << llendl;
 559		mCurlMultiHandle = LLCurl::newMultiHandle();
 560	}
 561	
 562	//llassert_always(mCurlMultiHandle);	
 563	
 564	if(mCurlMultiHandle)
 565	{
 566		if(LLCurl::getCurlThread()->getThreaded())
 567		{
 568			mMutexp = new LLMutex(NULL) ;
 569			mDeletionMutexp = new LLMutex(NULL) ;
 570			mEasyMutexp = new LLMutex(NULL) ;
 571		}
 572		LLCurl::getCurlThread()->addMulti(this) ;
 573
 574		mIdleTimeOut = idle_time_out ;
 575		if(mIdleTimeOut < LLCurl::sCurlRequestTimeOut)
 576		{
 577			mIdleTimeOut = LLCurl::sCurlRequestTimeOut ;
 578		}
 579
 580		++gCurlMultiCount;
 581	}
 582}
 583
 584LLCurl::Multi::~Multi()
 585{
 586	cleanup() ;	
 587}
 588
 589void LLCurl::Multi::cleanup()
 590{
 591	if(!mCurlMultiHandle)
 592	{
 593		return ; //nothing to clean.
 594	}
 595
 596	// Clean up active
 597	for(easy_active_list_t::iterator iter = mEasyActiveList.begin();
 598		iter != mEasyActiveList.end(); ++iter)
 599	{
 600		Easy* easy = *iter;
 601		check_curl_multi_code(curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle()));
 602		delete easy;
 603	}
 604	mEasyActiveList.clear();
 605	mEasyActiveMap.clear();
 606	
 607	// Clean up freed
 608	for_each(mEasyFreeList.begin(), mEasyFreeList.end(), DeletePointer());	
 609	mEasyFreeList.clear();
 610
 611	check_curl_multi_code(LLCurl::deleteMultiHandle(mCurlMultiHandle));
 612	mCurlMultiHandle = NULL ;
 613
 614	delete mMutexp ;
 615	mMutexp = NULL ;
 616	delete mDeletionMutexp ;
 617	mDeletionMutexp = NULL ;
 618	delete mEasyMutexp ;
 619	mEasyMutexp = NULL ;
 620	
 621	mQueued = 0 ;
 622	mState = STATE_COMPLETED;
 623	
 624	--gCurlMultiCount;
 625
 626	return ;
 627}
 628
 629void LLCurl::Multi::lock()
 630{
 631	if(mMutexp)
 632	{
 633		mMutexp->lock() ;
 634	}
 635}
 636
 637void LLCurl::Multi::unlock()
 638{
 639	if(mMutexp)
 640	{
 641		mMutexp->unlock() ;
 642	}
 643}
 644
 645void LLCurl::Multi::markDead()
 646{
 647	LLMutexLock lock(mDeletionMutexp) ;
 648	
 649	mDead = TRUE ;
 650	LLCurl::getCurlThread()->setPriority(mHandle, LLQueuedThread::PRIORITY_URGENT) ; 
 651}
 652
 653void LLCurl::Multi::setState(LLCurl::Multi::ePerformState state)
 654{
 655	lock() ;
 656	mState = state ;
 657	unlock() ;
 658
 659	if(mState == STATE_READY)
 660	{
 661		LLCurl::getCurlThread()->setPriority(mHandle, LLQueuedThread::PRIORITY_NORMAL) ;
 662	}	
 663}
 664
 665LLCurl::Multi::ePerformState LLCurl::Multi::getState()
 666{
 667	return mState;
 668}
 669	
 670bool LLCurl::Multi::isCompleted() 
 671{
 672	return STATE_COMPLETED == getState() ;
 673}
 674
 675bool LLCurl::Multi::waitToComplete()
 676{
 677	if(!isValid())
 678	{
 679		return true ;
 680	}
 681
 682	if(!mMutexp) //not threaded
 683	{
 684		doPerform() ;
 685		return true ;
 686	}
 687
 688	bool completed = (STATE_COMPLETED == mState) ;
 689	if(!completed)
 690	{
 691		LLCurl::getCurlThread()->setPriority(mHandle, LLQueuedThread::PRIORITY_HIGH) ;
 692	}
 693	
 694	return completed;
 695}
 696
 697CURLMsg* LLCurl::Multi::info_read(S32* msgs_in_queue)
 698{
 699	LLMutexLock lock(mMutexp) ;
 700
 701	CURLMsg* curlmsg = curl_multi_info_read(mCurlMultiHandle, msgs_in_queue);
 702	return curlmsg;
 703}
 704
 705//return true if dead
 706bool LLCurl::Multi::doPerform()
 707{
 708	LLMutexLock lock(mDeletionMutexp) ;
 709	
 710	bool dead = mDead ;
 711
 712	if(mDead)
 713	{
 714		setState(STATE_COMPLETED);
 715		mQueued = 0 ;
 716	}
 717	else if(getState() != STATE_COMPLETED)
 718	{		
 719		setState(STATE_PERFORMING);
 720
 721		S32 q = 0;
 722		for (S32 call_count = 0;
 723				call_count < MULTI_PERFORM_CALL_REPEAT;
 724				call_count++)
 725		{
 726			LLMutexLock lock(mMutexp) ;
 727
 728			//WARNING: curl_multi_perform will block for many hundreds of milliseconds
 729			// NEVER call this from the main thread, and NEVER allow the main thread to 
 730			// wait on a mutex held by this thread while curl_multi_perform is executing
 731			CURLMcode code = curl_multi_perform(mCurlMultiHandle, &q);
 732			if (CURLM_CALL_MULTI_PERFORM != code || q == 0)
 733			{
 734				check_curl_multi_code(code);
 735			
 736				break;
 737			}
 738		}
 739
 740		mQueued = q;	
 741		setState(STATE_COMPLETED) ;		
 742		mIdleTimer.reset() ;
 743	}
 744	else if(mIdleTimer.getElapsedTimeF32() > mIdleTimeOut) //idle for too long, remove it.
 745	{
 746		dead = true ;
 747	}
 748
 749	return dead ;
 750}
 751
 752S32 LLCurl::Multi::process()
 753{
 754	if(!isValid())
 755	{
 756		return 0 ;
 757	}
 758
 759	waitToComplete() ;
 760
 761	if (getState() != STATE_COMPLETED)
 762	{
 763		return 0;
 764	}
 765
 766	CURLMsg* msg;
 767	int msgs_in_queue;
 768
 769	S32 processed = 0;
 770	while ((msg = info_read(&msgs_in_queue)))
 771	{
 772		++processed;
 773		if (msg->msg == CURLMSG_DONE)
 774		{
 775			U32 response = 0;
 776			Easy* easy = NULL ;
 777
 778			{
 779				LLMutexLock lock(mEasyMutexp) ;
 780				easy_active_map_t::iterator iter = mEasyActiveMap.find(msg->easy_handle);
 781				if (iter != mEasyActiveMap.end())
 782				{
 783					easy = iter->second;
 784				}
 785			}
 786
 787			if(easy)
 788			{
 789				response = easy->report(msg->data.result);
 790				removeEasy(easy);
 791			}
 792			else
 793			{
 794				response = 499;
 795				//*TODO: change to llwarns
 796				llerrs << "cleaned up curl request completed!" << llendl;
 797			}
 798			if (response >= 400)
 799			{
 800				// failure of some sort, inc mErrorCount for debugging and flagging multi for destruction
 801				++mErrorCount;
 802			}
 803		}
 804	}
 805
 806	setState(STATE_READY);
 807
 808	return processed;
 809}
 810
 811LLCurl::Easy* LLCurl::Multi::allocEasy()
 812{
 813	Easy* easy = 0;	
 814
 815	if (mEasyFreeList.empty())
 816	{		
 817		easy = Easy::getEasy();
 818	}
 819	else
 820	{
 821		LLMutexLock lock(mEasyMutexp) ;
 822		easy = *(mEasyFreeList.begin());
 823		mEasyFreeList.erase(easy);
 824	}
 825	if (easy)
 826	{
 827		LLMutexLock lock(mEasyMutexp) ;
 828		mEasyActiveList.insert(easy);
 829		mEasyActiveMap[easy->getCurlHandle()] = easy;
 830	}
 831	return easy;
 832}
 833
 834bool LLCurl::Multi::addEasy(Easy* easy)
 835{
 836	LLMutexLock lock(mMutexp) ;
 837	CURLMcode mcode = curl_multi_add_handle(mCurlMultiHandle, easy->getCurlHandle());
 838	check_curl_multi_code(mcode);
 839	//if (mcode != CURLM_OK)
 840	//{
 841	//	llwarns << "Curl Error: " << curl_multi_strerror(mcode) << llendl;
 842	//	return false;
 843	//}
 844	return true;
 845}
 846
 847void LLCurl::Multi::easyFree(Easy* easy)
 848{
 849	if(mEasyMutexp)
 850	{
 851		mEasyMutexp->lock() ;
 852	}
 853
 854	mEasyActiveList.erase(easy);
 855	mEasyActiveMap.erase(easy->getCurlHandle());
 856
 857	if (mEasyFreeList.size() < EASY_HANDLE_POOL_SIZE)
 858	{		
 859		mEasyFreeList.insert(easy);
 860		
 861		if(mEasyMutexp)
 862		{
 863			mEasyMutexp->unlock() ;
 864		}
 865
 866		easy->resetState();
 867	}
 868	else
 869	{
 870		if(mEasyMutexp)
 871		{
 872			mEasyMutexp->unlock() ;
 873		}
 874		delete easy;
 875	}
 876}
 877
 878void LLCurl::Multi::removeEasy(Easy* easy)
 879{
 880	{
 881		LLMutexLock lock(mMutexp) ;
 882		check_curl_multi_code(curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle()));
 883	}
 884	easyFree(easy);
 885}
 886
 887//------------------------------------------------------------
 888//LLCurlThread
 889LLCurlThread::CurlRequest::CurlRequest(handle_t handle, LLCurl::Multi* multi, LLCurlThread* curl_thread) :
 890	LLQueuedThread::QueuedRequest(handle, LLQueuedThread::PRIORITY_NORMAL, FLAG_AUTO_COMPLETE),
 891	mMulti(multi),
 892	mCurlThread(curl_thread)
 893{	
 894}
 895
 896LLCurlThread::CurlRequest::~CurlRequest()
 897{	
 898	if(mMulti)
 899	{
 900		mCurlThread->deleteMulti(mMulti) ;
 901		mMulti = NULL ;
 902	}
 903}
 904
 905bool LLCurlThread::CurlRequest::processRequest()
 906{
 907	bool completed = true ;
 908	if(mMulti)
 909	{
 910		completed = mCurlThread->doMultiPerform(mMulti) ;
 911
 912		if(!completed)
 913		{
 914			setPriority(LLQueuedThread::PRIORITY_LOW) ;
 915		}
 916	}
 917
 918	return completed ;
 919}
 920
 921void LLCurlThread::CurlRequest::finishRequest(bool completed)
 922{
 923	if(mMulti->isDead())
 924	{
 925		mCurlThread->deleteMulti(mMulti) ;
 926	}
 927	else
 928	{
 929		mCurlThread->cleanupMulti(mMulti) ; //being idle too long, remove the request.
 930	}
 931
 932	mMulti = NULL ;
 933}
 934	
 935LLCurlThread::LLCurlThread(bool threaded) :
 936	LLQueuedThread("curlthread", threaded)
 937{
 938}
 939	
 940//virtual 
 941LLCurlThread::~LLCurlThread() 
 942{
 943}
 944
 945S32 LLCurlThread::update(F32 max_time_ms)
 946{	
 947	return LLQueuedThread::update(max_time_ms);
 948}
 949
 950void LLCurlThread::addMulti(LLCurl::Multi* multi)
 951{
 952	multi->mHandle = generateHandle() ;
 953
 954	CurlRequest* req = new CurlRequest(multi->mHandle, multi, this) ;
 955
 956	if (!addRequest(req))
 957	{
 958		llwarns << "curl request added when the thread is quitted" << llendl;
 959	}
 960}
 961	
 962void LLCurlThread::killMulti(LLCurl::Multi* multi)
 963{
 964	if(!multi)
 965	{
 966		return ;
 967	}
 968
 969	if(multi->isValid())
 970	{
 971		multi->markDead() ;
 972	}
 973	else
 974	{
 975		deleteMulti(multi) ;
 976	}
 977}
 978
 979//private
 980bool LLCurlThread::doMultiPerform(LLCurl::Multi* multi) 
 981{
 982	return multi->doPerform() ;
 983}
 984
 985//private
 986void LLCurlThread::deleteMulti(LLCurl::Multi* multi) 
 987{
 988	delete multi ;
 989}
 990
 991//private
 992void LLCurlThread::cleanupMulti(LLCurl::Multi* multi) 
 993{
 994	multi->cleanup() ;
 995}
 996
 997//------------------------------------------------------------
 998
 999//static
1000std::string LLCurl::strerror(CURLcode errorcode)
1001{
1002	return std::string(curl_easy_strerror(errorcode));
1003}
1004
1005////////////////////////////////////////////////////////////////////////////
1006// For generating a simple request for data
1007// using one multi and one easy per request 
1008
1009LLCurlRequest::LLCurlRequest() :
1010	mActiveMulti(NULL),
1011	mActiveRequestCount(0)
1012{
1013	mProcessing = FALSE;
1014}
1015
1016LLCurlRequest::~LLCurlRequest()
1017{
1018	//stop all Multi handle background threads
1019	for (curlmulti_set_t::iterator iter = mMultiSet.begin(); iter != mMultiSet.end(); ++iter)
1020	{
1021		LLCurl::getCurlThread()->killMulti(*iter) ;
1022	}
1023	mMultiSet.clear() ;
1024}
1025
1026void LLCurlRequest::addMulti()
1027{
1028	LLCurl::Multi* multi = new LLCurl::Multi();
1029	if(!multi->isValid())
1030	{
1031		LLCurl::getCurlThread()->killMulti(multi) ;
1032		mActiveMulti = NULL ;
1033		mActiveRequestCount = 0 ;
1034		return;
1035	}
1036
1037	mMultiSet.insert(multi);
1038	mActiveMulti = multi;
1039	mActiveRequestCount = 0;
1040}
1041
1042LLCurl::Easy* LLCurlRequest::allocEasy()
1043{
1044	if (!mActiveMulti ||
1045		mActiveRequestCount	>= MAX_ACTIVE_REQUEST_COUNT ||
1046		mActiveMulti->mErrorCount > 0)
1047	{
1048		addMulti();
1049	}
1050	if(!mActiveMulti)
1051	{
1052		return NULL ;
1053	}
1054
1055	//llassert_always(mActiveMulti);
1056	++mActiveRequestCount;
1057	LLCurl::Easy* easy = mActiveMulti->allocEasy();
1058	return easy;
1059}
1060
1061bool LLCurlRequest::addEasy(LLCurl::Easy* easy)
1062{
1063	llassert_always(mActiveMulti);
1064	
1065	if (mProcessing)
1066	{
1067		llerrs << "Posting to a LLCurlRequest instance from within a responder is not allowed (causes DNS timeouts)." << llendl;
1068	}
1069	bool res = mActiveMulti->addEasy(easy);
1070	return res;
1071}
1072
1073void LLCurlRequest::get(const std::string& url, LLCurl::ResponderPtr responder)
1074{
1075	getByteRange(url, headers_t(), 0, -1, responder);
1076}
1077	
1078bool LLCurlRequest::getByteRange(const std::string& url,
1079								 const headers_t& headers,
1080								 S32 offset, S32 length,
1081								 LLCurl::ResponderPtr responder)
1082{
1083	LLCurl::Easy* easy = allocEasy();
1084	if (!easy)
1085	{
1086		return false;
1087	}
1088	easy->prepRequest(url, headers, responder);
1089	easy->setopt(CURLOPT_HTTPGET, 1);
1090	if (length > 0)
1091	{
1092		std::string range = llformat("Range: bytes=%d-%d", offset,offset+length-1);
1093		easy->slist_append(range.c_str());
1094	}
1095	easy->setHeaders();
1096	bool res = addEasy(easy);
1097	return res;
1098}
1099
1100bool LLCurlRequest::post(const std::string& url,
1101						 const headers_t& headers,
1102						 const LLSD& data,
1103						 LLCurl::ResponderPtr responder, S32 time_out)
1104{
1105	LLCurl::Easy* easy = allocEasy();
1106	if (!easy)
1107	{
1108		return false;
1109	}
1110	easy->prepRequest(url, headers, responder, time_out);
1111
1112	LLSDSerialize::toXML(data, easy->getInput());
1113	S32 bytes = easy->getInput().str().length();
1114	
1115	easy->setopt(CURLOPT_POST, 1);
1116	easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL);
1117	easy->setopt(CURLOPT_POSTFIELDSIZE, bytes);
1118
1119	easy->slist_append("Content-Type: application/llsd+xml");
1120	easy->setHeaders();
1121
1122	lldebugs << "POSTING: " << bytes << " bytes." << llendl;
1123	bool res = addEasy(easy);
1124	return res;
1125}
1126
1127bool LLCurlRequest::post(const std::string& url,
1128						 const headers_t& headers,
1129						 const std::string& data,
1130						 LLCurl::ResponderPtr responder, S32 time_out)
1131{
1132	LLCurl::Easy* easy = allocEasy();
1133	if (!easy)
1134	{
1135		return false;
1136	}
1137	easy->prepRequest(url, headers, responder, time_out);
1138
1139	easy->getInput().write(data.data(), data.size());
1140	S32 bytes = easy->getInput().str().length();
1141	
1142	easy->setopt(CURLOPT_POST, 1);
1143	easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL);
1144	easy->setopt(CURLOPT_POSTFIELDSIZE, bytes);
1145
1146	easy->slist_append("Content-Type: application/octet-stream");
1147	easy->setHeaders();
1148
1149	lldebugs << "POSTING: " << bytes << " bytes." << llendl;
1150	bool res = addEasy(easy);
1151	return res;
1152}
1153
1154// Note: call once per frame
1155S32 LLCurlRequest::process()
1156{
1157	S32 res = 0;
1158
1159	mProcessing = TRUE;
1160	for (curlmulti_set_t::iterator iter = mMultiSet.begin();
1161		 iter != mMultiSet.end(); )
1162	{
1163		curlmulti_set_t::iterator curiter = iter++;
1164		LLCurl::Multi* multi = *curiter;
1165
1166		if(!multi->isValid())
1167		{
1168			if(multi == mActiveMulti)
1169			{				
1170				mActiveMulti = NULL ;
1171				mActiveRequestCount = 0 ;
1172			}
1173			mMultiSet.erase(curiter) ;
1174			LLCurl::getCurlThread()->killMulti(multi) ;
1175			continue ;
1176		}
1177
1178		S32 tres = multi->process();
1179		res += tres;
1180		if (multi != mActiveMulti && tres == 0 && multi->mQueued == 0)
1181		{
1182			mMultiSet.erase(curiter);
1183			LLCurl::getCurlThread()->killMulti(multi);
1184		}
1185	}
1186	mProcessing = FALSE;
1187	return res;
1188}
1189
1190S32 LLCurlRequest::getQueued()
1191{
1192	S32 queued = 0;
1193	for (curlmulti_set_t::iterator iter = mMultiSet.begin();
1194		 iter != mMultiSet.end(); )
1195	{
1196		curlmulti_set_t::iterator curiter = iter++;
1197		LLCurl::Multi* multi = *curiter;
1198		
1199		if(!multi->isValid())
1200		{
1201			if(multi == mActiveMulti)
1202			{				
1203				mActiveMulti = NULL ;
1204				mActiveRequestCount = 0 ;
1205			}
1206			LLCurl::getCurlThread()->killMulti(multi);
1207			mMultiSet.erase(curiter) ;
1208			continue ;
1209		}
1210
1211		queued += multi->mQueued;
1212		if (multi->getState() != LLCurl::Multi::STATE_READY)
1213		{
1214			++queued;
1215		}
1216	}
1217	return queued;
1218}
1219
1220////////////////////////////////////////////////////////////////////////////
1221// For generating one easy request
1222// associated with a single multi request
1223
1224LLCurlEasyRequest::LLCurlEasyRequest()
1225	: mRequestSent(false),
1226	  mResultReturned(false)
1227{
1228	mMulti = new LLCurl::Multi();
1229	
1230	if(mMulti->isValid())
1231	{
1232		mEasy = mMulti->allocEasy();
1233		if (mEasy)
1234		{
1235			mEasy->setErrorBuffer();
1236			mEasy->setCA();
1237			// Set proxy settings if configured to do so.
1238			LLProxy::getInstance()->applyProxySettings(mEasy);
1239		}
1240	}
1241	else
1242	{
1243		LLCurl::getCurlThread()->killMulti(mMulti) ;
1244		mEasy = NULL ;
1245		mMulti = NULL ;
1246	}
1247}
1248
1249LLCurlEasyRequest::~LLCurlEasyRequest()
1250{
1251	LLCurl::getCurlThread()->killMulti(mMulti) ;
1252}
1253	
1254void LLCurlEasyRequest::setopt(CURLoption option, S32 value)
1255{
1256	if (isValid() && mEasy)
1257	{
1258		mEasy->setopt(option, value);
1259	}
1260}
1261
1262void LLCurlEasyRequest::setoptString(CURLoption option, const std::string& value)
1263{
1264	if (isValid() && mEasy)
1265	{
1266		mEasy->setoptString(option, value);
1267	}
1268}
1269
1270void LLCurlEasyRequest::setPost(char* postdata, S32 size)
1271{
1272	if (isValid() && mEasy)
1273	{
1274		mEasy->setopt(CURLOPT_POST, 1);
1275		mEasy->setopt(CURLOPT_POSTFIELDS, postdata);
1276		mEasy->setopt(CURLOPT_POSTFIELDSIZE, size);
1277	}
1278}
1279
1280void LLCurlEasyRequest::setHeaderCallback(curl_header_callback callback, void* userdata)
1281{
1282	if (isValid() && mEasy)
1283	{
1284		mEasy->setopt(CURLOPT_HEADERFUNCTION, (void*)callback);
1285		mEasy->setopt(CURLOPT_HEADERDATA, userdata); // aka CURLOPT_WRITEHEADER
1286	}
1287}
1288
1289void LLCurlEasyRequest::setWriteCallback(curl_write_callback callback, void* userdata)
1290{
1291	if (isValid() && mEasy)
1292	{
1293		mEasy->setopt(CURLOPT_WRITEFUNCTION, (void*)callback);
1294		mEasy->setopt(CURLOPT_WRITEDATA, userdata);
1295	}
1296}
1297
1298void LLCurlEasyRequest::setReadCallback(curl_read_callback callback, void* userdata)
1299{
1300	if (isValid() && mEasy)
1301	{
1302		mEasy->setopt(CURLOPT_READFUNCTION, (void*)callback);
1303		mEasy->setopt(CURLOPT_READDATA, userdata);
1304	}
1305}
1306
1307void LLCurlEasyRequest::setSSLCtxCallback(curl_ssl_ctx_callback callback, void* userdata)
1308{
1309	if (isValid() && mEasy)
1310	{
1311		mEasy->setopt(CURLOPT_SSL_CTX_FUNCTION, (void*)callback);
1312		mEasy->setopt(CURLOPT_SSL_CTX_DATA, userdata);
1313	}
1314}
1315
1316void LLCurlEasyRequest::slist_append(const char* str)
1317{
1318	if (isValid() && mEasy)
1319	{
1320		mEasy->slist_append(str);
1321	}
1322}
1323
1324void LLCurlEasyRequest::sendRequest(const std::string& url)
1325{
1326	llassert_always(!mRequestSent);
1327	mRequestSent = true;
1328	lldebugs << url << llendl;
1329	if (isValid() && mEasy)
1330	{
1331		mEasy->setHeaders();
1332		mEasy->setoptString(CURLOPT_URL, url);
1333		mMulti->addEasy(mEasy);
1334	}
1335}
1336
1337void LLCurlEasyRequest::requestComplete()
1338{
1339	llassert_always(mRequestSent);
1340	mRequestSent = false;
1341	if (isValid() && mEasy)
1342	{
1343		mMulti->removeEasy(mEasy);
1344	}
1345}
1346
1347// Usage: Call getRestult until it returns false (no more messages)
1348bool LLCurlEasyRequest::getResult(CURLcode* result, LLCurl::TransferInfo* info)
1349{
1350	if(!isValid())
1351	{
1352		return false ;
1353	}
1354	if (!mMulti->isCompleted())
1355	{ //we're busy, try again later
1356		return false;
1357	}
1358	mMulti->setState(LLCurl::Multi::STATE_READY) ;
1359
1360	if (!mEasy)
1361	{
1362		// Special case - we failed to initialize a curl_easy (can happen if too many open files)
1363		//  Act as though the request failed to connect
1364		if (mResultReturned)
1365		{
1366			return false;
1367		}
1368		else
1369		{
1370			*result = CURLE_FAILED_INIT;
1371			mResultReturned = true;
1372			return true;
1373		}
1374	}
1375	// In theory, info_read might return a message with a status other than CURLMSG_DONE
1376	// In practice for all messages returned, msg == CURLMSG_DONE
1377	// Ignore other messages just in case
1378	while(1)
1379	{
1380		S32 q;
1381		CURLMsg* curlmsg = info_read(&q, info);
1382		if (curlmsg)
1383		{
1384			if (curlmsg->msg == CURLMSG_DONE)
1385			{
1386				*result = curlmsg->data.result;			
1387				return true;
1388			}
1389			// else continue
1390		}
1391		else
1392		{
1393			return false;
1394		}
1395	}
1396}
1397
1398// private
1399CURLMsg* LLCurlEasyRequest::info_read(S32* q, LLCurl::TransferInfo* info)
1400{
1401	if (mEasy)
1402	{
1403		CURLMsg* curlmsg = mMulti->info_read(q);
1404		if (curlmsg && curlmsg->msg == CURLMSG_DONE)
1405		{
1406			if (info)
1407			{
1408				mEasy->getTransferInfo(info);
1409			}
1410		}
1411		return curlmsg;
1412	}
1413	return NULL;
1414}
1415
1416std::string LLCurlEasyRequest::getErrorString()
1417{
1418	return isValid() &&  mEasy ? std::string(mEasy->getErrorBuffer()) : std::string();
1419}
1420
1421////////////////////////////////////////////////////////////////////////////
1422
1423#if SAFE_SSL
1424//static
1425void LLCurl::ssl_locking_callback(int mode, int type, const char *file, int line)
1426{
1427	if (mode & CRYPTO_LOCK)
1428	{
1429		LLCurl::sSSLMutex[type]->lock();
1430	}
1431	else
1432	{
1433		LLCurl::sSSLMutex[type]->unlock();
1434	}
1435}
1436
1437//static
1438unsigned long LLCurl::ssl_thread_id(void)
1439{
1440	return LLThread::currentID();
1441}
1442#endif
1443
1444void LLCurl::initClass(F32 curl_reuest_timeout, S32 max_number_handles, bool multi_threaded)
1445{
1446	sCurlRequestTimeOut = curl_reuest_timeout ; //seconds
1447	sMaxHandles = max_number_handles ; //max number of handles, (multi handles and easy handles combined).
1448
1449	// Do not change this "unless you are familiar with and mean to control 
1450	// internal operations of libcurl"
1451	// - http://curl.haxx.se/libcurl/c/curl_global_init.html
1452	CURLcode code = curl_global_init(CURL_GLOBAL_ALL);
1453
1454	check_curl_code(code);
1455	
1456#if SAFE_SSL
1457	S32 mutex_count = CRYPTO_num_locks();
1458	for (S32 i=0; i<mutex_count; i++)
1459	{
1460		sSSLMutex.push_back(new LLMutex(NULL));
1461	}
1462	CRYPTO_set_id_callback(&LLCurl::ssl_thread_id);
1463	CRYPTO_set_locking_callback(&LLCurl::ssl_locking_callback);
1464#endif
1465
1466	sCurlThread = new LLCurlThread(multi_threaded) ;
1467	if(multi_threaded)
1468	{
1469		sHandleMutexp = new LLMutex(NULL) ;
1470		Easy::sHandleMutexp = new LLMutex(NULL) ;
1471	}
1472}
1473
1474void LLCurl::cleanupClass()
1475{
1476	sNotQuitting = false; //set quitting
1477
1478	//shut down curl thread
1479	while(1)
1480	{
1481		if(!sCurlThread->update(1)) //finish all tasks
1482		{
1483			break ;
1484		}
1485	}
1486	sCurlThread->shutdown() ;
1487	delete sCurlThread ;
1488	sCurlThread = NULL ;
1489
1490#if SAFE_SSL
1491	CRYPTO_set_locking_callback(NULL);
1492	for_each(sSSLMutex.begin(), sSSLMutex.end(), DeletePointer());
1493#endif
1494
1495	for (std::set<CURL*>::iterator iter = Easy::sFreeHandles.begin(); iter != Easy::sFreeHandles.end(); ++iter)
1496	{
1497		CURL* curl = *iter;
1498		LLCurl::deleteEasyHandle(curl);
1499	}
1500
1501	Easy::sFreeHandles.clear();
1502
1503	delete Easy::sHandleMutexp ;
1504	Easy::sHandleMutexp = NULL ;
1505
1506	delete sHandleMutexp ;
1507	sHandleMutexp = NULL ;
1508
1509	llassert(Easy::sActiveHandles.empty());
1510}
1511
1512//static 
1513CURLM* LLCurl::newMultiHandle()
1514{
1515	LLMutexLock lock(sHandleMutexp) ;
1516
1517	if(sTotalHandles + 1 > sMaxHandles)
1518	{
1519		llwarns << "no more handles available." << llendl ;
1520		return NULL ; //failed
1521	}
1522	sTotalHandles++;
1523
1524	CURLM* ret = curl_multi_init() ;
1525	if(!ret)
1526	{
1527		llwarns << "curl_multi_init failed." << llendl ;
1528	}
1529
1530	return ret ;
1531}
1532
1533//static 
1534CURLMcode  LLCurl::deleteMultiHandle(CURLM* handle)
1535{
1536	if(handle)
1537	{
1538		LLMutexLock lock(sHandleMutexp) ;		
1539		sTotalHandles-- ;
1540		return curl_multi_cleanup(handle) ;
1541	}
1542	return CURLM_OK ;
1543}
1544
1545//static 
1546CURL*  LLCurl::newEasyHandle()
1547{
1548	LLMutexLock lock(sHandleMutexp) ;
1549
1550	if(sTotalHandles + 1 > sMaxHandles)
1551	{
1552		llwarns << "no more handles available." << llendl ;
1553		return NULL ; //failed
1554	}
1555	sTotalHandles++;
1556
1557	CURL* ret = curl_easy_init() ;
1558	if(!ret)
1559	{
1560		llwarns << "curl_easy_init failed." << llendl ;
1561	}
1562
1563	return ret ;
1564}
1565
1566//static 
1567void  LLCurl::deleteEasyHandle(CURL* handle)
1568{
1569	if(handle)
1570	{
1571		LLMutexLock lock(sHandleMutexp) ;
1572		curl_easy_cleanup(handle) ;
1573		sTotalHandles-- ;
1574	}
1575}
1576
1577const unsigned int LLCurl::MAX_REDIRECTS = 5;
1578
1579// Provide access to LLCurl free functions outside of llcurl.cpp without polluting the global namespace.
1580void LLCurlFF::check_easy_code(CURLcode code)
1581{
1582	check_curl_code(code);
1583}
1584void LLCurlFF::check_multi_code(CURLMcode code)
1585{
1586	check_curl_multi_code(code);
1587}