summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOz Linden <oz@lindenlab.com>2011-08-25 09:27:34 -0400
committerOz Linden <oz@lindenlab.com>2011-08-25 09:27:34 -0400
commite6239b7978fb9f05d2c8c7cf42b9277f4a5f7c52 (patch)
tree17080b4ffa8a59a5b9c158edaf9e60f9af2a67b4
parent66cac05cfb1236c3c1607dff27babf873c29a679 (diff)
parent6484dbf28cb8b6ffa745fe9b26beae58d3c68441 (diff)
merge changes for storm-1571
-rw-r--r--indra/llcommon/llerror.cpp2
-rw-r--r--indra/llcommon/llerror.h14
-rw-r--r--indra/llcommon/llsingleton.h20
-rw-r--r--indra/llmessage/CMakeLists.txt2
-rw-r--r--indra/llmessage/llcurl.cpp140
-rw-r--r--indra/llmessage/llcurl.h121
-rw-r--r--indra/llmessage/llhttpassetstorage.cpp5
-rw-r--r--indra/llmessage/llhttpclient.cpp5
-rw-r--r--indra/llmessage/lliosocket.cpp2
-rw-r--r--indra/llmessage/lliosocket.h14
-rw-r--r--indra/llmessage/llpacketring.cpp65
-rw-r--r--indra/llmessage/llpacketring.h12
-rw-r--r--indra/llmessage/llproxy.cpp551
-rw-r--r--indra/llmessage/llproxy.h342
-rw-r--r--indra/llmessage/llurlrequest.cpp4
-rw-r--r--indra/llmessage/net.cpp39
-rw-r--r--indra/llmessage/net.h4
-rw-r--r--indra/llui/llfunctorregistry.h4
-rw-r--r--indra/newview/app_settings/settings.xml55
-rw-r--r--indra/newview/llappviewer.cpp3
-rwxr-xr-xindra/newview/llfloaterpreference.cpp267
-rw-r--r--indra/newview/llfloaterpreference.h30
-rw-r--r--indra/newview/llloginhandler.cpp6
-rw-r--r--indra/newview/llpanellogin.h3
-rw-r--r--indra/newview/llsecapi.h4
-rw-r--r--indra/newview/llstartup.cpp192
-rw-r--r--indra/newview/llstartup.h2
-rw-r--r--indra/newview/llviewerfloaterreg.cpp1
-rw-r--r--indra/newview/llxmlrpctransaction.cpp13
-rw-r--r--indra/newview/skins/default/xui/en/floater_preferences_proxy.xml273
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml132
-rw-r--r--indra/newview/skins/default/xui/en/panel_cof_wearables.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_privacy.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_setup.xml85
34 files changed, 2117 insertions, 299 deletions
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index bb64152407..c35799bbb9 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -379,7 +379,7 @@ namespace
{
/* 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
*/
diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h
index 4a42241c4f..b3e604f8e8 100644
--- a/indra/llcommon/llerror.h
+++ b/indra/llcommon/llerror.h
@@ -39,7 +39,7 @@
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;
@@ -47,9 +47,9 @@
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
@@ -90,7 +90,7 @@
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.
@@ -106,7 +106,7 @@ namespace LLError
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,
@@ -220,7 +220,7 @@ namespace LLError
// 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.
diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index 7aee1bb85f..00757be277 100644
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -100,12 +100,6 @@ private:
DELETED
} EInitState;
- static void deleteSingleton()
- {
- delete getData().mSingletonInstance;
- getData().mSingletonInstance = NULL;
- }
-
// stores pointer to singleton instance
// and tracks initialization state of singleton
struct SingletonInstanceData
@@ -120,7 +114,11 @@ private:
~SingletonInstanceData()
{
- deleteSingleton();
+ SingletonInstanceData& data = getData();
+ if (data.mInitState != DELETED)
+ {
+ deleteSingleton();
+ }
}
};
@@ -132,6 +130,14 @@ public:
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
diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt
index c5f82cf052..0f40a670fa 100644
--- a/indra/llmessage/CMakeLists.txt
+++ b/indra/llmessage/CMakeLists.txt
@@ -65,6 +65,7 @@ set(llmessage_SOURCE_FILES
llpacketbuffer.cpp
llpacketring.cpp
llpartdata.cpp
+ llproxy.cpp
llpumpio.cpp
llregionpresenceverifier.cpp
llsdappservices.cpp
@@ -161,6 +162,7 @@ set(llmessage_HEADER_FILES
llpacketring.h
llpartdata.h
llpumpio.h
+ llproxy.h
llqueryflags.h
llregionflags.h
llregionhandle.h
diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp
index 1a86a69a04..bfdf49c74b 100644
--- a/indra/llmessage/llcurl.cpp
+++ b/indra/llmessage/llcurl.cpp
@@ -1,5 +1,5 @@
/**
- * @file llcurl.h
+ * @file llcurl.cpp
* @author Zero / Donovan
* @date 2006-10-15
* @brief Implementation of wrapper around libcurl.
@@ -26,7 +26,6 @@
* $/LicenseInfo$
*/
-
#if LL_WINDOWS
#define SAFE_SSL 1
#elif LL_DARWIN
@@ -47,8 +46,9 @@
#endif
#include "llbufferstream.h"
-#include "llstl.h"
+#include "llproxy.h"
#include "llsdserialize.h"
+#include "llstl.h"
#include "llthread.h"
#include "lltimer.h"
@@ -209,7 +209,7 @@ namespace boost
void intrusive_ptr_release(LLCurl::Responder* p)
{
- if(p && 0 == --p->mReferenceCount)
+ if (p && 0 == --p->mReferenceCount)
{
delete p;
}
@@ -219,73 +219,6 @@ namespace boost
//////////////////////////////////////////////////////////////////////////////
-
-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;
@@ -409,11 +342,11 @@ const char* LLCurl::Easy::getErrorBuffer()
void LLCurl::Easy::setCA()
{
- if(!sCAPath.empty())
+ if (!sCAPath.empty())
{
setoptString(CURLOPT_CAPATH, sCAPath);
}
- if(!sCAFile.empty())
+ if (!sCAFile.empty())
{
setoptString(CURLOPT_CAINFO, sCAFile);
}
@@ -536,9 +469,12 @@ void LLCurl::Easy::prepRequest(const std::string& url,
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);
@@ -550,7 +486,7 @@ void LLCurl::Easy::prepRequest(const std::string& url,
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);
@@ -563,7 +499,7 @@ void LLCurl::Easy::prepRequest(const std::string& url,
//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);
@@ -584,56 +520,6 @@ void LLCurl::Easy::prepRequest(const std::string& 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),
@@ -1071,6 +957,8 @@ LLCurlEasyRequest::LLCurlEasyRequest()
{
mEasy->setErrorBuffer();
mEasy->setCA();
+ // Set proxy settings if configured to do so.
+ LLProxy::getInstance()->applyProxySettings(mEasy);
}
}
diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h
index f7518c8e5c..5ab4dc35b9 100644
--- a/indra/llmessage/llcurl.h
+++ b/indra/llmessage/llcurl.h
@@ -187,6 +187,122 @@ private:
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);
@@ -243,6 +359,8 @@ public:
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);
@@ -253,4 +371,7 @@ private:
bool mResultReturned;
};
+void check_curl_code(CURLcode code);
+void check_curl_multi_code(CURLMcode code);
+
#endif // LL_LLCURL_H
diff --git a/indra/llmessage/llhttpassetstorage.cpp b/indra/llmessage/llhttpassetstorage.cpp
index 5a38b7fd9f..2bca517e97 100644
--- a/indra/llmessage/llhttpassetstorage.cpp
+++ b/indra/llmessage/llhttpassetstorage.cpp
@@ -33,6 +33,7 @@
#include "indra_constants.h"
#include "message.h"
+#include "llproxy.h"
#include "llvfile.h"
#include "llvfs.h"
@@ -232,6 +233,10 @@ void LLHTTPAssetRequest::setupCurlHandle()
{
// *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());
diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp
index 0e5206a520..dd4e3a6300 100644
--- a/indra/llmessage/llhttpclient.cpp
+++ b/indra/llmessage/llhttpclient.cpp
@@ -428,6 +428,9 @@ static LLSD blocking_request(
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
@@ -436,7 +439,7 @@ static LLSD blocking_request(
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())
diff --git a/indra/llmessage/lliosocket.cpp b/indra/llmessage/lliosocket.cpp
index b717e321bf..ee9379f205 100644
--- a/indra/llmessage/lliosocket.cpp
+++ b/indra/llmessage/lliosocket.cpp
@@ -251,10 +251,12 @@ LLSocket::~LLSocket()
{
ll_debug_socket("Destroying socket", mSocket);
apr_socket_close(mSocket);
+ mSocket = NULL;
}
if(mPool)
{
apr_pool_destroy(mPool);
+ mPool = NULL;
}
}
diff --git a/indra/llmessage/lliosocket.h b/indra/llmessage/lliosocket.h
index e0f6c1e34d..be0f7dfcc6 100644
--- a/indra/llmessage/lliosocket.h
+++ b/indra/llmessage/lliosocket.h
@@ -145,13 +145,6 @@ public:
*/
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
@@ -164,6 +157,13 @@ protected:
*/
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.
diff --git a/indra/llmessage/llpacketring.cpp b/indra/llmessage/llpacketring.cpp
index 8999dec64a..7628984de4 100644
--- a/indra/llmessage/llpacketring.cpp
+++ b/indra/llmessage/llpacketring.cpp
@@ -28,11 +28,20 @@
#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 "timing.h"
+#include "llproxy.h"
#include "llrand.h"
+#include "message.h"
+#include "timing.h"
#include "u64.h"
///////////////////////////////////////////////////////////
@@ -216,8 +225,32 @@ S32 LLPacketRing::receivePacket (S32 socket, char *datap)
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?
@@ -243,7 +276,7 @@ BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LL
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
{
@@ -264,7 +297,7 @@ BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LL
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
@@ -273,7 +306,7 @@ BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LL
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
@@ -311,3 +344,23 @@ BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LL
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());
+}
diff --git a/indra/llmessage/llpacketring.h b/indra/llmessage/llpacketring.h
index e6409d2048..7edcc834db 100644
--- a/indra/llmessage/llpacketring.h
+++ b/indra/llmessage/llpacketring.h
@@ -30,11 +30,11 @@
#include <queue>
-#include "llpacketbuffer.h"
#include "llhost.h"
-#include "net.h"
+#include "llpacketbuffer.h"
+#include "llproxy.h"
#include "llthrottle.h"
-
+#include "net.h"
class LLPacketRing
{
@@ -82,6 +82,12 @@ protected:
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);
};
diff --git a/indra/llmessage/llproxy.cpp b/indra/llmessage/llproxy.cpp
new file mode 100644
index 0000000000..3f4a6accbf
--- /dev/null
+++ b/indra/llmessage/llproxy.cpp
@@ -0,0 +1,551 @@
+/**
+ * @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();
+}
diff --git a/indra/llmessage/llproxy.h b/indra/llmessage/llproxy.h
new file mode 100644
index 0000000000..29e7e28567
--- /dev/null
+++ b/indra/llmessage/llproxy.h
@@ -0,0 +1,342 @@
+/**
+ * @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
diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp
index e8e35d00a2..d5400e4169 100644
--- a/indra/llmessage/llurlrequest.cpp
+++ b/indra/llmessage/llurlrequest.cpp
@@ -35,6 +35,7 @@
#include "llcurl.h"
#include "llioutil.h"
#include "llmemtype.h"
+#include "llproxy.h"
#include "llpumpio.h"
#include "llsd.h"
#include "llstring.h"
@@ -227,8 +228,7 @@ void LLURLRequest::useProxy(bool use_proxy)
}
}
-
- 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)
{
diff --git a/indra/llmessage/net.cpp b/indra/llmessage/net.cpp
index 97611c3b51..85aef5da00 100644
--- a/indra/llmessage/net.cpp
+++ b/indra/llmessage/net.cpp
@@ -50,7 +50,6 @@
#include "lltimer.h"
#include "indra_constants.h"
-
// Globals
#if LL_WINDOWS
@@ -174,7 +173,7 @@ U32 ip_string_to_u32(const char* ip_string)
// 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;
@@ -188,11 +187,11 @@ U32 ip_string_to_u32(const char* ip_string)
//////////////////////////////////////////////////////////////////////////////////////////
#if LL_WINDOWS
-
+
S32 start_net(S32& socket_out, int& nPort)
{
// Create socket, make non-blocking
- // Init WinSock
+ // Init WinSock
int nRet;
int hSocket;
@@ -201,7 +200,7 @@ S32 start_net(S32& socket_out, int& nPort)
int buff_size = 4;
// Initialize windows specific stuff
- if(WSAStartup(0x0202, &stWSAData))
+ if (WSAStartup(0x0202, &stWSAData))
{
S32 err = WSAGetLastError();
WSACleanup();
@@ -210,8 +209,8 @@ S32 start_net(S32& socket_out, int& nPort)
}
// 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();
@@ -304,7 +303,7 @@ S32 start_net(S32& socket_out, int& nPort)
// 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;
@@ -393,10 +392,10 @@ S32 start_net(S32& socket_out, int& nPort)
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;
@@ -429,7 +428,7 @@ S32 start_net(S32& socket_out, int& nPort)
}
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);
@@ -474,7 +473,7 @@ S32 start_net(S32& socket_out, int& 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)
@@ -510,8 +509,8 @@ S32 start_net(S32& socket_out, int& nPort)
// 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;
@@ -537,7 +536,7 @@ static int recvfrom_destip( int socket, void *buf, int len, struct sockaddr *fro
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;
@@ -545,14 +544,14 @@ static int recvfrom_destip( int socket, void *buf, int len, struct sockaddr *fro
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 )
{
@@ -650,7 +649,7 @@ BOOL send_packet(int hSocket, const char * sendBuffer, int size, U32 recipient,
}
}
}
- while ( resend && send_attempts < 3);
+ while (resend && send_attempts < 3);
if (send_attempts >= 3)
{
diff --git a/indra/llmessage/net.h b/indra/llmessage/net.h
index 9f4f5c5821..0f2437479d 100644
--- a/indra/llmessage/net.h
+++ b/indra/llmessage/net.h
@@ -46,10 +46,10 @@ S32 receive_packet(int hSocket, char * receiveBuffer);
BOOL send_packet(int hSocket, const char *sendBuffer, int size, U32 recipient, int nPort); // Returns TRUE on success.
//void get_sender(char * tmp);
-LLHost get_sender();
+LLHost get_sender();
U32 get_sender_port();
U32 get_sender_ip(void);
-LLHost get_receiving_interface();
+LLHost get_receiving_interface();
U32 get_receiving_interface_ip(void);
const char* u32_to_ip_string(U32 ip); // Returns pointer to internal string buffer, "(bad IP addr)" on failure, cannot nest calls
diff --git a/indra/llui/llfunctorregistry.h b/indra/llui/llfunctorregistry.h
index 752c7df7ee..899cc3a326 100644
--- a/indra/llui/llfunctorregistry.h
+++ b/indra/llui/llfunctorregistry.h
@@ -103,7 +103,7 @@ public:
}
else
{
- llwarns << "tried to find '" << name << "' in LLFunctorRegistry, but it wasn't there." << llendl;
+ lldebugs << "tried to find '" << name << "' in LLFunctorRegistry, but it wasn't there." << llendl;
return mMap[LOGFUNCTOR];
}
}
@@ -115,7 +115,7 @@ private:
static void log_functor(const LLSD& notification, const LLSD& payload)
{
- llwarns << "log_functor called with payload: " << payload << llendl;
+ lldebugs << "log_functor called with payload: " << payload << llendl;
}
static void do_nothing(const LLSD& notification, const LLSD& payload)
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 7c01731282..30e0b86a5a 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -798,6 +798,61 @@
<key>Value</key>
<integer>5</integer>
</map>
+ <key>Socks5ProxyEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Use Socks5 Proxy</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>HttpProxyType</key>
+ <map>
+ <key>Comment</key>
+ <string>Proxy type to use for HTTP operations</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>Socks</string>
+ </map>
+ <key>Socks5ProxyHost</key>
+ <map>
+ <key>Comment</key>
+ <string>Socks 5 Proxy Host</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string></string>
+ </map>
+ <key>Socks5ProxyPort</key>
+ <map>
+ <key>Comment</key>
+ <string>Socks 5 Proxy Port</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>1080</integer>
+ </map>
+ <key>Socks5AuthType</key>
+ <map>
+ <key>Comment</key>
+ <string>Selected Auth mechanism for Socks5</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>None</string>
+ </map>
<key>BuildAxisDeadZone0</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index d12b971bde..9b29d69cce 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -137,6 +137,7 @@
#include "lltoolmgr.h"
#include "llassetstorage.h"
#include "llpolymesh.h"
+#include "llproxy.h"
#include "llaudioengine.h"
#include "llstreamingaudio.h"
#include "llviewermenu.h"
@@ -1840,6 +1841,8 @@ bool LLAppViewer::cleanup()
LLWeb::loadURLExternal( gLaunchFileOnQuit, false );
llinfos << "File launched." << llendflush;
}
+ llinfos << "Cleaning up LLProxy." << llendl;
+ LLProxy::cleanupClass();
LLMainLoopRepeater::instance().stop();
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 5fd262a720..d65928e385 100755
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -105,6 +105,7 @@
#include "llviewermedia.h"
#include "llpluginclassmedia.h"
#include "llteleporthistorystorage.h"
+#include "llproxy.h"
#include "lllogininstance.h" // to check if logged in yet
#include "llsdserialize.h"
@@ -158,7 +159,7 @@ BOOL LLVoiceSetKeyDialog::handleKeyHere(KEY key, MASK mask)
{
BOOL result = TRUE;
- if(key == 'Q' && mask == MASK_CONTROL)
+ if (key == 'Q' && mask == MASK_CONTROL)
{
result = FALSE;
}
@@ -333,16 +334,17 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)
mCommitCallbackRegistrar.add("Pref.ClickEnablePopup", boost::bind(&LLFloaterPreference::onClickEnablePopup, this));
mCommitCallbackRegistrar.add("Pref.ClickDisablePopup", boost::bind(&LLFloaterPreference::onClickDisablePopup, this));
mCommitCallbackRegistrar.add("Pref.LogPath", boost::bind(&LLFloaterPreference::onClickLogPath, this));
- mCommitCallbackRegistrar.add("Pref.HardwareSettings", boost::bind(&LLFloaterPreference::onOpenHardwareSettings, this));
- mCommitCallbackRegistrar.add("Pref.HardwareDefaults", boost::bind(&LLFloaterPreference::setHardwareDefaults, this));
- mCommitCallbackRegistrar.add("Pref.VertexShaderEnable", boost::bind(&LLFloaterPreference::onVertexShaderEnable, this));
- mCommitCallbackRegistrar.add("Pref.WindowedMod", boost::bind(&LLFloaterPreference::onCommitWindowedMode, this));
- mCommitCallbackRegistrar.add("Pref.UpdateSliderText", boost::bind(&LLFloaterPreference::onUpdateSliderText,this, _1,_2));
- mCommitCallbackRegistrar.add("Pref.QualityPerformance", boost::bind(&LLFloaterPreference::onChangeQuality, this, _2));
+ mCommitCallbackRegistrar.add("Pref.HardwareSettings", boost::bind(&LLFloaterPreference::onOpenHardwareSettings, this));
+ mCommitCallbackRegistrar.add("Pref.HardwareDefaults", boost::bind(&LLFloaterPreference::setHardwareDefaults, this));
+ mCommitCallbackRegistrar.add("Pref.VertexShaderEnable", boost::bind(&LLFloaterPreference::onVertexShaderEnable, this));
+ mCommitCallbackRegistrar.add("Pref.WindowedMod", boost::bind(&LLFloaterPreference::onCommitWindowedMode, this));
+ mCommitCallbackRegistrar.add("Pref.UpdateSliderText", boost::bind(&LLFloaterPreference::onUpdateSliderText,this, _1,_2));
+ mCommitCallbackRegistrar.add("Pref.QualityPerformance", boost::bind(&LLFloaterPreference::onChangeQuality, this, _2));
mCommitCallbackRegistrar.add("Pref.applyUIColor", boost::bind(&LLFloaterPreference::applyUIColor, this ,_1, _2));
mCommitCallbackRegistrar.add("Pref.getUIColor", boost::bind(&LLFloaterPreference::getUIColor, this ,_1, _2));
mCommitCallbackRegistrar.add("Pref.MaturitySettings", boost::bind(&LLFloaterPreference::onChangeMaturity, this));
mCommitCallbackRegistrar.add("Pref.BlockList", boost::bind(&LLFloaterPreference::onClickBlockList, this));
+ mCommitCallbackRegistrar.add("Pref.Proxy", boost::bind(&LLFloaterPreference::onClickProxySettings, this));
sSkin = gSavedSettings.getString("SkinCurrent");
@@ -457,7 +459,7 @@ BOOL LLFloaterPreference::postBuild()
void LLFloaterPreference::onBusyResponseChanged()
{
// set "BusyResponseChanged" TRUE if user edited message differs from default, FALSE otherwise
- if(LLTrans::getString("BusyModeResponseDefault") != getChild<LLUICtrl>("busy_response")->getValue().asString())
+ if (LLTrans::getString("BusyModeResponseDefault") != getChild<LLUICtrl>("busy_response")->getValue().asString())
{
gSavedPerAccountSettings.setBOOL("BusyResponseChanged", TRUE );
}
@@ -539,7 +541,7 @@ void LLFloaterPreference::apply()
LLViewerMedia::setCookiesEnabled(getChild<LLUICtrl>("cookies_enabled")->getValue());
- if(hasChild("web_proxy_enabled") &&hasChild("web_proxy_editor") && hasChild("web_proxy_port"))
+ if (hasChild("web_proxy_enabled") &&hasChild("web_proxy_editor") && hasChild("web_proxy_port"))
{
bool proxy_enable = getChild<LLUICtrl>("web_proxy_enabled")->getValue();
std::string proxy_address = getChild<LLUICtrl>("web_proxy_editor")->getValue();
@@ -552,13 +554,13 @@ void LLFloaterPreference::apply()
gSavedSettings.setBOOL("PlainTextChatHistory", getChild<LLUICtrl>("plain_text_chat_history")->getValue().asBoolean());
- if(mGotPersonalInfo)
+ if (mGotPersonalInfo)
{
// gSavedSettings.setString("BusyModeResponse2", std::string(wstring_to_utf8str(busy_response)));
bool new_im_via_email = getChild<LLUICtrl>("send_im_to_email")->getValue().asBoolean();
bool new_hide_online = getChild<LLUICtrl>("online_visibility")->getValue().asBoolean();
- if((new_im_via_email != mOriginalIMViaEmail)
+ if ((new_im_via_email != mOriginalIMViaEmail)
||(new_hide_online != mOriginalHideOnlineStatus))
{
// This hack is because we are representing several different
@@ -566,13 +568,13 @@ void LLFloaterPreference::apply()
// can only select between 2 values, we represent it as a
// checkbox. This breaks down a little bit for liaisons, but
// works out in the end.
- if(new_hide_online != mOriginalHideOnlineStatus)
- {
- if(new_hide_online) mDirectoryVisibility = VISIBILITY_HIDDEN;
+ if (new_hide_online != mOriginalHideOnlineStatus)
+ {
+ if (new_hide_online) mDirectoryVisibility = VISIBILITY_HIDDEN;
else mDirectoryVisibility = VISIBILITY_DEFAULT;
//Update showonline value, otherwise multiple applys won't work
mOriginalHideOnlineStatus = new_hide_online;
- }
+ }
gAgent.sendAgentUpdateUserInfo(new_im_via_email,mDirectoryVisibility);
}
}
@@ -616,6 +618,11 @@ void LLFloaterPreference::cancel()
updateDoubleClickControls();
mDoubleClickActionDirty = false;
}
+ LLFloaterPreferenceProxy * advanced_proxy_settings = LLFloaterReg::findTypedInstance<LLFloaterPreferenceProxy>("prefs_proxy");
+ if (advanced_proxy_settings)
+ {
+ advanced_proxy_settings->cancel();
+ }
}
void LLFloaterPreference::onOpen(const LLSD& key)
@@ -799,7 +806,7 @@ void LLFloaterPreference::onBtnCancel()
void LLFloaterPreference::updateUserInfo(const std::string& visibility, bool im_via_email, const std::string& email)
{
LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences");
- if(instance)
+ if (instance)
{
instance->setPersonalInfo(visibility, im_via_email, email);
}
@@ -809,7 +816,7 @@ void LLFloaterPreference::updateUserInfo(const std::string& visibility, bool im_
void LLFloaterPreference::refreshEnabledGraphics()
{
LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences");
- if(instance)
+ if (instance)
{
instance->refresh();
//instance->refreshEnabledState();
@@ -1096,7 +1103,7 @@ void LLFloaterPreference::disableUnavailableSettings()
LLCheckBoxCtrl* ctrl_dof = getChild<LLCheckBoxCtrl>("UseDoF");
// if vertex shaders off, disable all shader related products
- if(!LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable"))
+ if (!LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable"))
{
ctrl_shader_enable->setEnabled(FALSE);
ctrl_shader_enable->setValue(FALSE);
@@ -1127,7 +1134,7 @@ void LLFloaterPreference::disableUnavailableSettings()
}
// disabled windlight
- if(!LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders"))
+ if (!LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders"))
{
ctrl_wind_light->setEnabled(FALSE);
ctrl_wind_light->setValue(FALSE);
@@ -1164,28 +1171,28 @@ void LLFloaterPreference::disableUnavailableSettings()
}
// disabled deferred SSAO
- if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferredSSAO"))
+ if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferredSSAO"))
{
ctrl_ssao->setEnabled(FALSE);
ctrl_ssao->setValue(FALSE);
}
// disabled deferred shadows
- if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderShadowDetail"))
+ if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderShadowDetail"))
{
ctrl_shadows->setEnabled(FALSE);
ctrl_shadows->setValue(0);
}
// disabled reflections
- if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderReflectionDetail"))
+ if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderReflectionDetail"))
{
ctrl_reflections->setEnabled(FALSE);
ctrl_reflections->setValue(FALSE);
}
// disabled av
- if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarVP"))
+ if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarVP"))
{
ctrl_avatar_vp->setEnabled(FALSE);
ctrl_avatar_vp->setValue(FALSE);
@@ -1208,14 +1215,14 @@ void LLFloaterPreference::disableUnavailableSettings()
}
// disabled cloth
- if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarCloth"))
+ if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarCloth"))
{
ctrl_avatar_cloth->setEnabled(FALSE);
ctrl_avatar_cloth->setValue(FALSE);
}
// disabled impostors
- if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderUseImpostors"))
+ if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderUseImpostors"))
{
ctrl_avatar_impostors->setEnabled(FALSE);
ctrl_avatar_impostors->setValue(FALSE);
@@ -1381,12 +1388,12 @@ void LLFloaterPreference::setPersonalInfo(const std::string& visibility, bool im
mOriginalIMViaEmail = im_via_email;
mDirectoryVisibility = visibility;
- if(visibility == VISIBILITY_DEFAULT)
+ if (visibility == VISIBILITY_DEFAULT)
{
mOriginalHideOnlineStatus = false;
getChildView("online_visibility")->setEnabled(TRUE);
}
- else if(visibility == VISIBILITY_HIDDEN)
+ else if (visibility == VISIBILITY_HIDDEN)
{
mOriginalHideOnlineStatus = true;
getChildView("online_visibility")->setEnabled(TRUE);
@@ -1434,7 +1441,7 @@ void LLFloaterPreference::onUpdateSliderText(LLUICtrl* ctrl, const LLSD& name)
{
std::string ctrl_name = name.asString();
- if((ctrl_name =="" )|| !hasChild(ctrl_name, true))
+ if ((ctrl_name =="" )|| !hasChild(ctrl_name, true))
return;
LLTextBox* text_box = getChild<LLTextBox>(name.asString());
@@ -1444,7 +1451,7 @@ void LLFloaterPreference::onUpdateSliderText(LLUICtrl* ctrl, const LLSD& name)
void LLFloaterPreference::updateSliderText(LLSliderCtrl* ctrl, LLTextBox* text_box)
{
- if(text_box == NULL || ctrl== NULL)
+ if (text_box == NULL || ctrl== NULL)
return;
// get range and points when text should change
@@ -1457,7 +1464,7 @@ void LLFloaterPreference::updateSliderText(LLSliderCtrl* ctrl, LLTextBox* text_b
F32 highPoint = min + (2.0f * range / 3.0f);
// choose the right text
- if(value < midPoint)
+ if (value < midPoint)
{
text_box->setText(LLTrans::getString("GraphicsQualityLow"));
}
@@ -1541,6 +1548,11 @@ void LLFloaterPreference::updateDoubleClickSettings()
}
}
+void LLFloaterPreference::onClickProxySettings()
+{
+ LLFloaterReg::showInstance("prefs_proxy");
+}
+
void LLFloaterPreference::updateDoubleClickControls()
{
// check is one of double-click actions settings enabled
@@ -1637,7 +1649,7 @@ BOOL LLPanelPreference::postBuild()
{
////////////////////// PanelVoice ///////////////////
- if(hasChild("voice_unavailable"))
+ if (hasChild("voice_unavailable"))
{
BOOL voice_disabled = gSavedSettings.getBOOL("CmdLineDisableVoice");
getChildView("voice_unavailable")->setVisible( voice_disabled);
@@ -1659,7 +1671,7 @@ BOOL LLPanelPreference::postBuild()
}
- if(hasChild("online_visibility") && hasChild("send_im_to_email"))
+ if (hasChild("online_visibility") && hasChild("send_im_to_email"))
{
getChild<LLUICtrl>("email_address")->setValue(getString("log_in_to_change") );
// getChild<LLUICtrl>("busy_response")->setValue(getString("log_in_to_change"));
@@ -1788,7 +1800,7 @@ void LLPanelPreference::cancel()
iter != mSavedColors.end(); ++iter)
{
LLColorSwatchCtrl* color_swatch = findChild<LLColorSwatchCtrl>(iter->first);
- if(color_swatch)
+ if (color_swatch)
{
color_swatch->set(iter->second);
color_swatch->onCommit();
@@ -1832,7 +1844,7 @@ void LLPanelPreferenceGraphics::draw()
LLButton* button_apply = findChild<LLButton>("Apply");
- if(button_apply && button_apply->getVisible())
+ if (button_apply && button_apply->getVisible())
{
bool enable = hasDirtyChilds();
@@ -1852,7 +1864,7 @@ bool LLPanelPreferenceGraphics::hasDirtyChilds()
LLUICtrl* ctrl = dynamic_cast<LLUICtrl*>(curview);
if (ctrl)
{
- if(ctrl->isDirty())
+ if (ctrl->isDirty())
return true;
}
// Push children onto the end of the work stack
@@ -1908,3 +1920,188 @@ void LLPanelPreferenceGraphics::setHardwareDefaults()
resetDirtyChilds();
LLPanelPreference::setHardwareDefaults();
}
+
+LLFloaterPreferenceProxy::LLFloaterPreferenceProxy(const LLSD& key)
+ : LLFloater(key),
+ mSocksSettingsDirty(false)
+{
+ mCommitCallbackRegistrar.add("Proxy.OK", boost::bind(&LLFloaterPreferenceProxy::onBtnOk, this));
+ mCommitCallbackRegistrar.add("Proxy.Cancel", boost::bind(&LLFloaterPreferenceProxy::onBtnCancel, this));
+ mCommitCallbackRegistrar.add("Proxy.Change", boost::bind(&LLFloaterPreferenceProxy::onChangeSocksSettings, this));
+}
+
+LLFloaterPreferenceProxy::~LLFloaterPreferenceProxy()
+{
+}
+
+BOOL LLFloaterPreferenceProxy::postBuild()
+{
+ LLRadioGroup* socksAuth = getChild<LLRadioGroup>("socks5_auth_type");
+ if (!socksAuth)
+ {
+ return FALSE;
+ }
+ if (socksAuth->getSelectedValue().asString() == "None")
+ {
+ getChild<LLLineEditor>("socks5_username")->setEnabled(false);
+ getChild<LLLineEditor>("socks5_password")->setEnabled(false);
+ }
+ else
+ {
+ // Populate the SOCKS 5 credential fields with protected values.
+ LLPointer<LLCredential> socks_cred = gSecAPIHandler->loadCredential("SOCKS5");
+ getChild<LLLineEditor>("socks5_username")->setValue(socks_cred->getIdentifier()["username"].asString());
+ getChild<LLLineEditor>("socks5_password")->setValue(socks_cred->getAuthenticator()["creds"].asString());
+ }
+
+ center();
+ return TRUE;
+}
+
+void LLFloaterPreferenceProxy::onOpen(const LLSD& key)
+{
+ saveSettings();
+}
+
+void LLFloaterPreferenceProxy::onClose(bool app_quitting)
+{
+ if (mSocksSettingsDirty)
+ {
+
+ // If the user plays with the Socks proxy settings after login, it's only fair we let them know
+ // it will not be updated until next restart.
+ if (LLStartUp::getStartupState()>STATE_LOGIN_WAIT)
+ {
+ LLNotifications::instance().add("ChangeProxySettings", LLSD(), LLSD());
+ mSocksSettingsDirty = false; // we have notified the user now be quiet again
+ }
+ }
+}
+
+void LLFloaterPreferenceProxy::saveSettings()
+{
+ // Save the value of all controls in the hierarchy
+ mSavedValues.clear();
+ std::list<LLView*> view_stack;
+ view_stack.push_back(this);
+ while(!view_stack.empty())
+ {
+ // Process view on top of the stack
+ LLView* curview = view_stack.front();
+ view_stack.pop_front();
+
+ LLUICtrl* ctrl = dynamic_cast<LLUICtrl*>(curview);
+ if (ctrl)
+ {
+ LLControlVariable* control = ctrl->getControlVariable();
+ if (control)
+ {
+ mSavedValues[control] = control->getValue();
+ }
+ }
+
+ // Push children onto the end of the work stack
+ for (child_list_t::const_iterator iter = curview->getChildList()->begin();
+ iter != curview->getChildList()->end(); ++iter)
+ {
+ view_stack.push_back(*iter);
+ }
+ }
+}
+
+void LLFloaterPreferenceProxy::onBtnOk()
+{
+ // commit any outstanding text entry
+ if (hasFocus())
+ {
+ LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus());
+ if (cur_focus && cur_focus->acceptsTextInput())
+ {
+ cur_focus->onCommit();
+ }
+ }
+
+ // Save SOCKS proxy credentials securely if password auth is enabled
+ LLRadioGroup* socksAuth = getChild<LLRadioGroup>("socks5_auth_type");
+ if (socksAuth->getSelectedValue().asString() == "UserPass")
+ {
+ LLSD socks_id = LLSD::emptyMap();
+ socks_id["type"] = "SOCKS5";
+ socks_id["username"] = getChild<LLLineEditor>("socks5_username")->getValue().asString();
+
+ LLSD socks_authenticator = LLSD::emptyMap();
+ socks_authenticator["type"] = "SOCKS5";
+ socks_authenticator["creds"] = getChild<LLLineEditor>("socks5_password")->getValue().asString();
+
+ // Using "SOCKS5" as the "grid" argument since the same proxy
+ // settings will be used for all grids and because there is no
+ // way to specify the type of credential.
+ LLPointer<LLCredential> socks_cred = gSecAPIHandler->createCredential("SOCKS5", socks_id, socks_authenticator);
+ gSecAPIHandler->saveCredential(socks_cred, true);
+ }
+ else
+ {
+ // Clear SOCKS5 credentials since they are no longer needed.
+ LLPointer<LLCredential> socks_cred = new LLCredential("SOCKS5");
+ gSecAPIHandler->deleteCredential(socks_cred);
+ }
+
+ closeFloater(false);
+}
+
+void LLFloaterPreferenceProxy::onBtnCancel()
+{
+ if (hasFocus())
+ {
+ LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus());
+ if (cur_focus && cur_focus->acceptsTextInput())
+ {
+ cur_focus->onCommit();
+ }
+ refresh();
+ }
+
+ cancel();
+}
+
+void LLFloaterPreferenceProxy::cancel()
+{
+
+ for (control_values_map_t::iterator iter = mSavedValues.begin();
+ iter != mSavedValues.end(); ++iter)
+ {
+ LLControlVariable* control = iter->first;
+ LLSD ctrl_value = iter->second;
+ control->set(ctrl_value);
+ }
+
+ closeFloater();
+}
+
+void LLFloaterPreferenceProxy::onChangeSocksSettings()
+{
+ mSocksSettingsDirty = true;
+
+ LLRadioGroup* socksAuth = getChild<LLRadioGroup>("socks5_auth_type");
+ if (socksAuth->getSelectedValue().asString() == "None")
+ {
+ getChild<LLLineEditor>("socks5_username")->setEnabled(false);
+ getChild<LLLineEditor>("socks5_password")->setEnabled(false);
+ }
+ else
+ {
+ getChild<LLLineEditor>("socks5_username")->setEnabled(true);
+ getChild<LLLineEditor>("socks5_password")->setEnabled(true);
+ }
+
+ // Check for invalid states for the other HTTP proxy radio
+ LLRadioGroup* otherHttpProxy = getChild<LLRadioGroup>("other_http_proxy_type");
+ if ((otherHttpProxy->getSelectedValue().asString() == "Socks" &&
+ getChild<LLCheckBoxCtrl>("socks_proxy_enabled")->get() == FALSE )||(
+ otherHttpProxy->getSelectedValue().asString() == "Web" &&
+ getChild<LLCheckBoxCtrl>("web_proxy_enabled")->get() == FALSE ) )
+ {
+ otherHttpProxy->selectFirstItem();
+ }
+
+};
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 61f2c78640..ef9bc2dd53 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -156,6 +156,7 @@ public:
void applyResolution();
void onChangeMaturity();
void onClickBlockList();
+ void onClickProxySettings();
void applyUIColor(LLUICtrl* ctrl, const LLSD& param);
void getUIColor(LLUICtrl* ctrl, const LLSD& param);
@@ -229,4 +230,33 @@ protected:
};
+class LLFloaterPreferenceProxy : public LLFloater
+{
+public:
+ LLFloaterPreferenceProxy(const LLSD& key);
+ ~LLFloaterPreferenceProxy();
+
+ /// show off our menu
+ static void show();
+ void cancel();
+
+protected:
+ BOOL postBuild();
+ void onOpen(const LLSD& key);
+ void onClose(bool app_quitting);
+ void saveSettings();
+ void onBtnOk();
+ void onBtnCancel();
+
+ void onChangeSocksSettings();
+
+private:
+
+ bool mSocksSettingsDirty;
+ typedef std::map<LLControlVariable*, LLSD> control_values_map_t;
+ control_values_map_t mSavedValues;
+
+};
+
+
#endif // LL_LLPREFERENCEFLOATER_H
diff --git a/indra/newview/llloginhandler.cpp b/indra/newview/llloginhandler.cpp
index 48be251611..9b4f146332 100644
--- a/indra/newview/llloginhandler.cpp
+++ b/indra/newview/llloginhandler.cpp
@@ -30,13 +30,13 @@
// viewer includes
#include "llsecapi.h"
-#include "lllogininstance.h" // to check if logged in yet
-#include "llpanellogin.h" // save_password_to_disk()
+#include "lllogininstance.h" // to check if logged in yet
+#include "llpanellogin.h"
#include "llstartup.h" // getStartupState()
#include "llslurl.h"
#include "llviewercontrol.h" // gSavedSettings
#include "llviewernetwork.h" // EGridInfo
-#include "llviewerwindow.h" // getWindow()
+#include "llviewerwindow.h" // getWindow()
// library includes
#include "llmd5.h"
diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h
index b29b3af7ca..4078eedc77 100644
--- a/indra/newview/llpanellogin.h
+++ b/indra/newview/llpanellogin.h
@@ -113,7 +113,4 @@ private:
static BOOL sCapslockDidNotification;
};
-std::string load_password_from_disk(void);
-void save_password_to_disk(const char* hashed_password);
-
#endif
diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h
index 8e4c2c56c6..0935a0005b 100644
--- a/indra/newview/llsecapi.h
+++ b/indra/newview/llsecapi.h
@@ -286,8 +286,8 @@ bool operator!=(const LLCertificateVector::iterator& _lhs, const LLCertificateVe
#define CRED_AUTHENTICATOR_TYPE_HASH "hash"
//
// LLCredential - interface for credentials providing the following functionality:
-// * persistance of credential information based on grid (for saving username/password)
-// * serialization to an OGP identifier/authenticator pair
+// * Persistence of credential information based on grid (for saving username/password)
+// * Serialization to an OGP identifier/authenticator pair
//
class LLCredential : public LLRefCount
{
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 880b437404..749acea6c1 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -126,6 +126,7 @@
#include "llpanelgroupnotices.h"
#include "llpreview.h"
#include "llpreviewscript.h"
+#include "llproxy.h"
#include "llproductinforequest.h"
#include "llsecondlifeurls.h"
#include "llselectmgr.h"
@@ -386,6 +387,14 @@ bool idle_startup()
LLNotificationsUtil::add(gViewerWindow->getInitAlert());
}
+ //-------------------------------------------------
+ // Init the SOCKS 5 proxy if the user has configured
+ // one. We need to do this early in case the user
+ // is using SOCKS for HTTP so we get the login
+ // screen and HTTP tables via SOCKS.
+ //-------------------------------------------------
+ LLStartUp::startLLProxy();
+
gSavedSettings.setS32("LastFeatureVersion", LLFeatureManager::getInstance()->getVersion());
gSavedSettings.setS32("LastGPUClass", LLFeatureManager::getInstance()->getGPUClass());
@@ -591,7 +600,7 @@ bool idle_startup()
}
LL_INFOS("AppInit") << "Message System Initialized." << LL_ENDL;
-
+
//-------------------------------------------------
// Init audio, which may be needed for prefs dialog
// or audio cues in connection UI.
@@ -800,7 +809,21 @@ bool idle_startup()
if (STATE_LOGIN_CLEANUP == LLStartUp::getStartupState())
{
- //reset the values that could have come in from a slurl
+ // Post login screen, we should see if any settings have changed that may
+ // require us to either start/stop or change the socks proxy. As various communications
+ // past this point may require the proxy to be up.
+ if (!LLStartUp::startLLProxy())
+ {
+ // Proxy start up failed, we should now bail the state machine
+ // startLLProxy() will have reported an error to the user
+ // already, so we just go back to the login screen. The user
+ // could then change the preferences to fix the issue.
+
+ LLStartUp::setStartupState(STATE_LOGIN_SHOW);
+ return FALSE;
+ }
+
+ // reset the values that could have come in from a slurl
// DEV-42215: Make sure they're not empty -- gUserCredential
// might already have been set from gSavedSettings, and it's too bad
// to overwrite valid values with empty strings.
@@ -2768,6 +2791,171 @@ void LLStartUp::setStartSLURL(const LLSLURL& slurl)
}
}
+/**
+ * Read all proxy configuration settings and set up both the HTTP proxy and
+ * SOCKS proxy as needed.
+ *
+ * Any errors that are encountered will result in showing the user a notification.
+ * When an error is encountered,
+ *
+ * @return Returns true if setup was successful, false if an error was encountered.
+ */
+bool LLStartUp::startLLProxy()
+{
+ bool proxy_ok = true;
+ std::string httpProxyType = gSavedSettings.getString("HttpProxyType");
+
+ // Set up SOCKS proxy (if needed)
+ if (gSavedSettings.getBOOL("Socks5ProxyEnabled"))
+ {
+ // Determine and update LLProxy with the saved authentication system
+ std::string auth_type = gSavedSettings.getString("Socks5AuthType");
+
+ if (auth_type.compare("UserPass") == 0)
+ {
+ LLPointer<LLCredential> socks_cred = gSecAPIHandler->loadCredential("SOCKS5");
+ std::string socks_user = socks_cred->getIdentifier()["username"].asString();
+ std::string socks_password = socks_cred->getAuthenticator()["creds"].asString();
+
+ bool ok = LLProxy::getInstance()->setAuthPassword(socks_user, socks_password);
+
+ if (!ok)
+ {
+ LLNotificationsUtil::add("SOCKS_BAD_CREDS");
+ proxy_ok = false;
+ }
+ }
+ else if (auth_type.compare("None") == 0)
+ {
+ LLProxy::getInstance()->setAuthNone();
+ }
+ else
+ {
+ LL_WARNS("Proxy") << "Invalid SOCKS 5 authentication type."<< LL_ENDL;
+
+ // Unknown or missing setting.
+ gSavedSettings.setString("Socks5AuthType", "None");
+
+ // Clear the SOCKS credentials.
+ LLPointer<LLCredential> socks_cred = new LLCredential("SOCKS5");
+ gSecAPIHandler->deleteCredential(socks_cred);
+
+ LLProxy::getInstance()->setAuthNone();
+ }
+
+ if (proxy_ok)
+ {
+ // Start the proxy and check for errors
+ // If status != SOCKS_OK, stopSOCKSProxy() will already have been called when startSOCKSProxy() returns.
+ LLHost socks_host;
+ socks_host.setHostByName(gSavedSettings.getString("Socks5ProxyHost"));
+ socks_host.setPort(gSavedSettings.getU32("Socks5ProxyPort"));
+ int status = LLProxy::getInstance()->startSOCKSProxy(socks_host);
+
+ if (status != SOCKS_OK)
+ {
+ LLSD subs;
+ subs["HOST"] = gSavedSettings.getString("Socks5ProxyHost");
+ subs["PORT"] = (S32)gSavedSettings.getU32("Socks5ProxyPort");
+
+ std::string error_string;
+
+ switch(status)
+ {
+ case SOCKS_CONNECT_ERROR: // TCP Fail
+ error_string = "SOCKS_CONNECT_ERROR";
+ break;
+
+ case SOCKS_NOT_PERMITTED: // SOCKS 5 server rule set refused connection
+ error_string = "SOCKS_NOT_PERMITTED";
+ break;
+
+ case SOCKS_NOT_ACCEPTABLE: // Selected authentication is not acceptable to server
+ error_string = "SOCKS_NOT_ACCEPTABLE";
+ break;
+
+ case SOCKS_AUTH_FAIL: // Authentication failed
+ error_string = "SOCKS_AUTH_FAIL";
+ break;
+
+ case SOCKS_UDP_FWD_NOT_GRANTED: // UDP forward request failed
+ error_string = "SOCKS_UDP_FWD_NOT_GRANTED";
+ break;
+
+ case SOCKS_HOST_CONNECT_FAILED: // Failed to open a TCP channel to the socks server
+ error_string = "SOCKS_HOST_CONNECT_FAILED";
+ break;
+
+ case SOCKS_INVALID_HOST: // Improperly formatted host address or port.
+ error_string = "SOCKS_INVALID_HOST";
+ break;
+
+ default:
+ error_string = "SOCKS_UNKNOWN_STATUS"; // Something strange happened,
+ LL_WARNS("Proxy") << "Unknown return from LLProxy::startProxy(): " << status << LL_ENDL;
+ break;
+ }
+
+ LLNotificationsUtil::add(error_string, subs);
+ proxy_ok = false;
+ }
+ }
+ }
+ else
+ {
+ LLProxy::getInstance()->stopSOCKSProxy(); // ensure no UDP proxy is running and it's all cleaned up
+ }
+
+ if (proxy_ok)
+ {
+ // Determine the HTTP proxy type (if any)
+ if ((httpProxyType.compare("Web") == 0) && gSavedSettings.getBOOL("BrowserProxyEnabled"))
+ {
+ LLHost http_host;
+ http_host.setHostByName(gSavedSettings.getString("BrowserProxyAddress"));
+ http_host.setPort(gSavedSettings.getS32("BrowserProxyPort"));
+ if (!LLProxy::getInstance()->enableHTTPProxy(http_host, LLPROXY_HTTP))
+ {
+ LLSD subs;
+ subs["HOST"] = http_host.getIPString();
+ subs["PORT"] = (S32)http_host.getPort();
+ LLNotificationsUtil::add("PROXY_INVALID_HTTP_HOST", subs);
+ proxy_ok = false;
+ }
+ }
+ else if ((httpProxyType.compare("Socks") == 0) && gSavedSettings.getBOOL("Socks5ProxyEnabled"))
+ {
+ LLHost socks_host;
+ socks_host.setHostByName(gSavedSettings.getString("Socks5ProxyHost"));
+ socks_host.setPort(gSavedSettings.getU32("Socks5ProxyPort"));
+ if (!LLProxy::getInstance()->enableHTTPProxy(socks_host, LLPROXY_SOCKS))
+ {
+ LLSD subs;
+ subs["HOST"] = socks_host.getIPString();
+ subs["PORT"] = (S32)socks_host.getPort();
+ LLNotificationsUtil::add("PROXY_INVALID_SOCKS_HOST", subs);
+ proxy_ok = false;
+ }
+ }
+ else if (httpProxyType.compare("None") == 0)
+ {
+ LLProxy::getInstance()->disableHTTPProxy();
+ }
+ else
+ {
+ LL_WARNS("Proxy") << "Invalid other HTTP proxy configuration."<< LL_ENDL;
+
+ // Set the missing or wrong configuration back to something valid.
+ gSavedSettings.setString("HttpProxyType", "None");
+ LLProxy::getInstance()->disableHTTPProxy();
+
+ // Leave proxy_ok alone, since this isn't necessarily fatal.
+ }
+ }
+
+ return proxy_ok;
+}
+
bool login_alert_done(const LLSD& notification, const LLSD& response)
{
LLPanelLogin::giveFocus();
diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h
index b3d9ef1dcc..99a644eb9c 100644
--- a/indra/newview/llstartup.h
+++ b/indra/newview/llstartup.h
@@ -113,6 +113,8 @@ public:
static void setStartSLURL(const LLSLURL& slurl);
static LLSLURL& getStartSLURL() { return sStartSLURL; }
+ static bool startLLProxy(); // Initialize the SOCKS 5 proxy
+
private:
static LLSLURL sStartSLURL;
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index dd0989d608..fecc6d91bd 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -232,6 +232,7 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("postcard", "floater_postcard.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPostcard>);
LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreference>);
+ LLFloaterReg::add("prefs_proxy", "floater_preferences_proxy.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreferenceProxy>);
LLFloaterReg::add("prefs_hardware_settings", "floater_hardware_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHardwareSettings>);
LLFloaterReg::add("perm_prefs", "floater_perm_prefs.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPerms>);
LLFloaterReg::add("pref_joystick", "floater_joystick.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterJoystick>);
diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp
index bd1d2ed7a7..f483ba5af8 100644
--- a/indra/newview/llxmlrpctransaction.cpp
+++ b/indra/newview/llxmlrpctransaction.cpp
@@ -306,19 +306,8 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip)
mCurlRequest = new LLCurlEasyRequest();
}
mErrorCert = NULL;
-
- if (gSavedSettings.getBOOL("BrowserProxyEnabled"))
- {
- mProxyAddress = gSavedSettings.getString("BrowserProxyAddress");
- S32 port = gSavedSettings.getS32 ( "BrowserProxyPort" );
-
- // tell curl about the settings
- mCurlRequest->setoptString(CURLOPT_PROXY, mProxyAddress);
- mCurlRequest->setopt(CURLOPT_PROXYPORT, port);
- mCurlRequest->setopt(CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
- }
-// mCurlRequest->setopt(CURLOPT_VERBOSE, 1); // usefull for debugging
+// mCurlRequest->setopt(CURLOPT_VERBOSE, 1); // useful for debugging
mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1);
mCurlRequest->setWriteCallback(&curlDownloadCallback, (void*)this);
BOOL vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert");
diff --git a/indra/newview/skins/default/xui/en/floater_preferences_proxy.xml b/indra/newview/skins/default/xui/en/floater_preferences_proxy.xml
new file mode 100644
index 0000000000..449731ab89
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_preferences_proxy.xml
@@ -0,0 +1,273 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ legacy_header_height="18"
+ height="500"
+ layout="topleft"
+ name="Proxy Settings Floater"
+ help_topic="proxysettings"
+ title="Proxy Settings"
+ width="500">
+ <check_box
+ control_name="BrowserProxyEnabled"
+ top="38"
+ enabled="true"
+ follows="left|top"
+ height="14"
+ initial_value="false"
+ commit_callback.function="Proxy.Change"
+ label="Use HTTP Proxy for Web pages"
+ left="22"
+ mouse_opaque="true"
+ name="web_proxy_enabled"
+ radio_style="false"
+ width="400"
+ top_pad="5" />
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="10"
+ left_delta="23"
+ layout="topleft"
+ name="Proxy location"
+ top_pad="10"
+ width="300">
+ HTTP Proxy:
+ </text>
+ <line_editor
+ control_name="BrowserProxyAddress"
+ enabled_control="BrowserProxyEnabled"
+ follows="left|top"
+ font="SansSerif"
+ height="23"
+ layout="topleft"
+ left_delta="0"
+ name="web_proxy_editor"
+ tool_tip="The DNS name or IP address of the HTTP proxy you would like to use."
+ top_pad="4"
+ width="200" />
+ <spinner
+ control_name="BrowserProxyPort"
+ enabled_control="BrowserProxyEnabled"
+ decimal_digits="0"
+ follows="left|top"
+ height="23"
+ increment="1"
+ initial_value="80"
+ label="Port number:"
+ label_width="95"
+ layout="topleft"
+ left_delta="210"
+ max_val="12000"
+ min_val="10"
+ name="web_proxy_port"
+ top_delta="0"
+ tool_tip="The port of the HTTP proxy you would like to use."
+ width="145" />
+ <check_box
+ control_name="Socks5ProxyEnabled"
+ height="16"
+ label="Use SOCKS 5 Proxy for UDP traffic"
+ layout="topleft"
+ left="22"
+ name="socks_proxy_enabled"
+ top_pad="32"
+ width="256"
+ commit_callback.function="Proxy.Change" />
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="10"
+ layout="topleft"
+ left_delta="23"
+ name="Proxy location"
+ top_pad="10"
+ width="300">
+ SOCKS 5 Proxy:
+ </text>
+ <line_editor
+ control_name="Socks5ProxyHost"
+ enabled_control="Socks5ProxyEnabled"
+ follows="left|top"
+ font="SansSerif"
+ height="23"
+ layout="topleft"
+ left_delta="0"
+ name="socks_proxy_editor"
+ tool_tip="The DNS name or IP address of the SOCKS 5 proxy you would like to use."
+ top_pad="4"
+ width="200"
+ commit_callback.function="Proxy.Change" />
+ <spinner
+ control_name="Socks5ProxyPort"
+ enabled_control="Socks5ProxyEnabled"
+ decimal_digits="0"
+ follows="left|top"
+ height="23"
+ increment="1"
+ initial_value="80"
+ label="Port number:"
+ label_width="95"
+ layout="topleft"
+ left_delta="210"
+ max_val="12000"
+ min_val="10"
+ name="socks_proxy_port"
+ top_delta="0"
+ width="145"
+ tool_tip="The port of the SOCKS 5 proxy you would like to use."
+ commit_callback.function="Proxy.Change" />
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="10"
+ layout="topleft"
+ left="40"
+ name="Proxy location"
+ top_pad="15"
+ width="300">
+ SOCKS Authentication:
+ </text>
+ <radio_group
+ control_name="Socks5AuthType"
+ enabled_control="Socks5ProxyEnabled"
+ height="50"
+ layout="topleft"
+ name="socks5_auth_type"
+ top_pad="10"
+ width="120"
+ commit_callback.function="Proxy.Change" >
+ <radio_item
+ height="16"
+ label="No Authentication"
+ layout="topleft"
+ name="Socks5NoAuth"
+ value="None"
+ tool_tip="Socks5 proxy requires no authentication."
+ width="120" />
+ <radio_item
+ height="16"
+ label="Username/Password"
+ layout="topleft"
+ name="Socks5UserPass"
+ value="UserPass"
+ tool_tip="Socks5 proxy requires username/password authentication."
+ width="120" />
+ </radio_group>
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="10"
+ layout="topleft"
+ left_delta="20"
+ top_delta="50"
+ width="200">
+ Username:
+ </text>
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="10"
+ left_pad="15"
+ layout="topleft"
+ width="200">
+ Password:
+ </text>
+ <line_editor
+ follows="left|top"
+ font="SansSerif"
+ height="23"
+ layout="topleft"
+ left="60"
+ name="socks5_username"
+ tool_tip="The username used to authenticate with your SOCKS 5 server"
+ top_pad="4"
+ width="200"
+ commit_callback.function="Proxy.Change" />
+ <line_editor
+ follows="left|top"
+ font="SansSerif"
+ height="23"
+ layout="topleft"
+ left_pad="15"
+ name="socks5_password"
+ tool_tip="The password used to authenticate with your SOCKS 5 server"
+ top_delta="0"
+ width="200"
+ is_password="true"
+ commit_callback.function="Proxy.Change" />
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="10"
+ layout="topleft"
+ left="25"
+ name="Proxy location"
+ top_pad="18"
+ width="300">
+ Other HTTP traffic proxy:
+ </text>
+ <radio_group
+ control_name="HttpProxyType"
+ name="other_http_proxy_type"
+ height="60"
+ layout="topleft"
+ top_pad="9"
+ width="120"
+ left_delta="15"
+ commit_callback.function="Proxy.Change" >
+ <radio_item
+ height="16"
+ label="Do not proxy"
+ layout="topleft"
+ name="OtherNoProxy"
+ value="None"
+ width="120"
+ tool_tip="Non-web HTTP traffic will NOT be sent to any proxy."/>
+ <radio_item
+ height="16"
+ label="Use HTTP Proxy"
+ layout="topleft"
+ name="OtherHTTPProxy"
+ value="Web"
+ width="120"
+ enabled_control="BrowserProxyEnabled"
+ tool_tip="Non-web HTTP will be sent through the configured Web proxy." />
+ <radio_item
+ height="16"
+ label="Use SOCKS 5 Proxy"
+ layout="topleft"
+ name="OtherSocksProxy"
+ value="Socks"
+ width="120"
+ enabled_control="Socks5ProxyEnabled"
+ tool_tip="Non-web HTTP traffic will be sent through the configured Socks 5 proxy."/>
+ </radio_group>
+ <button
+ follows="left|top"
+ height="22"
+ label="OK"
+ label_selected="OK"
+ layout="topleft"
+ left="282"
+ name="OK"
+ top_pad="36"
+ width="90"
+ commit_callback.function="Proxy.OK" />
+ <button
+ follows="left|top"
+ height="22"
+ label="Cancel"
+ label_selected="Cancel"
+ layout="topleft"
+ left_pad="10"
+ name="Cancel"
+ top_delta="0"
+ width="90"
+ commit_callback.function="Proxy.Cancel" />
+</floater>
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index c9ccd44b83..104bcaf7d0 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -7157,6 +7157,138 @@ Click and drag anywhere on the world to rotate your view
</notification>
<notification
+ icon="alertmodal.tga"
+ name="SOCKS_NOT_PERMITTED"
+ type="alertmodal">
+ The SOCKS 5 proxy "[HOST]:[PORT]" refused the connection, not allowed by rule set.
+ <tag>fail</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="SOCKS_CONNECT_ERROR"
+ type="alertmodal">
+ The SOCKS 5 proxy "[HOST]:[PORT]" refused the connection, could not open TCP channel.
+ <tag>fail</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="SOCKS_NOT_ACCEPTABLE"
+ type="alertmodal">
+ The SOCKS 5 proxy "[HOST]:[PORT]" refused the selected authentication system.
+ <tag>fail</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="SOCKS_AUTH_FAIL"
+ type="alertmodal">
+ The SOCKS 5 proxy "[HOST]:[PORT]" reported your credentials are invalid.
+ <tag>fail</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="SOCKS_UDP_FWD_NOT_GRANTED"
+ type="alertmodal">
+ The SOCKS 5 proxy "[HOST]:[PORT]" refused the UDP associate request.
+ <tag>fail</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="SOCKS_HOST_CONNECT_FAILED"
+ type="alertmodal">
+ Could not connect to SOCKS 5 proxy server "[HOST]:[PORT]".
+ <tag>fail</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="SOCKS_UNKNOWN_STATUS"
+ type="alertmodal">
+ Unknown proxy error with server "[HOST]:[PORT]".
+ <tag>fail</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="SOCKS_INVALID_HOST"
+ type="alertmodal">
+ Invalid SOCKS proxy address or port "[HOST]:[PORT]".
+ <tag>fail</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="SOCKS_BAD_CREDS"
+ type="alertmodal">
+ Invalid SOCKS 5 username or password.
+ <tag>fail</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="PROXY_INVALID_HTTP_HOST"
+ type="alertmodal">
+ Invalid HTTP proxy address or port "[HOST]:[PORT]".
+ <tag>fail</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="PROXY_INVALID_SOCKS_HOST"
+ type="alertmodal">
+ Invalid SOCKS proxy address or port "[HOST]:[PORT]".
+ <tag>fail</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="ChangeProxySettings"
+ type="alert">
+ Proxy settings take effect after you restart [APP_NAME].
+ <tag>fail</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
name="AuthRequest"
type="browser">
The site at &apos;&lt;nolink&gt;[HOST_NAME]&lt;/nolink&gt;&apos; in realm &apos;[REALM]&apos; requires a user name and password.
diff --git a/indra/newview/skins/default/xui/en/panel_cof_wearables.xml b/indra/newview/skins/default/xui/en/panel_cof_wearables.xml
index 9e70706603..beea53437a 100644
--- a/indra/newview/skins/default/xui/en/panel_cof_wearables.xml
+++ b/indra/newview/skins/default/xui/en/panel_cof_wearables.xml
@@ -52,7 +52,7 @@
multi_select="true"
name="list_attachments"
top="0"
- width="311"/>
+ width="311" />
</accordion_tab>
<accordion_tab
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml b/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml
index 30be5bc853..47236c1a48 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml
@@ -139,7 +139,7 @@
height="16"
label="Add datestamp to log file name."
layout="topleft"
- left_detla="5"
+ left_delta="5"
name="logfile_name_datestamp"
top_pad="10"
width="350"/>
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
index e639f0dc9d..a7078ce2e1 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
@@ -70,7 +70,7 @@
layout="topleft"
left="77"
name="connection_port_enabled"
- top_pad="20"
+ top_pad="10"
width="256">
<check_box.commit_callback
function="Notification.Show"
@@ -79,7 +79,7 @@
<spinner
control_name="ConnectionPort"
enabled_control="ConnectionPortEnabled"
- decimal_digits="0"
+ decimal_digits="0"
follows="left|top"
height="23"
increment="1"
@@ -195,60 +195,6 @@
name="media_popup_enabled"
width="400"
top_pad="5"/>
- <check_box
- top_delta="4"
- enabled="true"
- follows="left|top"
- height="14"
- initial_value="false"
- control_name="BrowserProxyEnabled"
- label="Enable Web Proxy"
- left_delta="0"
- mouse_opaque="true"
- name="web_proxy_enabled"
- radio_style="false"
- width="400" top_pad="5"/>
- <text
- type="string"
- length="1"
- follows="left|top"
- height="10"
- layout="topleft"
- left_delta="20"
- name="Proxy location"
- top_delta="16"
- width="300">
- Proxy location:
- </text>
- <line_editor
- control_name="BrowserProxyAddress"
- enabled_control="BrowserProxyEnabled"
- follows="left|top"
- font="SansSerif"
- height="23"
- layout="topleft"
- left_delta="0"
- name="web_proxy_editor"
- tool_tip="The name or IP address of the proxy you would like to use"
- top_pad="4"
- width="200" />
- <spinner
- control_name="BrowserProxyPort"
- enabled_control="BrowserProxyEnabled"
- decimal_digits="0"
- follows="left|top"
- height="23"
- increment="1"
- initial_value="80"
- label="Port number:"
- label_width="95"
- layout="topleft"
- left_delta="210"
- max_val="12000"
- min_val="10"
- name="web_proxy_port"
- top_delta="0"
- width="145" />
<text
type="string"
length="1"
@@ -286,4 +232,31 @@
name="Install_manual"
value="0" />
</combo_box>
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="10"
+ layout="topleft"
+ left="30"
+ name="Proxy Settings:"
+ mouse_opaque="false"
+ top_pad="5"
+ width="300">
+ Proxy Settings:
+ </text>
+ <button
+ label="Adjust proxy settings"
+ follows="left|top"
+ height="23"
+ width="140"
+ label_selected="Browse"
+ layout="topleft"
+ left_delta="50"
+ name="set_proxy"
+ top_pad="5"
+ >
+ <button.commit_callback
+ function="Pref.Proxy" />
+ </button>
</panel>