Files
SingularityViewer/indra/llmessage/llproxy.h
Lirusaito 433c7c3f99 Spelling fixes and stuff like that to AICurl* and llproxy.* documentations
Also removes a duplicate include from llares.cpp

Conflicts:
	indra/llmessage/aicurl.cpp
2012-06-28 04:08:25 -04:00

377 lines
14 KiB
C++

/**
* @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 "aithreadsafe.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()).
*
* To ensure thread safety, all LLProxy members that relate to the HTTP
* proxy require the LLProxyMutex to be locked before accessing.
*/
struct ProxyUnshared
{
/*###########################################################################################
MEMBERS READ AND WRITTEN ONLY IN THE MAIN THREAD.
###########################################################################################*/
// 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;
/*###########################################################################################
END OF UNSHARED MEMBERS
###########################################################################################*/
};
struct ProxyShared
{
ProxyShared(void);
/*###########################################################################################
MEMBERS WRITTEN IN MAIN THREAD AND READ IN ANY THREAD.
###########################################################################################*/
// HTTP proxy address and port
LLHost mHTTPProxy;
// Currently selected HTTP proxy type. Can be web or SOCKS.
LLHttpProxyType mProxyType;
// SOCKS 5 selected authentication method.
LLSocks5AuthType mAuthMethodSelected;
// SOCKS 5 username
std::string mSocksUsername;
// SOCKS 5 password
std::string mSocksPassword;
/*###########################################################################################
END OF SHARED MEMBERS
###########################################################################################*/
};
class LLProxy: public LLSingleton<LLProxy>
{
LOG_CLASS(LLProxy);
public:
typedef AISTAccessConst<ProxyUnshared> Unshared_crat; // Constant Read Access Type for Unshared (cannot be converted to write access).
typedef AISTAccess<ProxyUnshared> Unshared_rat; // Read Access Type for Unshared (same as write access type, since we don't lock at all).
typedef AISTAccess<ProxyUnshared> Unshared_wat; // Write Access Type, for Unshared.
typedef AIReadAccessConst<ProxyShared> Shared_crat; // Constant Read Access Type for Shared (cannot be converted to write access).
typedef AIReadAccess<ProxyShared> Shared_rat; // Read Access Type for Shared.
typedef AIWriteAccess<ProxyShared> Shared_wat; // Write Access Type for Shared.
/*###########################################################################################
Public methods that only access variables not shared between threads.
###########################################################################################*/
// Constructor, cannot have parameters due to LLSingleton parent class. Call from main thread only.
LLProxy();
// Static check for enabled status for UDP packets. Called from main thread only.
static bool isSOCKSProxyEnabled(void) { llassert(is_main_thread()); return sUDPProxyEnabled; }
// Get the UDP proxy address and port. Called from main thread only.
LLHost getUDPProxy(void) const { return Unshared_crat(mUnshared)->mUDPProxy; }
/*###########################################################################################
End of methods that only access variables not shared between threads.
###########################################################################################*/
// Return true if there is a good chance that the HTTP proxy is currently enabled.
bool HTTPProxyEnabled(void) const { return mHTTPProxyEnabled; }
/*###########################################################################################
Public methods that access variables shared between threads.
###########################################################################################*/
// Destructor, closes open connections. Do not call directly, use cleanupClass().
~LLProxy();
// Delete LLProxy singleton. Allows the apr_socket used in the SOCKS 5 control channel to be
// destroyed before the call to apr_terminate. Call from main thread only.
static void cleanupClass();
// Apply the current proxy settings to a curl request. Doesn't do anything if mHTTPProxyEnabled is false.
// Safe to call from any thread.
void applyProxySettings(AICurlEasyRequest_wat const& curlEasyRequest_w);
// Start a connection to the SOCKS 5 proxy. Call from main thread only.
S32 startSOCKSProxy(LLHost host);
// Disconnect and clean up any connection to the SOCKS 5 proxy. Call from main thread only.
void stopSOCKSProxy();
// Use Password auth when connecting to the SOCKS proxy. Call from main thread only.
bool setAuthPassword(const std::string &username, const std::string &password);
// Disable authentication when connecting to the SOCKS proxy. Call from main thread only.
void setAuthNone();
// Proxy HTTP packets via httpHost, which can be a SOCKS 5 or a HTTP proxy.
// as specified in type. Call from main thread only.
bool enableHTTPProxy(LLHost httpHost, LLHttpProxyType type);
bool enableHTTPProxy();
// Stop proxying HTTP packets. Call from main thread only.
// Note that this needs shared_w to be passed because we want the shared members to be locked when this is reset to false.
void disableHTTPProxy(Shared_wat const& shared_w) { mHTTPProxyEnabled = false; }
void disableHTTPProxy(void) { disableHTTPProxy(Shared_wat(mShared)); }
// Get the currently selected HTTP proxy address and port
LLHost const& getHTTPProxy(Shared_crat const& shared_r) const { return shared_r->mHTTPProxy; }
// Get the currently selected HTTP proxy type
LLHttpProxyType getHTTPProxyType(Shared_crat const& shared_r) const { return shared_r->mProxyType; }
// Get the currently selected auth method.
LLSocks5AuthType getSelectedAuthMethod(Shared_crat const& shared_r) const { return shared_r->mAuthMethodSelected; }
// SOCKS 5 username and password accessors.
std::string getSocksUser(Shared_crat const& shared_r) const { return shared_r->mSocksUsername; }
std::string getSocksPwd(Shared_crat const& shared_r) const { return shared_r->mSocksPassword; }
/*###########################################################################################
End of methods that access variables shared between threads.
###########################################################################################*/
private:
/*###########################################################################################
Private methods that access variables shared between threads.
###########################################################################################*/
// Perform a SOCKS 5 authentication and UDP association with the proxy server.
S32 proxyHandshake(LLHost proxy);
/*###########################################################################################
End of methods that access variables shared between threads.
###########################################################################################*/
private:
// Is the HTTP proxy enabled? Safe to read in any thread, but do not write directly.
// Instead use enableHTTPProxy() and disableHTTPProxy() instead.
mutable LLAtomic32<bool> mHTTPProxyEnabled;
// Is the UDP proxy enabled?
static bool sUDPProxyEnabled;
AIThreadSafeSingleThreadDC<ProxyUnshared> mUnshared;
AIThreadSafeDC<ProxyShared> mShared;
public:
// For thread-safe read access. Use the _crat access types with these.
AIThreadSafeSingleThreadDC<ProxyUnshared> const& unshared_lockobj(void) const { return mUnshared; }
AIThreadSafeDC<ProxyShared> const& shared_lockobj(void) const { return mShared; }
};
#endif