Always set proxy settings for every HTTP curl connection.
Move applyProxySettings to CurlEasyRequest and call it from applyDefaultOptions. Use AIThreadSafe for LLProxy for a more robust threadsafeness. (This forces correct locking, checks that the unshared vars are indeed unshared and made it easy to use read/write locking, which might be important in this case (we do a lot of read-only accesses to it).
This commit is contained in:
@@ -47,23 +47,22 @@ static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataou
|
||||
static LLSocket::ptr_t tcp_open_channel(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(),
|
||||
mUDPProxy(),
|
||||
mTCPProxy(),
|
||||
mHTTPProxy(),
|
||||
ProxyShared::ProxyShared(void):
|
||||
mProxyType(LLPROXY_SOCKS),
|
||||
mAuthMethodSelected(METHOD_NOAUTH),
|
||||
mSocksUsername(),
|
||||
mSocksPassword()
|
||||
mAuthMethodSelected(METHOD_NOAUTH)
|
||||
{
|
||||
}
|
||||
|
||||
LLProxy::LLProxy():
|
||||
mHTTPProxyEnabled(false)
|
||||
{
|
||||
}
|
||||
|
||||
LLProxy::~LLProxy()
|
||||
{
|
||||
stopSOCKSProxy();
|
||||
disableHTTPProxy();
|
||||
Shared_wat shared_w(mShared);
|
||||
disableHTTPProxy(shared_w);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,15 +77,18 @@ S32 LLProxy::proxyHandshake(LLHost proxy)
|
||||
{
|
||||
S32 result;
|
||||
|
||||
Unshared_rat unshared_r(mUnshared);
|
||||
Shared_rat shared_r(mShared);
|
||||
|
||||
/* 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.
|
||||
socks_auth_request.methods = getSelectedAuthMethod(shared_r); // Send only the selected method.
|
||||
|
||||
result = tcp_blocking_handshake(mProxyControlChannel,
|
||||
result = tcp_blocking_handshake(unshared_r->mProxyControlChannel,
|
||||
static_cast<char*>(static_cast<void*>(&socks_auth_request)),
|
||||
sizeof(socks_auth_request),
|
||||
static_cast<char*>(static_cast<void*>(&socks_auth_response)),
|
||||
@@ -109,8 +111,8 @@ S32 LLProxy::proxyHandshake(LLHost proxy)
|
||||
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());
|
||||
std::string socks_username(getSocksUser(shared_r));
|
||||
std::string socks_password(getSocksPwd(shared_r));
|
||||
U32 request_size = socks_username.size() + socks_password.size() + 3;
|
||||
char * password_auth = new char[request_size];
|
||||
password_auth[0] = 0x01;
|
||||
@@ -121,7 +123,7 @@ S32 LLProxy::proxyHandshake(LLHost proxy)
|
||||
|
||||
authmethod_password_reply_t password_reply;
|
||||
|
||||
result = tcp_blocking_handshake(mProxyControlChannel,
|
||||
result = tcp_blocking_handshake(unshared_r->mProxyControlChannel,
|
||||
password_auth,
|
||||
request_size,
|
||||
static_cast<char*>(static_cast<void*>(&password_reply)),
|
||||
@@ -157,7 +159,7 @@ S32 LLProxy::proxyHandshake(LLHost proxy)
|
||||
// "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_blocking_handshake(mProxyControlChannel,
|
||||
result = tcp_blocking_handshake(unshared_r->mProxyControlChannel,
|
||||
static_cast<char*>(static_cast<void*>(&connect_request)),
|
||||
sizeof(connect_request),
|
||||
static_cast<char*>(static_cast<void*>(&connect_reply)),
|
||||
@@ -176,10 +178,14 @@ S32 LLProxy::proxyHandshake(LLHost proxy)
|
||||
return SOCKS_UDP_FWD_NOT_GRANTED;
|
||||
}
|
||||
|
||||
mUDPProxy.setPort(ntohs(connect_reply.port)); // reply port is in network byte order
|
||||
mUDPProxy.setAddress(proxy.getAddress());
|
||||
{
|
||||
// Write acccess type and read access type are really the same, so unshared_w must be simply a reference.
|
||||
Unshared_wat& unshared_w = unshared_r;
|
||||
unshared_w->mUDPProxy.setPort(ntohs(connect_reply.port)); // reply port is in network byte order
|
||||
unshared_w->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;
|
||||
LL_INFOS("Proxy") << "SOCKS 5 UDP proxy connected on " << unshared_r->mUDPProxy << LL_ENDL;
|
||||
|
||||
return SOCKS_OK;
|
||||
}
|
||||
@@ -197,9 +203,11 @@ S32 LLProxy::proxyHandshake(LLHost proxy)
|
||||
*/
|
||||
S32 LLProxy::startSOCKSProxy(LLHost host)
|
||||
{
|
||||
Unshared_wat unshared_w(mUnshared);
|
||||
|
||||
if (host.isOk())
|
||||
{
|
||||
mTCPProxy = host;
|
||||
unshared_w->mTCPProxy = host;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -209,13 +217,13 @@ S32 LLProxy::startSOCKSProxy(LLHost host)
|
||||
// Close any running SOCKS connection.
|
||||
stopSOCKSProxy();
|
||||
|
||||
mProxyControlChannel = tcp_open_channel(mTCPProxy);
|
||||
if (!mProxyControlChannel)
|
||||
unshared_w->mProxyControlChannel = tcp_open_channel(unshared_w->mTCPProxy);
|
||||
if (!unshared_w->mProxyControlChannel)
|
||||
{
|
||||
return SOCKS_HOST_CONNECT_FAILED;
|
||||
}
|
||||
|
||||
S32 status = proxyHandshake(mTCPProxy);
|
||||
S32 status = proxyHandshake(unshared_w->mTCPProxy);
|
||||
|
||||
if (status != SOCKS_OK)
|
||||
{
|
||||
@@ -246,14 +254,16 @@ void LLProxy::stopSOCKSProxy()
|
||||
// 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())
|
||||
Shared_rat shared_r(mShared);
|
||||
if (LLPROXY_SOCKS == getHTTPProxyType(shared_r))
|
||||
{
|
||||
disableHTTPProxy();
|
||||
Shared_wat shared_w(shared_r);
|
||||
disableHTTPProxy(shared_w);
|
||||
}
|
||||
|
||||
if (mProxyControlChannel)
|
||||
Unshared_wat unshared_w(mUnshared);
|
||||
if (unshared_w->mProxyControlChannel)
|
||||
{
|
||||
tcp_close_channel(&mProxyControlChannel);
|
||||
tcp_close_channel(&unshared_w->mProxyControlChannel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,9 +272,7 @@ void LLProxy::stopSOCKSProxy()
|
||||
*/
|
||||
void LLProxy::setAuthNone()
|
||||
{
|
||||
LLMutexLock lock(&mProxyMutex);
|
||||
|
||||
mAuthMethodSelected = METHOD_NOAUTH;
|
||||
Shared_wat(mShared)->mAuthMethodSelected = METHOD_NOAUTH;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -288,11 +296,10 @@ bool LLProxy::setAuthPassword(const std::string &username, const std::string &pa
|
||||
return false;
|
||||
}
|
||||
|
||||
LLMutexLock lock(&mProxyMutex);
|
||||
|
||||
mAuthMethodSelected = METHOD_PASSWORD;
|
||||
mSocksUsername = username;
|
||||
mSocksPassword = password;
|
||||
Shared_wat shared_w(mShared);
|
||||
shared_w->mAuthMethodSelected = METHOD_PASSWORD;
|
||||
shared_w->mSocksUsername = username;
|
||||
shared_w->mSocksPassword = password;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -314,12 +321,10 @@ bool LLProxy::enableHTTPProxy(LLHost httpHost, LLHttpProxyType type)
|
||||
return false;
|
||||
}
|
||||
|
||||
LLMutexLock lock(&mProxyMutex);
|
||||
|
||||
mHTTPProxy = httpHost;
|
||||
mProxyType = type;
|
||||
|
||||
Shared_wat shared_w(mShared);
|
||||
mHTTPProxyEnabled = true;
|
||||
shared_w->mHTTPProxy = httpHost;
|
||||
shared_w->mProxyType = type;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -335,9 +340,8 @@ bool LLProxy::enableHTTPProxy()
|
||||
{
|
||||
bool ok;
|
||||
|
||||
LLMutexLock lock(&mProxyMutex);
|
||||
|
||||
ok = (mHTTPProxy.isOk());
|
||||
Shared_rat shared_r(mShared);
|
||||
ok = (shared_r->mHTTPProxy.isOk());
|
||||
if (ok)
|
||||
{
|
||||
mHTTPProxyEnabled = true;
|
||||
@@ -346,54 +350,6 @@ bool LLProxy::enableHTTPProxy()
|
||||
return ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable the HTTP proxy.
|
||||
*/
|
||||
void LLProxy::disableHTTPProxy()
|
||||
{
|
||||
LLMutexLock lock(&mProxyMutex);
|
||||
|
||||
mHTTPProxyEnabled = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*
|
||||
@@ -406,47 +362,6 @@ void LLProxy::cleanupClass()
|
||||
deleteSingleton();
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 curlEasyRequest_w An already locked curl easy handle, before it has been performed.
|
||||
*/
|
||||
void LLProxy::applyProxySettings(AICurlEasyRequest_wat const& curlEasyRequest_w)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
curlEasyRequest_w->setopt(CURLOPT_PROXY, mHTTPProxy.getIPString().c_str());
|
||||
curlEasyRequest_w->setopt(CURLOPT_PROXYPORT, mHTTPProxy.getPort());
|
||||
|
||||
if (mProxyType == LLPROXY_SOCKS)
|
||||
{
|
||||
curlEasyRequest_w->setopt(CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
|
||||
if (mAuthMethodSelected == METHOD_PASSWORD)
|
||||
{
|
||||
std::string auth_string = mSocksUsername + ":" + mSocksPassword;
|
||||
curlEasyRequest_w->setopt(CURLOPT_PROXYUSERPWD, auth_string.c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
curlEasyRequest_w->setopt(CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send one TCP packet and receive one in return.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user