dessie linden avatar dessie linden committed 0496d2f Merge

reconciled .hgtags

Comments (0)

Files changed (63)

 1778f26b6d0ae762dec3ca37140f66620f2485d9 3.0.0-release
 42784bf50fa01974bada2a1af3892ee09c93fcda DRTVWR-83_3.0.2-beta1
 42784bf50fa01974bada2a1af3892ee09c93fcda 3.0.2-beta1
+e5c9af2d7980a99a71650be3a0cf7b2b3c3b897e DRTVWR-86_3.0.2-beta2
+e5c9af2d7980a99a71650be3a0cf7b2b3c3b897e 3.0.2-beta2
+b95ddac176ac944efdc85cbee94ac2e1eab44c79 3.0.3-start
 1778f26b6d0ae762dec3ca37140f66620f2485d9 DRTVWR-78_3.0.0-release
 0000000000000000000000000000000000000000 DRTVWR-78_3.0.0-release
 1778f26b6d0ae762dec3ca37140f66620f2485d9 DRTVWR-77_3.0.0-release
+6694f3f062aa45f64ab391d25a3eb3d5eb1b0871 DRTVWR-85_3.0.3-beta1
+6694f3f062aa45f64ab391d25a3eb3d5eb1b0871 3.0.3-beta1
+61aa7974df089e8621fe9a4c69bcdefdb3cc208a DRTVWR-89_3.0.3-beta2
+61aa7974df089e8621fe9a4c69bcdefdb3cc208a 3.0.3-beta2
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>0db10480362168f075c2af0ae302cb74</string>
+              <string>362654a472ef7368d4c803ae3fb89d95</string>
               <key>url</key>
-              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-llconvexdecomposition/rev/234943/arch/Darwin/installer/llconvexdecomposition-0.1-darwin-20110707.tar.bz2</string>
+              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-llconvexdecomposition/rev/238959/arch/Darwin/installer/llconvexdecomposition-0.1-darwin-20110819.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>f3c667dc159c0537a9122ce6e72e16db</string>
+              <string>c7801d899daec5338fbe95053255b7e7</string>
               <key>url</key>
-              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-llconvexdecomposition/rev/234943/arch/Linux/installer/llconvexdecomposition-0.1-linux-20110707.tar.bz2</string>
+              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-llconvexdecomposition/rev/238959/arch/Linux/installer/llconvexdecomposition-0.1-linux-20110819.tar.bz2</string>
             </map>
             <key>name</key>
             <string>linux</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>46cac4d667446bbbc9b5023f2848a5ac</string>
+              <string>6ecf2f85f03c5ae87fe45769566a5660</string>
               <key>url</key>
-              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-llconvexdecomposition/rev/234943/arch/CYGWIN/installer/llconvexdecomposition-0.1-windows-20110707.tar.bz2</string>
+              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-llconvexdecomposition/rev/238959/arch/CYGWIN/installer/llconvexdecomposition-0.1-windows-20110819.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>bc1388fc28dbb3bba1fe7cb8d09f49b4</string>
+              <string>a5f53e09f67271fd50f1131ffdda9d27</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llconvexdecompositionstub/rev/227399/arch/Darwin/installer/llconvexdecompositionstub-0.3-darwin-20110421.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llconvexdecompositionstub/rev/238958/arch/Darwin/installer/llconvexdecompositionstub-0.3-darwin-20110819.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>3295bd4a0514b7c15dda9044f40c175e</string>
+              <string>0006a964f1497f55a5f181b7042d2d22</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llconvexdecompositionstub/rev/227399/arch/Linux/installer/llconvexdecompositionstub-0.3-linux-20110422.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llconvexdecompositionstub/rev/238958/arch/Linux/installer/llconvexdecompositionstub-0.3-linux-20110819.tar.bz2</string>
             </map>
             <key>name</key>
             <string>linux</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>92f1dff3249024c1534b55343ed79ea3</string>
+              <string>b859e7e3bb03ebb467f0309f46422995</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llconvexdecompositionstub/rev/227399/arch/CYGWIN/installer/llconvexdecompositionstub-0.3-windows-20110421.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llconvexdecompositionstub/rev/238958/arch/CYGWIN/installer/llconvexdecompositionstub-0.3-windows-20110819.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
             <map>
               <key>build</key>
               <map>
+                <key>command</key>
+                <string>xcodebuild</string>
                 <key>filters</key>
                 <array>
                   <string>setenv</string>
                 </array>
-                <key>command</key>
-                <string>xcodebuild</string>
                 <key>options</key>
                 <array>
                   <string>-configuration Debug</string>
             <map>
               <key>build</key>
               <map>
+                <key>command</key>
+                <string>xcodebuild</string>
                 <key>filters</key>
                 <array>
                   <string>setenv</string>
                 </array>
-                <key>command</key>
-                <string>xcodebuild</string>
                 <key>options</key>
                 <array>
                   <string>-configuration RelWithDebInfo</string>
             <map>
               <key>build</key>
               <map>
+                <key>command</key>
+                <string>xcodebuild</string>
                 <key>filters</key>
                 <array>
                   <string>setenv</string>
                 </array>
-                <key>command</key>
-                <string>xcodebuild</string>
                 <key>options</key>
                 <array>
                   <string>-configuration Release</string>

doc/contributions.txt

 	STORM-1313
 	STORM-899
 	STORM-1273
+	STORM-1276
 	STORM-1462
 	STORM-1459
 Kadah Coba

indra/llcommon/llerror.cpp

 	{
 		/* This pattern, of returning a reference to a static function
 		   variable, is to ensure that this global is constructed before
-		   it is used, no matter what the global initializeation sequence
+		   it is used, no matter what the global initialization sequence
 		   is.
 		   See C++ FAQ Lite, sections 10.12 through 10.14
 		*/

indra/llcommon/llerror.h

 
 	Information for most users:
 	
-	Code can log messages with constuctions like this:
+	Code can log messages with constructions like this:
 	
 		LL_INFOS("StringTag") << "request to fizzbip agent " << agent_id
 			<< " denied due to timeout" << LL_ENDL;
 	Messages can be logged to one of four increasing levels of concern,
 	using one of four "streams":
 
-		LL_DEBUGS("StringTag")	- debug messages that are normally supressed
-		LL_INFOS("StringTag")	- informational messages that are normall shown
-		LL_WARNS("StringTag")	- warning messages that singal a problem
+		LL_DEBUGS("StringTag")	- debug messages that are normally suppressed
+		LL_INFOS("StringTag")	- informational messages that are normal shown
+		LL_WARNS("StringTag")	- warning messages that signal a problem
 		LL_ERRS("StringTag")	- error messages that are major, unrecoverable failures
 		
 	The later (LL_ERRS("StringTag")) automatically crashes the process after the message
 	
 		WARN: LLFoo::doSomething: called with a big value for i: 283
 	
-	Which messages are logged and which are supressed can be controled at run
+	Which messages are logged and which are suppressed can be controlled at run
 	time from the live file logcontrol.xml based on function, class and/or 
 	source file.  See etc/logcontrol-dev.xml for details.
 	
 	enum ELevel
 	{
 		LEVEL_ALL = 0,
-			// used to indicate that all messagess should be logged
+			// used to indicate that all messages should be logged
 			
 		LEVEL_DEBUG = 0,
 		LEVEL_INFO = 1,
 	// See top of file for example of how to use this
 	
 typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
-	// Outside a class declartion, or in class without LOG_CLASS(), this
+	// Outside a class declaration, or in class without LOG_CLASS(), this
 	// typedef causes the messages to not be associated with any class.
 
 

indra/llcommon/llinstancetracker.h

 	public:
 		typedef boost::iterator_facade<key_iter, KEY, boost::forward_traversal_tag> super_t;
 
-		key_iter(typename InstanceMap::iterator& it)
+		key_iter(typename InstanceMap::iterator it)
 			:	mIterator(it)
 		{
 			++sIterationNestDepth;

indra/llcommon/llsingleton.h

 		DELETED
 	} EInitState;
 	
-	static void deleteSingleton()
-	{
-		delete getData().mSingletonInstance;
-		getData().mSingletonInstance = NULL;
-	}
-	
 	// stores pointer to singleton instance
 	// and tracks initialization state of singleton
 	struct SingletonInstanceData
 
 		~SingletonInstanceData()
 		{
-			deleteSingleton();
+			SingletonInstanceData& data = getData();
+			if (data.mInitState != DELETED)
+			{
+				deleteSingleton();
+			}
 		}
 	};
 	
 		data.mInitState = DELETED;
 	}
 
+	// Can be used to control when the singleton is deleted.  Not normally needed.
+	static void deleteSingleton()
+	{
+		delete getData().mSingletonInstance;
+		getData().mSingletonInstance = NULL;
+		getData().mInitState = DELETED;
+	}
+
 	static SingletonInstanceData& getData()
 	{
 		// this is static to cache the lookup results

indra/llcommon/llversionviewer.h

 
 const S32 LL_VERSION_MAJOR = 3;
 const S32 LL_VERSION_MINOR = 0;
-const S32 LL_VERSION_PATCH = 2;
+const S32 LL_VERSION_PATCH = 3;
 const S32 LL_VERSION_BUILD = 0;
 
 const char * const LL_CHANNEL = "Second Life Developer";

indra/llcommon/tests/llinstancetracker_test.cpp

         ensure_equals(Keyed::instanceCount(), 0);
     }
 
-  //  template<> template<>
-  //  void object::test<2>()
-  //  {
-  //      ensure_equals(Unkeyed::instanceCount(), 0);
-  //      {
-  //          Unkeyed one;
-  //          ensure_equals(Unkeyed::instanceCount(), 1);
-  //          Unkeyed* found = Unkeyed::getInstance(&one);
-  //          ensure_equals(found, &one);
-  //          {
-  //              boost::scoped_ptr<Unkeyed> two(new Unkeyed);
-  //              ensure_equals(Unkeyed::instanceCount(), 2);
-  //              Unkeyed* found = Unkeyed::getInstance(two.get());
-  //              ensure_equals(found, two.get());
-  //          }
-  //          ensure_equals(Unkeyed::instanceCount(), 1);
-  //      }
-  //      ensure_equals(Unkeyed::instanceCount(), 0);
-  //  }
+    template<> template<>
+    void object::test<2>()
+    {
+        ensure_equals(Unkeyed::instanceCount(), 0);
+        {
+            Unkeyed one;
+            ensure_equals(Unkeyed::instanceCount(), 1);
+            Unkeyed* found = Unkeyed::getInstance(&one);
+            ensure_equals(found, &one);
+            {
+                boost::scoped_ptr<Unkeyed> two(new Unkeyed);
+                ensure_equals(Unkeyed::instanceCount(), 2);
+                Unkeyed* found = Unkeyed::getInstance(two.get());
+                ensure_equals(found, two.get());
+            }
+            ensure_equals(Unkeyed::instanceCount(), 1);
+        }
+        ensure_equals(Unkeyed::instanceCount(), 0);
+    }
 
-  //  template<> template<>
-  //  void object::test<3>()
-  //  {
-  //      Keyed one("one"), two("two"), three("three");
-  //      // We don't want to rely on the underlying container delivering keys
-  //      // in any particular order. That allows us the flexibility to
-  //      // reimplement LLInstanceTracker using, say, a hash map instead of a
-  //      // std::map. We DO insist that every key appear exactly once.
-  //      typedef std::vector<std::string> StringVector;
-  //      StringVector keys(Keyed::beginKeys(), Keyed::endKeys());
-  //      std::sort(keys.begin(), keys.end());
-  //      StringVector::const_iterator ki(keys.begin());
-  //      ensure_equals(*ki++, "one");
-  //      ensure_equals(*ki++, "three");
-  //      ensure_equals(*ki++, "two");
-  //      // Use ensure() here because ensure_equals would want to display
-  //      // mismatched values, and frankly that wouldn't help much.
-  //      ensure("didn't reach end", ki == keys.end());
+    template<> template<>
+    void object::test<3>()
+    {
+        Keyed one("one"), two("two"), three("three");
+        // We don't want to rely on the underlying container delivering keys
+        // in any particular order. That allows us the flexibility to
+        // reimplement LLInstanceTracker using, say, a hash map instead of a
+        // std::map. We DO insist that every key appear exactly once.
+        typedef std::vector<std::string> StringVector;
+        StringVector keys(Keyed::beginKeys(), Keyed::endKeys());
+        std::sort(keys.begin(), keys.end());
+        StringVector::const_iterator ki(keys.begin());
+        ensure_equals(*ki++, "one");
+        ensure_equals(*ki++, "three");
+        ensure_equals(*ki++, "two");
+        // Use ensure() here because ensure_equals would want to display
+        // mismatched values, and frankly that wouldn't help much.
+        ensure("didn't reach end", ki == keys.end());
 
-  //      // Use a somewhat different approach to order independence with
-  //      // beginInstances(): explicitly capture the instances we know in a
-  //      // set, and delete them as we iterate through.
-  //      typedef std::set<Keyed*> InstanceSet;
-  //      InstanceSet instances;
-  //      instances.insert(&one);
-  //      instances.insert(&two);
-  //      instances.insert(&three);
-  //      for (Keyed::instance_iter ii(Keyed::beginInstances()), iend(Keyed::endInstances());
-  //           ii != iend; ++ii)
-  //      {
-  //          Keyed& ref = *ii;
-  //          ensure_equals("spurious instance", instances.erase(&ref), 1);
-  //      }
-  //      ensure_equals("unreported instance", instances.size(), 0);
-  //  }
+        // Use a somewhat different approach to order independence with
+        // beginInstances(): explicitly capture the instances we know in a
+        // set, and delete them as we iterate through.
+        typedef std::set<Keyed*> InstanceSet;
+        InstanceSet instances;
+        instances.insert(&one);
+        instances.insert(&two);
+        instances.insert(&three);
+        for (Keyed::instance_iter ii(Keyed::beginInstances()), iend(Keyed::endInstances());
+             ii != iend; ++ii)
+        {
+            Keyed& ref = *ii;
+            ensure_equals("spurious instance", instances.erase(&ref), 1);
+        }
+        ensure_equals("unreported instance", instances.size(), 0);
+    }
 
-  //  template<> template<>
-  //  void object::test<4>()
-  //  {
-  //      Unkeyed one, two, three;
-  //      typedef std::set<Unkeyed*> KeySet;
-  //  
-  //      KeySet instances;
-  //      instances.insert(&one);
-  //      instances.insert(&two);
-  //      instances.insert(&three);
-	
-		//for (Unkeyed::instance_iter ii(Unkeyed::beginInstances()), iend(Unkeyed::endInstances()); ii != iend; ++ii)
-		//{
-		//	Unkeyed& ref = *ii;
-		//	ensure_equals("spurious instance", instances.erase(&ref), 1);
-		//}
-	
-  //      ensure_equals("unreported instance", instances.size(), 0);
-  //  }
+    template<> template<>
+    void object::test<4>()
+    {
+        Unkeyed one, two, three;
+        typedef std::set<Unkeyed*> KeySet;
+    
+        KeySet instances;
+        instances.insert(&one);
+        instances.insert(&two);
+        instances.insert(&three);
+
+		for (Unkeyed::instance_iter ii(Unkeyed::beginInstances()), iend(Unkeyed::endInstances()); ii != iend; ++ii)
+		{
+			Unkeyed& ref = *ii;
+			ensure_equals("spurious instance", instances.erase(&ref), 1);
+		}
+
+        ensure_equals("unreported instance", instances.size(), 0);
+    }
 } // namespace tut

indra/llmessage/CMakeLists.txt

     llpacketbuffer.cpp
     llpacketring.cpp
     llpartdata.cpp
+    llproxy.cpp
     llpumpio.cpp
     llregionpresenceverifier.cpp
     llsdappservices.cpp
     llpacketring.h
     llpartdata.h
     llpumpio.h
+    llproxy.h
     llqueryflags.h
     llregionflags.h
     llregionhandle.h

indra/llmessage/llcurl.cpp

 /**
- * @file llcurl.h
+ * @file llcurl.cpp
  * @author Zero / Donovan
  * @date 2006-10-15
  * @brief Implementation of wrapper around libcurl.
  * $/LicenseInfo$
  */
 
-
 #if LL_WINDOWS
 #define SAFE_SSL 1
 #elif LL_DARWIN
 #endif
 
 #include "llbufferstream.h"
+#include "llproxy.h"
+#include "llsdserialize.h"
 #include "llstl.h"
-#include "llsdserialize.h"
 #include "llthread.h"
 #include "lltimer.h"
 
 	
 	void intrusive_ptr_release(LLCurl::Responder* p)
 	{
-		if(p && 0 == --p->mReferenceCount)
+		if (p && 0 == --p->mReferenceCount)
 		{
 			delete p;
 		}
 
 //////////////////////////////////////////////////////////////////////////////
 
-
-class LLCurl::Easy
-{
-	LOG_CLASS(Easy);
-
-private:
-	Easy();
-	
-public:
-	static Easy* getEasy();
-	~Easy();
-
-	CURL* getCurlHandle() const { return mCurlEasyHandle; }
-
-	void setErrorBuffer();
-	void setCA();
-	
-	void setopt(CURLoption option, S32 value);
-	// These assume the setter does not free value!
-	void setopt(CURLoption option, void* value);
-	void setopt(CURLoption option, char* value);
-	// Copies the string so that it is gauranteed to stick around
-	void setoptString(CURLoption option, const std::string& value);
-	
-	void slist_append(const char* str);
-	void setHeaders();
-	
-	U32 report(CURLcode);
-	void getTransferInfo(LLCurl::TransferInfo* info);
-
-	void prepRequest(const std::string& url, const std::vector<std::string>& headers, ResponderPtr, S32 time_out = 0, bool post = false);
-	
-	const char* getErrorBuffer();
-
-	std::stringstream& getInput() { return mInput; }
-	std::stringstream& getHeaderOutput() { return mHeaderOutput; }
-	LLIOPipe::buffer_ptr_t& getOutput() { return mOutput; }
-	const LLChannelDescriptors& getChannels() { return mChannels; }
-	
-	void resetState();
-
-	static CURL* allocEasyHandle();
-	static void releaseEasyHandle(CURL* handle);
-
-private:	
-	friend class LLCurl;
-
-	CURL*				mCurlEasyHandle;
-	struct curl_slist*	mHeaders;
-	
-	std::stringstream	mRequest;
-	LLChannelDescriptors mChannels;
-	LLIOPipe::buffer_ptr_t mOutput;
-	std::stringstream	mInput;
-	std::stringstream	mHeaderOutput;
-	char				mErrorBuffer[CURL_ERROR_SIZE];
-
-	// Note: char*'s not strings since we pass pointers to curl
-	std::vector<char*>	mStrings;
-	
-	ResponderPtr		mResponder;
-
-	static std::set<CURL*> sFreeHandles;
-	static std::set<CURL*> sActiveHandles;
-	static LLMutex* sHandleMutex;
-};
-
 std::set<CURL*> LLCurl::Easy::sFreeHandles;
 std::set<CURL*> LLCurl::Easy::sActiveHandles;
 LLMutex* LLCurl::Easy::sHandleMutex = NULL;
 
 void LLCurl::Easy::setCA()
 {
-	if(!sCAPath.empty())
+	if (!sCAPath.empty())
 	{
 		setoptString(CURLOPT_CAPATH, sCAPath);
 	}
-	if(!sCAFile.empty())
+	if (!sCAFile.empty())
 	{
 		setoptString(CURLOPT_CAINFO, sCAFile);
 	}
 	
 	if (post) setoptString(CURLOPT_ENCODING, "");
 
-	//setopt(CURLOPT_VERBOSE, 1); // usefull for debugging
+	//setopt(CURLOPT_VERBOSE, 1); // useful for debugging
 	setopt(CURLOPT_NOSIGNAL, 1);
 
+	// Set the CURL options for either Socks or HTTP proxy
+	LLProxy::getInstance()->applyProxySettings(this);
+
 	mOutput.reset(new LLBufferArray);
 	setopt(CURLOPT_WRITEFUNCTION, (void*)&curlWriteCallback);
 	setopt(CURLOPT_WRITEDATA, (void*)this);
 	setopt(CURLOPT_HEADERDATA, (void*)this);
 
 	// Allow up to five redirects
-	if(responder && responder->followRedir())
+	if (responder && responder->followRedir())
 	{
 		setopt(CURLOPT_FOLLOWLOCATION, 1);
 		setopt(CURLOPT_MAXREDIRS, MAX_REDIRECTS);
 	
 	//don't verify host name so urls with scrubbed host names will work (improves DNS performance)
 	setopt(CURLOPT_SSL_VERIFYHOST, 0);
-	setopt(CURLOPT_TIMEOUT, llmax(time_out, CURL_REQUEST_TIMEOUT));
+	setopt(CURLOPT_TIMEOUT, CURL_REQUEST_TIMEOUT);
 
 	setoptString(CURLOPT_URL, url);
 
 
 ////////////////////////////////////////////////////////////////////////////
 
-class LLCurl::Multi : public LLThread
-{
-	LOG_CLASS(Multi);
-public:
-
-	typedef enum
-	{
-		PERFORM_STATE_READY=0,
-		PERFORM_STATE_PERFORMING=1,
-		PERFORM_STATE_COMPLETED=2
-	} ePerformState;
-
-	Multi();
-	~Multi();
-
-	Easy* allocEasy();
-	bool addEasy(Easy* easy);
-	
-	void removeEasy(Easy* easy);
-
-	S32 process();
-	void perform();
-	void doPerform();
-	
-	virtual void run();
-
-	CURLMsg* info_read(S32* msgs_in_queue);
-
-	S32 mQueued;
-	S32 mErrorCount;
-	
-	S32 mPerformState;
-
-	LLCondition* mSignal;
-	bool mQuitting;
-	bool mThreaded;
-
-private:
-	void easyFree(Easy*);
-	
-	CURLM* mCurlMultiHandle;
-
-	typedef std::set<Easy*> easy_active_list_t;
-	easy_active_list_t mEasyActiveList;
-	typedef std::map<CURL*, Easy*> easy_active_map_t;
-	easy_active_map_t mEasyActiveMap;
-	typedef std::set<Easy*> easy_free_list_t;
-	easy_free_list_t mEasyFreeList;
-};
-
 LLCurl::Multi::Multi()
 	: LLThread("Curl Multi"),
 	  mQueued(0),
 	{
 		mEasy->setErrorBuffer();
 		mEasy->setCA();
+		// Set proxy settings if configured to do so.
+		LLProxy::getInstance()->applyProxySettings(mEasy);
 	}
 }
 

indra/llmessage/llcurl.h

 	static const unsigned int MAX_REDIRECTS;
 };
 
+class LLCurl::Easy
+{
+	LOG_CLASS(Easy);
+
+private:
+	Easy();
+
+public:
+	static Easy* getEasy();
+	~Easy();
+
+	CURL* getCurlHandle() const { return mCurlEasyHandle; }
+
+	void setErrorBuffer();
+	void setCA();
+
+	void setopt(CURLoption option, S32 value);
+	// These assume the setter does not free value!
+	void setopt(CURLoption option, void* value);
+	void setopt(CURLoption option, char* value);
+	// Copies the string so that it is guaranteed to stick around
+	void setoptString(CURLoption option, const std::string& value);
+
+	void slist_append(const char* str);
+	void setHeaders();
+
+	U32 report(CURLcode);
+	void getTransferInfo(LLCurl::TransferInfo* info);
+
+	void prepRequest(const std::string& url, const std::vector<std::string>& headers, ResponderPtr, S32 time_out = 0, bool post = false);
+
+	const char* getErrorBuffer();
+
+	std::stringstream& getInput() { return mInput; }
+	std::stringstream& getHeaderOutput() { return mHeaderOutput; }
+	LLIOPipe::buffer_ptr_t& getOutput() { return mOutput; }
+	const LLChannelDescriptors& getChannels() { return mChannels; }
+
+	void resetState();
+
+	static CURL* allocEasyHandle();
+	static void releaseEasyHandle(CURL* handle);
+
+private:
+	friend class LLCurl;
+
+	CURL*				mCurlEasyHandle;
+	struct curl_slist*	mHeaders;
+
+	std::stringstream	mRequest;
+	LLChannelDescriptors mChannels;
+	LLIOPipe::buffer_ptr_t mOutput;
+	std::stringstream	mInput;
+	std::stringstream	mHeaderOutput;
+	char				mErrorBuffer[CURL_ERROR_SIZE];
+
+	// Note: char*'s not strings since we pass pointers to curl
+	std::vector<char*>	mStrings;
+
+	ResponderPtr		mResponder;
+
+	static std::set<CURL*> sFreeHandles;
+	static std::set<CURL*> sActiveHandles;
+	static LLMutex* sHandleMutex;
+};
+
+class LLCurl::Multi : public LLThread
+{
+	LOG_CLASS(Multi);
+public:
+
+	typedef enum
+	{
+		PERFORM_STATE_READY=0,
+		PERFORM_STATE_PERFORMING=1,
+		PERFORM_STATE_COMPLETED=2
+	} ePerformState;
+
+	Multi();
+	~Multi();
+
+	Easy* allocEasy();
+	bool addEasy(Easy* easy);
+	
+	void removeEasy(Easy* easy);
+
+	S32 process();
+	void perform();
+	void doPerform();
+	
+	virtual void run();
+
+	CURLMsg* info_read(S32* msgs_in_queue);
+
+	S32 mQueued;
+	S32 mErrorCount;
+	
+	S32 mPerformState;
+
+	LLCondition* mSignal;
+	bool mQuitting;
+	bool mThreaded;
+
+private:
+	void easyFree(Easy*);
+	
+	CURLM* mCurlMultiHandle;
+
+	typedef std::set<Easy*> easy_active_list_t;
+	easy_active_list_t mEasyActiveList;
+	typedef std::map<CURL*, Easy*> easy_active_map_t;
+	easy_active_map_t mEasyActiveMap;
+	typedef std::set<Easy*> easy_free_list_t;
+	easy_free_list_t mEasyFreeList;
+};
+
 namespace boost
 {
 	void intrusive_ptr_add_ref(LLCurl::Responder* p);
 	bool getResult(CURLcode* result, LLCurl::TransferInfo* info = NULL);
 	std::string getErrorString();
 
+	LLCurl::Easy* getEasy() const { return mEasy; }
+
 private:
 	CURLMsg* info_read(S32* queue, LLCurl::TransferInfo* info);
 	
 	bool mResultReturned;
 };
 
+void check_curl_code(CURLcode code);
+void check_curl_multi_code(CURLMcode code);
+
 #endif // LL_LLCURL_H

indra/llmessage/llhttpassetstorage.cpp

 
 #include "indra_constants.h"
 #include "message.h"
+#include "llproxy.h"
 #include "llvfile.h"
 #include "llvfs.h"
 
 {
 	// *NOTE: Similar code exists in mapserver/llcurlutil.cpp  JC
 	mCurlHandle = curl_easy_init();
+
+	// Apply proxy settings if configured to do so
+	LLProxy::getInstance()->applyProxySettings(mCurlHandle);
+
 	curl_easy_setopt(mCurlHandle, CURLOPT_NOSIGNAL, 1);
 	curl_easy_setopt(mCurlHandle, CURLOPT_NOPROGRESS, 1);
 	curl_easy_setopt(mCurlHandle, CURLOPT_URL, mURLBuffer.c_str());

indra/llmessage/llhttpclient.cpp

 	std::string body_str;
 	
 	// other request method checks root cert first, we skip?
+
+	// Apply configured proxy settings
+	LLProxy::getInstance()->applyProxySettings(curlp);
 	
 	// * Set curl handle options
 	curl_easy_setopt(curlp, CURLOPT_NOSIGNAL, 1);	// don't use SIGALRM for timeouts
 	curl_easy_setopt(curlp, CURLOPT_WRITEDATA, &http_buffer);
 	curl_easy_setopt(curlp, CURLOPT_URL, url.c_str());
 	curl_easy_setopt(curlp, CURLOPT_ERRORBUFFER, curl_error_buffer);
-	
+
 	// * Setup headers (don't forget to free them after the call!)
 	curl_slist* headers_list = NULL;
 	if (headers.isMap())

indra/llmessage/lliosocket.cpp

 	{
 		ll_debug_socket("Destroying socket", mSocket);
 		apr_socket_close(mSocket);
+		mSocket = NULL;
 	}
 	if(mPool)
 	{
 		apr_pool_destroy(mPool);
+		mPool = NULL;
 	}
 }
 

indra/llmessage/lliosocket.h

 	 */
 	apr_socket_t* getSocket() const { return mSocket; }
 
-protected:
-	/** 
-	 * @brief Protected constructor since should only make sockets
-	 * with one of the two <code>create()</code> calls.
-	 */
-	LLSocket(apr_socket_t* socket, apr_pool_t* pool);
-
 	/** 
 	 * @brief Set default socket options, with SO_NONBLOCK = 0 and a timeout in us.
 	 * @param timeout Number of microseconds to wait on this socket. Any
 	 */
 	void setNonBlocking();
 
+protected:
+	/**
+	 * @brief Protected constructor since should only make sockets
+	 * with one of the two <code>create()</code> calls.
+	 */
+	LLSocket(apr_socket_t* socket, apr_pool_t* pool);
+
 public:
 	/** 
 	 * @brief Do not call this directly.

indra/llmessage/llpacketring.cpp

 
 #include "llpacketring.h"
 
+#if LL_WINDOWS
+	#include <winsock2.h>
+#else
+	#include <sys/socket.h>
+	#include <netinet/in.h>
+#endif
+
 // linden library includes
 #include "llerror.h"
 #include "lltimer.h"
+#include "llproxy.h"
+#include "llrand.h"
+#include "message.h"
 #include "timing.h"
-#include "llrand.h"
 #include "u64.h"
 
 ///////////////////////////////////////////////////////////
 	else
 	{
 		// no delay, pull straight from net
-		packet_size = receive_packet(socket, datap);		
-		mLastSender = ::get_sender();
+		if (LLProxy::isSOCKSProxyEnabled())
+		{
+			U8 buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE];
+			packet_size = receive_packet(socket, reinterpret_cast<char *>(buffer));
+			
+			if (packet_size > SOCKS_HEADER_SIZE)
+			{
+				// *FIX We are assuming ATYP is 0x01 (IPv4), not 0x03 (hostname) or 0x04 (IPv6)
+				memcpy(datap, buffer + SOCKS_HEADER_SIZE, packet_size - SOCKS_HEADER_SIZE);
+				proxywrap_t * header = reinterpret_cast<proxywrap_t *>(buffer);
+				mLastSender.setAddress(header->addr);
+				mLastSender.setPort(ntohs(header->port));
+
+				packet_size -= SOCKS_HEADER_SIZE; // The unwrapped packet size
+			}
+			else
+			{
+				packet_size = 0;
+			}
+		}
+		else
+		{
+			packet_size = receive_packet(socket, datap);
+			mLastSender = ::get_sender();
+		}
+
 		mLastReceivingIF = ::get_receiving_interface();
 
 		if (packet_size)  // did we actually get a packet?
 	BOOL status = TRUE;
 	if (!mUseOutThrottle)
 	{
-		return send_packet(h_socket, send_buffer, buf_size, host.getAddress(), host.getPort() );
+		return sendPacketImpl(h_socket, send_buffer, buf_size, host );
 	}
 	else
 	{
 				mOutBufferLength -= packetp->getSize();
 				packet_size = packetp->getSize();
 
-				status = send_packet(h_socket, packetp->getData(), packet_size, packetp->getHost().getAddress(), packetp->getHost().getPort());
+				status = sendPacketImpl(h_socket, packetp->getData(), packet_size, packetp->getHost());
 				
 				delete packetp;
 				// Update the throttle
 			else
 			{
 				// If the queue's empty, we can just send this packet right away.
-				status = send_packet(h_socket, send_buffer, buf_size, host.getAddress(), host.getPort() );
+				status =  sendPacketImpl(h_socket, send_buffer, buf_size, host );
 				packet_size = buf_size;
 
 				// Update the throttle
 
 	return status;
 }
+
+BOOL LLPacketRing::sendPacketImpl(int h_socket, const char * send_buffer, S32 buf_size, LLHost host)
+{
+	
+	if (!LLProxy::isSOCKSProxyEnabled())
+	{
+		return send_packet(h_socket, send_buffer, buf_size, host.getAddress(), host.getPort());
+	}
+
+	proxywrap_t *socks_header = reinterpret_cast<proxywrap_t *>(&mProxyWrappedSendBuffer);
+	socks_header->rsv   = 0;
+	socks_header->addr  = host.getAddress();
+	socks_header->port  = htons(host.getPort());
+	socks_header->atype = ADDRESS_IPV4;
+	socks_header->frag  = 0;
+
+	memcpy(mProxyWrappedSendBuffer + SOCKS_HEADER_SIZE, send_buffer, buf_size);
+
+	return send_packet(h_socket, (const char*) mProxyWrappedSendBuffer, buf_size + 10, LLProxy::getInstance()->getUDPProxy().getAddress(), LLProxy::getInstance()->getUDPProxy().getPort());
+}

indra/llmessage/llpacketring.h

 
 #include <queue>
 
+#include "llhost.h"
 #include "llpacketbuffer.h"
-#include "llhost.h"
+#include "llproxy.h"
+#include "llthrottle.h"
 #include "net.h"
-#include "llthrottle.h"
-
 
 class LLPacketRing
 {
 
 	LLHost mLastSender;
 	LLHost mLastReceivingIF;
+
+
+	U8 mProxyWrappedSendBuffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE];
+
+private:
+	BOOL sendPacketImpl(int h_socket, const char * send_buffer, S32 buf_size, LLHost host);
 };
 
 

indra/llmessage/llproxy.cpp

+/**
+ * @file llproxy.cpp
+ * @brief UDP and HTTP proxy communications
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, 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
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llproxy.h"
+
+#include <string>
+#include <curl/curl.h>
+
+#include "llapr.h"
+#include "llcurl.h"
+#include "llhost.h"
+
+// Static class variable instances
+
+// We want this to be static to avoid excessive indirection on every
+// incoming packet just to do a simple bool test. The getter for this
+// member is also static
+bool LLProxy::sUDPProxyEnabled = false;
+
+// Some helpful TCP static functions.
+static S32 tcp_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen); // Do a TCP data handshake
+static LLSocket::ptr_t tcp_open_channel(apr_pool_t* pool, LLHost host); // Open a TCP channel to a given host
+static void tcp_close_channel(LLSocket::ptr_t* handle_ptr); // Close an open TCP channel
+
+LLProxy::LLProxy():
+		mHTTPProxyEnabled(false),
+		mProxyMutex(0),
+		mUDPProxy(),
+		mTCPProxy(),
+		mPool(gAPRPoolp),
+		mHTTPProxy(),
+		mProxyType(LLPROXY_SOCKS),
+		mAuthMethodSelected(METHOD_NOAUTH),
+		mSocksUsername(),
+		mSocksPassword()
+{
+}
+
+LLProxy::~LLProxy()
+{
+	stopSOCKSProxy();
+	sUDPProxyEnabled  = false;
+	mHTTPProxyEnabled = false;
+}
+
+/**
+ * @brief Open the SOCKS 5 TCP control channel.
+ *
+ * Perform a SOCKS 5 authentication and UDP association to the proxy server.
+ *
+ * @param proxy The SOCKS 5 server to connect to.
+ * @return SOCKS_OK if successful, otherwise a socks error code from llproxy.h.
+ */
+S32 LLProxy::proxyHandshake(LLHost proxy)
+{
+	S32 result;
+
+	/* SOCKS 5 Auth request */
+	socks_auth_request_t  socks_auth_request;
+	socks_auth_response_t socks_auth_response;
+
+	socks_auth_request.version     = SOCKS_VERSION;       // SOCKS version 5
+	socks_auth_request.num_methods = 1;                   // Sending 1 method.
+	socks_auth_request.methods     = getSelectedAuthMethod(); // Send only the selected method.
+
+	result = tcp_handshake(mProxyControlChannel, (char*)&socks_auth_request, sizeof(socks_auth_request), (char*)&socks_auth_response, sizeof(socks_auth_response));
+	if (result != APR_SUCCESS)
+	{
+		LL_WARNS("Proxy") << "SOCKS authentication request failed, error on TCP control channel : " << result << LL_ENDL;
+		stopSOCKSProxy();
+		return SOCKS_CONNECT_ERROR;
+	}
+
+	if (socks_auth_response.method == AUTH_NOT_ACCEPTABLE)
+	{
+		LL_WARNS("Proxy") << "SOCKS 5 server refused all our authentication methods" << LL_ENDL;
+		stopSOCKSProxy();
+		return SOCKS_NOT_ACCEPTABLE;
+	}
+
+	// SOCKS 5 USERNAME/PASSWORD authentication
+	if (socks_auth_response.method == METHOD_PASSWORD)
+	{
+		// The server has requested a username/password combination
+		std::string socks_username(getSocksUser());
+		std::string socks_password(getSocksPwd());
+		U32 request_size = socks_username.size() + socks_password.size() + 3;
+		char * password_auth = new char[request_size];
+		password_auth[0] = 0x01;
+		password_auth[1] = socks_username.size();
+		memcpy(&password_auth[2], socks_username.c_str(), socks_username.size());
+		password_auth[socks_username.size() + 2] = socks_password.size();
+		memcpy(&password_auth[socks_username.size()+3], socks_password.c_str(), socks_password.size());
+
+		authmethod_password_reply_t password_reply;
+
+		result = tcp_handshake(mProxyControlChannel, password_auth, request_size, (char*)&password_reply, sizeof(password_reply));
+		delete[] password_auth;
+
+		if (result != APR_SUCCESS)
+		{
+			LL_WARNS("Proxy") << "SOCKS authentication failed, error on TCP control channel : " << result << LL_ENDL;
+			stopSOCKSProxy();
+			return SOCKS_CONNECT_ERROR;
+		}
+
+		if (password_reply.status != AUTH_SUCCESS)
+		{
+			LL_WARNS("Proxy") << "SOCKS authentication failed" << LL_ENDL;
+			stopSOCKSProxy();
+			return SOCKS_AUTH_FAIL;
+		}
+	}
+
+	/* SOCKS5 connect request */
+
+	socks_command_request_t  connect_request;
+	socks_command_response_t connect_reply;
+
+	connect_request.version		= SOCKS_VERSION;         // SOCKS V5
+	connect_request.command		= COMMAND_UDP_ASSOCIATE; // Associate UDP
+	connect_request.reserved	= FIELD_RESERVED;
+	connect_request.atype		= ADDRESS_IPV4;
+	connect_request.address		= htonl(0); // 0.0.0.0
+	connect_request.port		= htons(0); // 0
+	// "If the client is not in possession of the information at the time of the UDP ASSOCIATE,
+	//  the client MUST use a port number and address of all zeros. RFC 1928"
+
+	result = tcp_handshake(mProxyControlChannel, (char*)&connect_request, sizeof(connect_request), (char*)&connect_reply, sizeof(connect_reply));
+	if (result != APR_SUCCESS)
+	{
+		LL_WARNS("Proxy") << "SOCKS connect request failed, error on TCP control channel : " << result << LL_ENDL;
+		stopSOCKSProxy();
+		return SOCKS_CONNECT_ERROR;
+	}
+
+	if (connect_reply.reply != REPLY_REQUEST_GRANTED)
+	{
+		LL_WARNS("Proxy") << "Connection to SOCKS 5 server failed, UDP forward request not granted" << LL_ENDL;
+		stopSOCKSProxy();
+		return SOCKS_UDP_FWD_NOT_GRANTED;
+	}
+
+	mUDPProxy.setPort(ntohs(connect_reply.port)); // reply port is in network byte order
+	mUDPProxy.setAddress(proxy.getAddress());
+	// The connection was successful. We now have the UDP port to send requests that need forwarding to.
+	LL_INFOS("Proxy") << "SOCKS 5 UDP proxy connected on " << mUDPProxy << LL_ENDL;
+	return SOCKS_OK;
+}
+
+/**
+ * @brief Initiates a SOCKS 5 proxy session.
+ *
+ * Performs basic checks on host to verify that it is a valid address. Opens the control channel
+ * and then negotiates the proxy connection with the server.
+ *
+ *
+ * @param host Socks server to connect to.
+ * @return SOCKS_OK if successful, otherwise a SOCKS error code defined in llproxy.h.
+ */
+S32 LLProxy::startSOCKSProxy(LLHost host)
+{
+	S32 status = SOCKS_OK;
+
+	if (host.isOk())
+	{
+		mTCPProxy = host;
+	}
+	else
+	{
+		status = SOCKS_INVALID_HOST;
+	}
+
+	if (mProxyControlChannel && status == SOCKS_OK)
+	{
+		tcp_close_channel(&mProxyControlChannel);
+	}
+
+	if (status == SOCKS_OK)
+	{
+		mProxyControlChannel = tcp_open_channel(mPool, mTCPProxy);
+		if (!mProxyControlChannel)
+		{
+			status = SOCKS_HOST_CONNECT_FAILED;
+		}
+	}
+
+	if (status == SOCKS_OK)
+	{
+		status = proxyHandshake(mTCPProxy);
+	}
+	if (status == SOCKS_OK)
+	{
+		sUDPProxyEnabled = true;
+	}
+	else
+	{
+		stopSOCKSProxy();
+	}
+	return status;
+}
+
+/**
+ * @brief Stop using the SOCKS 5 proxy.
+ *
+ * This will stop sending UDP packets through the SOCKS 5 proxy
+ * and will also stop the HTTP proxy if it is configured to use SOCKS.
+ * The proxy control channel will also be disconnected.
+ */
+void LLProxy::stopSOCKSProxy()
+{
+	sUDPProxyEnabled = false;
+
+	// If the SOCKS proxy is requested to stop and we are using that for HTTP as well
+	// then we must shut down any HTTP proxy operations. But it is allowable if web
+	// proxy is being used to continue proxying HTTP.
+
+	if (LLPROXY_SOCKS == getHTTPProxyType())
+	{
+		void disableHTTPProxy();
+	}
+
+	if (mProxyControlChannel)
+	{
+		tcp_close_channel(&mProxyControlChannel);
+	}
+}
+
+/**
+ * @brief Set the proxy's SOCKS authentication method to none.
+ */
+void LLProxy::setAuthNone()
+{
+	LLMutexLock lock(&mProxyMutex);
+
+	mAuthMethodSelected = METHOD_NOAUTH;
+}
+
+/**
+ * @brief Set the proxy's SOCKS authentication method to password.
+ *
+ * Check whether the lengths of the supplied username
+ * and password conform to the lengths allowed by the
+ * SOCKS protocol.
+ *
+ * @param 	username The SOCKS username to send.
+ * @param 	password The SOCKS password to send.
+ * @return  Return true if applying the settings was successful. No changes are made if false.
+ *
+ */
+bool LLProxy::setAuthPassword(const std::string &username, const std::string &password)
+{
+	if (username.length() > SOCKSMAXUSERNAMELEN || password.length() > SOCKSMAXPASSWORDLEN ||
+			username.length() < SOCKSMINUSERNAMELEN || password.length() < SOCKSMINPASSWORDLEN)
+	{
+		LL_WARNS("Proxy") << "Invalid SOCKS 5 password or username length." << LL_ENDL;
+		return false;
+	}
+
+	LLMutexLock lock(&mProxyMutex);
+
+	mAuthMethodSelected = METHOD_PASSWORD;
+	mSocksUsername      = username;
+	mSocksPassword      = password;
+
+	return true;
+}
+
+/**
+ * @brief Enable the HTTP proxy for either SOCKS or HTTP.
+ *
+ * Check the supplied host to see if it is a valid IP and port.
+ *
+ * @param httpHost Proxy server to connect to.
+ * @param type Is the host a SOCKS or HTTP proxy.
+ * @return Return true if applying the setting was successful. No changes are made if false.
+ */
+bool LLProxy::enableHTTPProxy(LLHost httpHost, LLHttpProxyType type)
+{
+	if (!httpHost.isOk())
+	{
+		LL_WARNS("Proxy") << "Invalid SOCKS 5 Server" << LL_ENDL;
+		return false;
+	}
+
+	LLMutexLock lock(&mProxyMutex);
+
+	mHTTPProxy        = httpHost;
+	mProxyType        = type;
+
+	mHTTPProxyEnabled = true;
+
+	return true;
+}
+
+/**
+ * @brief Enable the HTTP proxy without changing the proxy settings.
+ *
+ * This should not be called unless the proxy has already been set up.
+ *
+ * @return Return true only if the current settings are valid and the proxy was enabled.
+ */
+bool LLProxy::enableHTTPProxy()
+{
+	bool ok;
+
+	LLMutexLock lock(&mProxyMutex);
+
+	ok = (mHTTPProxy.isOk());
+	if (ok)
+	{
+		mHTTPProxyEnabled = true;
+	}
+
+	return ok;
+}
+
+/**
+ * @brief Disable the HTTP proxy.
+ */
+void LLProxy::disableHTTPProxy()
+{
+	LLMutexLock lock(&mProxyMutex);
+
+	mHTTPProxyEnabled = false;
+}
+
+/**
+ * @brief Get the HTTP proxy address and port
+ */
+//
+LLHost LLProxy::getHTTPProxy() const
+{
+	LLMutexLock lock(&mProxyMutex);
+	return mHTTPProxy;
+}
+
+/**
+ * @brief Get the currently selected HTTP proxy type
+ */
+LLHttpProxyType LLProxy::getHTTPProxyType() const
+{
+	LLMutexLock lock(&mProxyMutex);
+	return mProxyType;
+}
+
+/**
+ * @brief Get the SOCKS 5 password.
+ */
+std::string LLProxy::getSocksPwd() const
+{
+	LLMutexLock lock(&mProxyMutex);
+	return mSocksPassword;
+}
+
+/**
+ * @brief Get the SOCKS 5 username.
+ */
+std::string LLProxy::getSocksUser() const
+{
+	LLMutexLock lock(&mProxyMutex);
+	return mSocksUsername;
+}
+
+/**
+ * @brief Get the currently selected SOCKS 5 authentication method.
+ *
+ * @return Returns either none or password.
+ */
+LLSocks5AuthType LLProxy::getSelectedAuthMethod() const
+{
+	LLMutexLock lock(&mProxyMutex);
+	return mAuthMethodSelected;
+}
+
+/**
+ * @brief Stop the LLProxy and make certain that any APR pools and classes are deleted before terminating APR.
+ *
+ * Deletes the LLProxy singleton, destroying the APR pool used by the control channel as well as .
+ */
+//static
+void LLProxy::cleanupClass()
+{
+	getInstance()->stopSOCKSProxy();
+	deleteSingleton();
+}
+
+void LLProxy::applyProxySettings(LLCurlEasyRequest* handle)
+{
+	applyProxySettings(handle->getEasy());
+}
+
+void LLProxy::applyProxySettings(LLCurl::Easy* handle)
+{
+	applyProxySettings(handle->getCurlHandle());
+}
+
+/**
+ * @brief Apply proxy settings to a CuRL request if an HTTP proxy is enabled.
+ *
+ * This method has been designed to be safe to call from
+ * any thread in the viewer.  This allows requests in the
+ * texture fetch thread to be aware of the proxy settings.
+ * When the HTTP proxy is enabled, the proxy mutex will
+ * be locked every time this method is called.
+ *
+ * @param handle A pointer to a valid CURL request, before it has been performed.
+ */
+void LLProxy::applyProxySettings(CURL* handle)
+{
+	// Do a faster unlocked check to see if we are supposed to proxy.
+	if (mHTTPProxyEnabled)
+	{
+		// We think we should proxy, lock the proxy mutex.
+		LLMutexLock lock(&mProxyMutex);
+		// Now test again to verify that the proxy wasn't disabled between the first check and the lock.
+		if (mHTTPProxyEnabled)
+		{
+			check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXY, mHTTPProxy.getIPString().c_str()));
+			check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYPORT, mHTTPProxy.getPort()));
+
+			if (mProxyType == LLPROXY_SOCKS)
+			{
+				check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5));
+				if (mAuthMethodSelected == METHOD_PASSWORD)
+				{
+					std::string auth_string = mSocksUsername + ":" + mSocksPassword;
+					check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYUSERPWD, auth_string.c_str()));
+				}
+			}
+			else
+			{
+				check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP));
+			}
+		}
+	}
+}
+
+/**
+ * @brief Send one TCP packet and receive one in return.
+ *
+ * This operation is done synchronously with a 1000ms timeout. Therefore, it should not be used when a blocking
+ * operation would impact the operation of the viewer.
+ *
+ * @param handle_ptr 	Pointer to a connected LLSocket of type STREAM_TCP.
+ * @param dataout		Data to send.
+ * @param outlen		Length of dataout.
+ * @param datain		Buffer for received data. Undefined if return value is not APR_SUCCESS.
+ * @param maxinlen		Maximum possible length of received data.  Short reads are allowed.
+ * @return 				Indicates APR status code of exchange. APR_SUCCESS if exchange was successful, -1 if invalid data length was received.
+ */
+static S32 tcp_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen)
+{
+	apr_socket_t* apr_socket = handle->getSocket();
+	apr_status_t rv = APR_SUCCESS;
+
+	apr_size_t expected_len = outlen;
+
+	handle->setBlocking(1000);
+
+  	rv = apr_socket_send(apr_socket, dataout, &outlen);
+	if (APR_SUCCESS != rv)
+	{
+		LL_WARNS("Proxy") << "Error sending data to proxy control channel, status: " << rv << LL_ENDL;
+		ll_apr_warn_status(rv);
+	}
+	else if (expected_len != outlen)
+	{
+		LL_WARNS("Proxy") << "Incorrect data length sent. Expected: " << expected_len <<
+				" Sent: " << outlen << LL_ENDL;
+		rv = -1;
+	}
+
+	if (APR_SUCCESS == rv)
+	{
+		expected_len = maxinlen;
+		rv = apr_socket_recv(apr_socket, datain, &maxinlen);
+		if (rv != APR_SUCCESS)
+		{
+			LL_WARNS("Proxy") << "Error receiving data from proxy control channel, status: " << rv << LL_ENDL;
+			ll_apr_warn_status(rv);
+		}
+		else if (expected_len < maxinlen)
+		{
+			LL_WARNS("Proxy") << "Incorrect data length received. Expected: " << expected_len <<
+					" Received: " << maxinlen << LL_ENDL;
+			rv = -1;
+		}
+	}
+
+	handle->setNonBlocking();
+
+	return rv;
+}
+
+/**
+ * @brief Open a LLSocket and do a blocking connect to the chosen host.
+ *
+ * Checks for a successful connection, and makes sure the connection is closed if it fails.
+ *
+ * @param pool		APR pool to pass into the LLSocket.
+ * @param host		The host to open the connection to.
+ * @return			The created socket.  Will evaluate as NULL if the connection is unsuccessful.
+ */
+static LLSocket::ptr_t tcp_open_channel(apr_pool_t* pool, LLHost host)
+{
+	LLSocket::ptr_t socket = LLSocket::create(pool, LLSocket::STREAM_TCP);
+	bool connected = socket->blockingConnect(host);
+	if (!connected)
+	{
+		tcp_close_channel(&socket);
+	}
+
+	return socket;
+}
+
+/**
+ * @brief Close the socket.
+ *
+ * @param handle_ptr A pointer-to-pointer to avoid increasing the use count.
+ */
+static void tcp_close_channel(LLSocket::ptr_t* handle_ptr)
+{
+	LL_DEBUGS("Proxy") << "Resetting proxy LLSocket handle, use_count == " << handle_ptr->use_count() << LL_ENDL;
+	handle_ptr->reset();
+}

indra/llmessage/llproxy.h

+/**
+ * @file llproxy.h
+ * @brief UDP and HTTP proxy communications
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, 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
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_PROXY_H
+#define LL_PROXY_H
+
+#include "llcurl.h"
+#include "llhost.h"
+#include "lliosocket.h"
+#include "llmemory.h"
+#include "llsingleton.h"
+#include "llthread.h"
+#include <string>
+
+// SOCKS error codes returned from the StartProxy method
+
+#define SOCKS_OK 0
+#define SOCKS_CONNECT_ERROR (-1)
+#define SOCKS_NOT_PERMITTED (-2)
+#define SOCKS_NOT_ACCEPTABLE (-3)
+#define SOCKS_AUTH_FAIL (-4)
+#define SOCKS_UDP_FWD_NOT_GRANTED (-5)
+#define SOCKS_HOST_CONNECT_FAILED (-6)
+#define SOCKS_INVALID_HOST (-7)
+
+
+#ifndef MAXHOSTNAMELEN
+#define	MAXHOSTNAMELEN (255 + 1) /* socks5: 255, +1 for len. */
+#endif
+
+#define SOCKSMAXUSERNAMELEN 255
+#define SOCKSMAXPASSWORDLEN 255
+
+#define SOCKSMINUSERNAMELEN 1
+#define SOCKSMINPASSWORDLEN 1
+
+#define SOCKS_VERSION 0x05 // we are using SOCKS 5
+
+#define SOCKS_HEADER_SIZE 10
+
+// SOCKS 5 address/hostname types
+#define ADDRESS_IPV4     0x01
+#define ADDRESS_HOSTNAME 0x03
+#define ADDRESS_IPV6     0x04
+
+// Lets just use our own ipv4 struct rather than dragging in system
+// specific headers
+union ipv4_address_t {
+	U8		octets[4];
+	U32		addr32;
+};
+
+// SOCKS 5 control channel commands
+#define COMMAND_TCP_STREAM    0x01
+#define COMMAND_TCP_BIND      0x02
+#define COMMAND_UDP_ASSOCIATE 0x03
+
+// SOCKS 5 command replies
+#define REPLY_REQUEST_GRANTED     0x00
+#define REPLY_GENERAL_FAIL        0x01
+#define REPLY_RULESET_FAIL        0x02
+#define REPLY_NETWORK_UNREACHABLE 0x03
+#define REPLY_HOST_UNREACHABLE    0x04
+#define REPLY_CONNECTION_REFUSED  0x05
+#define REPLY_TTL_EXPIRED         0x06
+#define REPLY_PROTOCOL_ERROR      0x07
+#define REPLY_TYPE_NOT_SUPPORTED  0x08
+
+#define FIELD_RESERVED 0x00
+
+// The standard SOCKS 5 request packet
+// Push current alignment to stack and set alignment to 1 byte boundary
+// This enabled us to use structs directly to set up and receive network packets
+// into the correct fields, without fear of boundary alignment causing issues
+#pragma pack(push,1)
+
+// SOCKS 5 command packet
+struct socks_command_request_t {
+	U8		version;
+	U8		command;
+	U8		reserved;
+	U8		atype;
+	U32		address;
+	U16		port;
+};
+
+// Standard SOCKS 5 reply packet
+struct socks_command_response_t {
+	U8		version;
+	U8		reply;
+	U8		reserved;
+	U8		atype;
+	U8		add_bytes[4];
+	U16		port;
+};
+
+#define AUTH_NOT_ACCEPTABLE 0xFF // reply if preferred methods are not available
+#define AUTH_SUCCESS        0x00 // reply if authentication successful
+
+// SOCKS 5 authentication request, stating which methods the client supports
+struct socks_auth_request_t {
+	U8		version;
+	U8		num_methods;
+	U8		methods; // We are only using a single method currently
+};
+
+// SOCKS 5 authentication response packet, stating server preferred method
+struct socks_auth_response_t {
+	U8		version;
+	U8		method;
+};
+
+// SOCKS 5 password reply packet
+struct authmethod_password_reply_t {
+	U8		version;
+	U8		status;
+};
+
+// SOCKS 5 UDP packet header
+struct proxywrap_t {
+	U16		rsv;
+	U8		frag;
+	U8		atype;
+	U32		addr;
+	U16		port;
+};
+
+#pragma pack(pop) /* restore original alignment from stack */
+
+
+// Currently selected HTTP proxy type
+enum LLHttpProxyType
+{
+	LLPROXY_SOCKS = 0,
+	LLPROXY_HTTP  = 1
+};
+
+// Auth types
+enum LLSocks5AuthType
+{
+	METHOD_NOAUTH   = 0x00,	// Client supports no auth
+	METHOD_GSSAPI   = 0x01,	// Client supports GSSAPI (Not currently supported)
+	METHOD_PASSWORD = 0x02 	// Client supports username/password
+};
+
+/**
+ * @brief Manage SOCKS 5 UDP proxy and HTTP proxy.
+ *
+ * This class is responsible for managing two interconnected tasks,
+ * connecting to a SOCKS 5 proxy for use by LLPacketRing to send UDP
+ * packets and managing proxy settings for HTTP requests.
+ *
+ * <h1>Threading:</h1>
+ * Because HTTP requests can be generated in threads outside the
+ * main thread, it is necessary for some of the information stored
+ * by this class to be available to other threads. The members that
+ * need to be read across threads are in a labeled section below.
+ * To protect those members, a mutex, mProxyMutex should be locked
+ * before reading or writing those members.  Methods that can lock
+ * mProxyMutex are in a labeled section below. Those methods should
+ * not be called while the mutex is already locked.
+ *
+ * There is also a LLAtomic type flag (mHTTPProxyEnabled) that is used
+ * to track whether the HTTP proxy is currently enabled. This allows
+ * for faster unlocked checks to see if the proxy is enabled.  This
+ * allows us to cut down on the performance hit when the proxy is
+ * disabled compared to before this class was introduced.
+ *
+ * <h1>UDP Proxying:</h1>
+ * UDP datagrams are proxied via a SOCKS 5 proxy with the UDP associate
+ * command.  To initiate the proxy, a TCP socket connection is opened
+ * to the SOCKS 5 host, and after a handshake exchange, the server
+ * returns a port and address to send the UDP traffic that is to be
+ * proxied to. The LLProxy class tracks this address and port after the
+ * exchange and provides it to LLPacketRing when required to. All UDP
+ * proxy management occurs in the main thread.
+ *
+ * <h1>HTTP Proxying:</h1>
+ * This class allows all viewer HTTP packets to be sent through a proxy.
+ * The user can select whether to send HTTP packets through a standard
+ * "web" HTTP proxy, through a SOCKS 5 proxy, or to not proxy HTTP
+ * communication. This class does not manage the integrated web browser
+ * proxy, which is handled in llviewermedia.cpp.
+ *
+ * The implementation of HTTP proxying is handled by libcurl. LLProxy
+ * is responsible for managing the HTTP proxy options and provides a
+ * thread-safe method to apply those options to a curl request
+ * (LLProxy::applyProxySettings()). This method is overloaded
+ * to accommodate the various abstraction libcurl layers that exist
+ * throughout the viewer (LLCurlEasyRequest, LLCurl::Easy, and CURL).
+ *
+ * If you are working with LLCurl or LLCurlEasyRequest objects,
+ * the configured proxy settings will be applied in the constructors
+ * of those request handles.  If you are working with CURL objects
+ * directly, you will need to pass the handle of the request to
+ * applyProxySettings() before issuing the request.
+ *
+ * To ensure thread safety, all LLProxy members that relate to the HTTP
+ * proxy require the LLProxyMutex to be locked before accessing.
+ */
+class LLProxy: public LLSingleton<LLProxy>
+{
+	LOG_CLASS(LLProxy);
+public:
+	// METHODS THAT DO NOT LOCK mProxyMutex!
+
+	LLProxy();
+
+	// static check for enabled status for UDP packets
+	static bool isSOCKSProxyEnabled() { return sUDPProxyEnabled; }
+
+	// check for enabled status for HTTP packets
+	// mHTTPProxyEnabled is atomic, so no locking is required for thread safety.
+	bool isHTTPProxyEnabled() const { return mHTTPProxyEnabled; }
+
+	// Get the UDP proxy address and port
+	LLHost getUDPProxy() const { return mUDPProxy; }
+
+	// Get the SOCKS 5 TCP control channel address and port
+	LLHost getTCPProxy() const { return mTCPProxy; }
+
+	// END OF NON-LOCKING METHODS
+
+	// METHODS THAT DO LOCK mProxyMutex! DO NOT CALL WHILE mProxyMutex IS LOCKED!
+
+	~LLProxy();
+
+	// Start a connection to the SOCKS 5 proxy
+	S32 startSOCKSProxy(LLHost host);
+
+	// Disconnect and clean up any connection to the SOCKS 5 proxy
+	void stopSOCKSProxy();
+
+	// Delete LLProxy singleton, destroying the APR pool used by the control channel.
+	static void cleanupClass();
+
+	// Set up to use Password auth when connecting to the SOCKS proxy
+	bool setAuthPassword(const std::string &username, const std::string &password);
+
+	// Set up to use No Auth when connecting to the SOCKS proxy
+	void setAuthNone();
+
+	// Get the currently selected auth method.
+	LLSocks5AuthType getSelectedAuthMethod() const;
+
+	// Proxy HTTP packets via httpHost, which can be a SOCKS 5 or a HTTP proxy
+	// as specified in type
+	bool enableHTTPProxy(LLHost httpHost, LLHttpProxyType type);
+	bool enableHTTPProxy();
+
+	// Stop proxying HTTP packets
+	void disableHTTPProxy();
+
+	// Apply the current proxy settings to a curl request. Doesn't do anything if mHTTPProxyEnabled is false.
+	void applyProxySettings(CURL* handle);
+	void applyProxySettings(LLCurl::Easy* handle);
+	void applyProxySettings(LLCurlEasyRequest* handle);
+
+	// Get the HTTP proxy address and port
+	LLHost getHTTPProxy() const;
+
+	// Get the currently selected HTTP proxy type
+	LLHttpProxyType getHTTPProxyType() const;
+
+	std::string getSocksPwd() const;
+	std::string getSocksUser() const;
+
+	// END OF LOCKING METHODS
+private:
+	// Open a communication channel to the SOCKS 5 proxy proxy, at port messagePort
+	S32 proxyHandshake(LLHost proxy);
+
+private:
+	// Is the HTTP proxy enabled?
+	// Safe to read in any thread, do not write directly,
+	// use enableHTTPProxy() and disableHTTPProxy() instead.
+	mutable LLAtomic32<bool> mHTTPProxyEnabled;
+
+	// Mutex to protect shared members in non-main thread calls to applyProxySettings()
+	mutable LLMutex mProxyMutex;
+
+	// MEMBERS READ AND WRITTEN ONLY IN THE MAIN THREAD. DO NOT SHARE!
+
+	// Is the UDP proxy enabled?
+	static bool sUDPProxyEnabled;
+
+	// UDP proxy address and port
+	LLHost mUDPProxy;
+	// TCP proxy control channel address and port
+	LLHost mTCPProxy;
+
+	// socket handle to proxy TCP control channel
+	LLSocket::ptr_t mProxyControlChannel;
+
+	// APR pool for the socket
+	apr_pool_t* mPool;
+
+	// END OF UNSHARED MEMBERS
+
+	// MEMBERS WRITTEN IN MAIN THREAD AND READ IN ANY THREAD. ONLY READ OR WRITE AFTER LOCKING mProxyMutex!
+
+	// HTTP proxy address and port
+	LLHost mHTTPProxy;
+
+	// Currently selected HTTP proxy type. Can be web or socks.
+	LLHttpProxyType mProxyType;
+
+	// SOCKS 5 auth method selected
+	LLSocks5AuthType mAuthMethodSelected;
+
+	// SOCKS 5 username
+	std::string mSocksUsername;
+	// SOCKS 5 password
+	std::string mSocksPassword;
+
+	// END OF SHARED MEMBERS
+};
+
+#endif

indra/llmessage/llurlrequest.cpp

 #include "llcurl.h"
 #include "llioutil.h"
 #include "llmemtype.h"
+#include "llproxy.h"
 #include "llpumpio.h"
 #include "llsd.h"
 #include "llstring.h"
         }
     }
 
-
-    lldebugs << "use_proxy = " << (use_proxy?'Y':'N') << ", env_proxy = " << (env_proxy ? env_proxy : "(null)") << llendl;
+    LL_DEBUGS("Proxy") << "use_proxy = " << (use_proxy?'Y':'N') << ", env_proxy = " << (env_proxy ? env_proxy : "(null)") << LL_ENDL;
 
     if (env_proxy && use_proxy)
     {

indra/llmessage/net.cpp

 #include "lltimer.h"
 #include "indra_constants.h"
 
-
 // Globals
 #if LL_WINDOWS
 
 	// use wildcard addresses. -Ambroff
 	U32 ip = inet_addr(ip_string);
 	if (ip == INADDR_NONE 
-	    && strncmp(ip_string, BROADCAST_ADDRESS_STRING, MAXADDRSTR) != 0)
+			&& strncmp(ip_string, BROADCAST_ADDRESS_STRING, MAXADDRSTR) != 0)
 	{
 		llwarns << "ip_string_to_u32() failed, Error: Invalid IP string '" << ip_string << "'" << llendl;
 		return INVALID_HOST_IP_ADDRESS;
 //////////////////////////////////////////////////////////////////////////////////////////
 
 #if LL_WINDOWS
- 
+
 S32 start_net(S32& socket_out, int& nPort) 
 {			
 	// Create socket, make non-blocking
-    // Init WinSock 
+	// Init WinSock
 	int nRet;
 	int hSocket;
 
 	int buff_size = 4;
  
 	// Initialize windows specific stuff
-	if(WSAStartup(0x0202, &stWSAData))
+	if (WSAStartup(0x0202, &stWSAData))
 	{
 		S32 err = WSAGetLastError();
 		WSACleanup();
 	}
 
 	// Get a datagram socket
-    hSocket = (int)socket(AF_INET, SOCK_DGRAM, 0);
-    if (hSocket == INVALID_SOCKET)
+	hSocket = (int)socket(AF_INET, SOCK_DGRAM, 0);
+	if (hSocket == INVALID_SOCKET)
 	{
 		S32 err = WSAGetLastError();
 		WSACleanup();
 	//  Setup a destination address
 	stDstAddr.sin_family =      AF_INET;
 	stDstAddr.sin_addr.s_addr = INVALID_HOST_IP_ADDRESS;
-    stDstAddr.sin_port =        htons(nPort);
+	stDstAddr.sin_port =        htons(nPort);
 
 	socket_out = hSocket;
 	return 0;
 	int rec_size = RECEIVE_BUFFER_SIZE;
 
 	socklen_t buff_size = 4;
-    
+
 	//  Create socket
-    hSocket = socket(AF_INET, SOCK_DGRAM, 0);
-    if (hSocket < 0)
+	hSocket = socket(AF_INET, SOCK_DGRAM, 0);
+	if (hSocket < 0)
 	{
 		llwarns << "socket() failed" << llendl;
 		return 1;
 	}
 	else
 	{
-	    // Name the socket (assign the local port number to receive on)
+		// Name the socket (assign the local port number to receive on)
 		stLclAddr.sin_family      = AF_INET;
 		stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY);
 		stLclAddr.sin_port        = htons(nPort);
 		nPort = attempt_port;
 	}
 	// Set socket to be non-blocking
- 	fcntl(hSocket, F_SETFL, O_NONBLOCK);
+	fcntl(hSocket, F_SETFL, O_NONBLOCK);
 	// set a large receive buffer
 	nRet = setsockopt(hSocket, SOL_SOCKET, SO_RCVBUF, (char *)&rec_size, buff_size);
 	if (nRet)
 	//  Setup a destination address
 	char achMCAddr[MAXADDRSTR] = "127.0.0.1";	/* Flawfinder: ignore */ 
 	stDstAddr.sin_family =      AF_INET;
-        stDstAddr.sin_addr.s_addr = ip_string_to_u32(achMCAddr);
-        stDstAddr.sin_port =        htons(nPort);
+	stDstAddr.sin_addr.s_addr = ip_string_to_u32(achMCAddr);
+	stDstAddr.sin_port =        htons(nPort);
 
 	socket_out = hSocket;
 	return 0;
 	iov[0].iov_base = buf;
 	iov[0].iov_len = len;
 
-	memset( &msg, 0, sizeof msg );
+	memset(&msg, 0, sizeof msg);
 	msg.msg_name = from;
 	msg.msg_namelen = *fromlen;
 	msg.msg_iov = iov;
 	msg.msg_control = &cmsg;
 	msg.msg_controllen = sizeof(cmsg);
 
-	size = recvmsg( socket, &msg, 0 );
+	size = recvmsg(socket, &msg, 0);
 
-	if( size == -1 )
+	if (size == -1)
 	{
 		return -1;
 	}
 
-	for( cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR( &msg, cmsgptr ) )
+	for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR( &msg, cmsgptr))
 	{
 		if( cmsgptr->cmsg_level == SOL_IP && cmsgptr->cmsg_type == IP_PKTINFO )
 		{
 			}
 		}
 	}
-	while ( resend && send_attempts < 3);
+	while (resend && send_attempts < 3);
 
 	if (send_attempts >= 3)
 	{