www.pudn.com > eMule0.42e-Sources.zip > AsyncProxySocketLayer.cpp


/*CAsyncProxySocketLayer by Tim Kosse (Tim.Kosse@gmx.de) 
                 Version 1.6 (2003-03-26) 
-------------------------------------------------------- 
 
Introduction: 
------------- 
 
This class is layer class for CAsyncSocketEx. With this class you 
can connect through SOCKS4/5 and HTTP 1.1 proxies. This class works 
as semi-transparent layer between CAsyncSocketEx and the actual socket. 
This class is used in FileZilla, a powerful open-source FTP client. 
It can be found under http://sourceforge.net/projects/filezilla 
For more information about SOCKS4/5 goto 
http://www.socks.nec.com/socksprot.html 
For more information about HTTP 1.1 goto http://www.rfc-editor.org 
and search for RFC2616 
 
How to use? 
----------- 
 
You don't have to change much in you already existing code to use 
CAsyncProxySocketLayer. 
To use it, create an instance of CAsyncProxySocketLayer, call SetProxy 
and attach it to a CAsyncSocketEx instance. 
You have to process OnLayerCallback in you CAsyncSocketEx instance as it will 
receive all layer nofications. 
The following notifications are sent: 
 
//Error codes 
PROXYERROR_NOERROR 0 
PROXYERROR_NOCONN 1 //Can't connect to proxy server, use GetLastError for more information 
PROXYERROR_REQUESTFAILED 2 //Request failed, can't send data 
PROXYERROR_AUTHREQUIRED 3 //Authentication required 
PROXYERROR_AUTHTYPEUNKNOWN 4 //Authtype unknown or not supported 
PROXYERROR_AUTHFAILED 5  //Authentication failed 
PROXYERROR_AUTHNOLOGON 6 
PROXYERROR_CANTRESOLVEHOST 7 
 
//Status messages 
PROXYSTATUS_LISTENSOCKETCREATED 8 //Called when a listen socket was created successfully. Unlike the normal listen function, 
								//a socksified socket has to connect to the proxy to negotiate the details with the server 
								//on which the listen socket will be created 
								//The two parameters will contain the ip and port of the listen socket on the server. 
 
If you want to use CAsyncProxySocketLayer to create a listen socket, you 
have to use this overloaded function: 
BOOL PrepareListen(unsigned long serverIp); 
serverIP is the IP of the server you are already connected 
through the SOCKS proxy. You can't use listen sockets over a 
SOCKS proxy without a primary connection. Listen sockets are only 
supported by SOCKS proxies, this won't work with HTTP proxies. 
When the listen socket is created successfully, the PROXYSTATUS_LISTENSOCKETCREATED 
notification is sent. The parameters  will tell you the ip and the port of the listen socket. 
After it you have to handle the OnAccept message and accept the 
connection. 
Be carful when calling Accept: rConnected socket will NOT be filled! Instead use the instance which created the 
listen socket, it will handle the data connection. 
If you want to accept more than one connection, you have to create a listing socket for each of them! 
 
Description of important functions and their parameters: 
-------------------------------------------------------- 
 
void SetProxy(int nProxyType); 
void SetProxy(int nProxyType, const char * pProxyHost, int nProxyPort); 
void SetProxy(int nProxyType, const char * pProxyHost, int nProxyPort, const char *pProxyUser, const char * pProxyPass); 
 
Call one of this functions to set the proxy type. 
Parametes: 
- nProxyType specifies the Proxy Type. 
- ProxyHost and nProxyPort specify the address of the proxy 
- ProxyUser and ProxyPass are only available for SOCKS5 proxies. 
 
supported proxy types: 
PROXYTYPE_NOPROXY 
PROXYTYPE_SOCKS4 
PROXYTYPE_SOCKS4A 
PROXYTYPE_SOCKS5 
PROXYTYPE_HTTP11 
 
There are also some other functions: 
 
GetProxyPeerName 
Like GetPeerName of CAsyncSocket, but returns the address of the 
server connected through the proxy.	If using proxies, GetPeerName 
only returns the address of the proxy. 
 
int GetProxyType(); 
Returns the used proxy 
 
const int GetLastProxyError() const; 
Returns the last proxy error 
 
License 
------- 
 
Feel free to use this class, as long as you don't claim that you wrote it 
and this copyright notice stays intact in the source files. 
If you use this class in commercial applications, please send a short message 
to tim.kosse@gmx.de 
 
Version history 
--------------- 
 
- 1.6 got rid of MFC 
- 1.5 released CAsyncSocketExLayer version 
- 1.4 added UNICODE support 
- 1.3 added basic HTTP1.1 authentication 
      fixed memory leak in SOCKS5 code 
	  OnSocksOperationFailed will be called after Socket has been closed 
      fixed some minor bugs 
- 1.2 renamed into CAsyncProxySocketLayer 
      added HTTP1.1 proxy support 
- 1.1 fixes all known bugs, mostly with SOCKS5 authentication 
- 1.0 initial release 
*/ 
 
#include "stdafx.h" 
#include "AsyncProxySocketLayer.h" 
#include "atlconv.h" //Unicode<->Ascii conversion macros declared here 
#include "CBase64coding.hpp" 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[]=__FILE__; 
#define new DEBUG_NEW 
#endif 
 
////////////////////////////////////////////////////////////////////// 
// Konstruktion/Destruktion 
////////////////////////////////////////////////////////////////////// 
 
CAsyncProxySocketLayer::CAsyncProxySocketLayer() 
{ 
	m_nProxyOpID=0; 
	m_nProxyOpState=0; 
	m_pRecvBuffer=0; 
	m_nRecvBufferPos=0; 
	m_ProxyData.nProxyType=0; 
	m_nProxyPeerIp=0; 
	m_nProxyPeerPort=0; 
	m_pProxyPeerHost = NULL; 
	m_pStrBuffer = NULL; 
	m_ProxyData.pProxyHost = NULL; 
	m_ProxyData.pProxyUser = NULL; 
	m_ProxyData.pProxyPass = NULL; 
	m_pProxyPeerHost = NULL; 
} 
 
CAsyncProxySocketLayer::~CAsyncProxySocketLayer() 
{ 
	delete [] m_ProxyData.pProxyHost; 
	delete [] m_ProxyData.pProxyUser; 
	delete [] m_ProxyData.pProxyPass; 
	delete [] m_pProxyPeerHost; 
	ClearBuffer(); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// Member-Funktion CAsyncProxySocketLayer 
 
void CAsyncProxySocketLayer::SetProxy(int nProxyType) 
{ 
	//Validate the parameters 
	ASSERT(nProxyType==PROXYTYPE_NOPROXY); 
	m_ProxyData.nProxyType=nProxyType; 
} 
 
void CAsyncProxySocketLayer::SetProxy(int nProxyType, const char * pProxyHost, int ProxyPort) 
{ 
	//Validate the parameters 
	ASSERT(nProxyType==PROXYTYPE_SOCKS4  || 
		   nProxyType==PROXYTYPE_SOCKS4A || 
		   nProxyType==PROXYTYPE_SOCKS5  || 
		   nProxyType==PROXYTYPE_HTTP11); 
	ASSERT(!m_nProxyOpID); 
	ASSERT(pProxyHost && *pProxyHost); 
	ASSERT(ProxyPort>0); 
	ASSERT(ProxyPort<=65535); 
 
	delete [] m_ProxyData.pProxyHost; 
	delete [] m_ProxyData.pProxyUser; 
	delete [] m_ProxyData.pProxyPass; 
	m_ProxyData.pProxyHost = NULL; // 'new' may throw an exception 
	m_ProxyData.pProxyUser = NULL; 
	m_ProxyData.pProxyPass = NULL; 
 
	m_ProxyData.nProxyType = nProxyType; 
	m_ProxyData.pProxyHost = new char[_tcslen(pProxyHost)+1]; 
	_tcscpy(m_ProxyData.pProxyHost, pProxyHost); 
	m_ProxyData.nProxyPort = ProxyPort; 
	m_ProxyData.bUseLogon = FALSE; 
} 
 
void CAsyncProxySocketLayer::SetProxy(int nProxyType, const char * pProxyHost, int ProxyPort, const char * pProxyUser, const char * pProxyPass) 
{ 
	//Validate the parameters 
	ASSERT(nProxyType==PROXYTYPE_SOCKS5 || nProxyType==PROXYTYPE_HTTP11); 
	ASSERT(!m_nProxyOpID); 
	ASSERT(pProxyHost && *pProxyHost); 
	ASSERT(ProxyPort>0); 
	ASSERT(ProxyPort<=65535); 
 
	delete [] m_ProxyData.pProxyHost; 
	delete [] m_ProxyData.pProxyUser; 
	delete [] m_ProxyData.pProxyPass; 
	m_ProxyData.pProxyHost = NULL; // 'new' may throw an exception 
	m_ProxyData.pProxyUser = NULL; 
	m_ProxyData.pProxyPass = NULL; 
 
	m_ProxyData.nProxyType = nProxyType; 
	m_ProxyData.pProxyHost = new char[_tcslen(pProxyHost)+1]; 
	_tcscpy(m_ProxyData.pProxyHost, pProxyHost); 
	m_ProxyData.nProxyPort=ProxyPort; 
	if (pProxyUser) 
	{ 
		m_ProxyData.pProxyUser = new TCHAR[_tcslen(pProxyUser)+1]; 
		_tcscpy(m_ProxyData.pProxyUser, pProxyUser); 
	} 
	if (pProxyPass) 
	{ 
		m_ProxyData.pProxyPass = new TCHAR[_tcslen(pProxyPass)+1]; 
		_tcscpy(m_ProxyData.pProxyPass, pProxyPass); 
	} 
	m_ProxyData.bUseLogon = TRUE; 
} 
 
void CAsyncProxySocketLayer::OnReceive(int nErrorCode) 
{ 
	//Here we handle the responses from the SOCKS proxy 
	if (!m_nProxyOpID) 
	{ 
		TriggerEvent(FD_READ, nErrorCode, TRUE); 
		return; 
	} 
	if (nErrorCode) 
	{ 
		TriggerEvent(FD_READ, nErrorCode, TRUE); 
	} 
	if (!m_nProxyOpState) //We should not receive a response yet! 
	{ //Ignore it 
		return; 
	} 
	if (m_ProxyData.nProxyType==PROXYTYPE_SOCKS4 || m_ProxyData.nProxyType==PROXYTYPE_SOCKS4A) 
	{ 
		if (m_nProxyOpState==1) //Both for PROXYOP_CONNECT and PROXYOP_BIND 
		{ 
			if (!m_pRecvBuffer) 
				m_pRecvBuffer=new char[8]; 
			int numread=ReceiveNext(m_pRecvBuffer+m_nRecvBufferPos, 8-m_nRecvBufferPos); 
			if (numread==SOCKET_ERROR) 
			{ 
				if (WSAGetLastError()!=WSAEWOULDBLOCK) 
				{ 
					DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, PROXYERROR_REQUESTFAILED, 0); 
					if (m_nProxyOpID==PROXYOP_CONNECT) 
						TriggerEvent(FD_CONNECT, WSAGetLastError(), TRUE); 
					else 
						TriggerEvent(FD_ACCEPT, WSAGetLastError(), TRUE); 
					Reset(); 
					ClearBuffer(); 
				} 
				return; 
			} 
			m_nRecvBufferPos+=numread; 
			if (m_nRecvBufferPos==8) 
			{ 
				if (m_pRecvBuffer[1]!=90 || m_pRecvBuffer[0]!=0) 
				{ 
					DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, PROXYERROR_REQUESTFAILED, 0); 
					if (m_nProxyOpID==PROXYOP_CONNECT) 
						TriggerEvent(FD_CONNECT, WSAECONNABORTED, TRUE); 
					else 
						TriggerEvent(FD_ACCEPT, WSAECONNABORTED, TRUE); 
					Reset(); 
					ClearBuffer(); 
					return; 
				} 
				if (m_nProxyOpID==PROXYOP_CONNECT) 
				{ 
					//OK, we are connected with the remote server 
					ClearBuffer(); 
					Reset(); 
					TriggerEvent(FD_CONNECT, 0, TRUE); 
					TriggerEvent(FD_READ, 0, TRUE); 
					TriggerEvent(FD_WRITE, 0, TRUE); 
					return; 
				} 
				else 
				{ 
					//Listen socket created 
					m_nProxyOpState++; 
					unsigned long ip; 
					int port; 
					memcpy(&ip,&m_pRecvBuffer[4],4); 
					if (!ip) 
					{ //No IP return, use the IP of the proxy server 
						SOCKADDR SockAddr; 
						memset(&SockAddr,0,sizeof(SockAddr)); 
						int SockAddrLen=sizeof(SockAddr); 
						if (GetPeerName(&SockAddr, &SockAddrLen )) 
						{ 
							ip=((LPSOCKADDR_IN)&SockAddr)->sin_addr.S_un.S_addr; 
						} 
						else 
						{ 
							DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, PROXYERROR_REQUESTFAILED, 0); 
							if (m_nProxyOpID==PROXYOP_CONNECT) 
								TriggerEvent(FD_CONNECT, WSAECONNABORTED, TRUE); 
							else 
								TriggerEvent(FD_ACCEPT, WSAECONNABORTED, TRUE); 
							Reset(); 
							ClearBuffer(); 
							return; 
						} 
					} 
					memcpy(&port,&m_pRecvBuffer[2],2); 
					t_ListenSocketCreatedStruct data; 
					data.ip=ip; 
					data.nPort=port; 
					DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, PROXYSTATUS_LISTENSOCKETCREATED, (int)&data); 
				} 
				ClearBuffer(); 
			} 
		} 
		else if (m_nProxyOpID==2) 
		{ 
			if (!m_pRecvBuffer) 
				m_pRecvBuffer=new char[8]; 
			int numread=ReceiveNext(m_pRecvBuffer+m_nRecvBufferPos,8-m_nRecvBufferPos); 
			if (numread==SOCKET_ERROR) 
			{ 
				if (WSAGetLastError()!=WSAEWOULDBLOCK) 
				{ 
					DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, PROXYERROR_REQUESTFAILED, 0); 
					if (m_nProxyOpID==PROXYOP_CONNECT) 
						TriggerEvent(FD_CONNECT, WSAGetLastError(), TRUE); 
					else 
						TriggerEvent(FD_ACCEPT, WSAGetLastError(), TRUE); 
					Reset(); 
					ClearBuffer(); 
				} 
				return; 
			} 
			m_nRecvBufferPos+=numread; 
			if (m_nRecvBufferPos==8) 
			{ 
				if (m_pRecvBuffer[1]!=90 || m_pRecvBuffer[0]!=0) 
				{ 
					DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, PROXYERROR_REQUESTFAILED, 0); 
					if (m_nProxyOpID==PROXYOP_CONNECT) 
						TriggerEvent(FD_CONNECT, WSAECONNABORTED, TRUE); 
					else 
						TriggerEvent(FD_ACCEPT, WSAECONNABORTED, TRUE); 
					Reset(); 
					ClearBuffer(); 
					return; 
				} 
				//Connection to remote server established 
				ClearBuffer(); 
				Reset(); 
				TriggerEvent(FD_ACCEPT, 0, TRUE); 
				TriggerEvent(FD_READ, 0, TRUE); 
				TriggerEvent(FD_WRITE, 0, TRUE); 
			} 
		} 
	} 
	else if (m_ProxyData.nProxyType==PROXYTYPE_SOCKS5) 
	{ 
		if (m_nProxyOpState==1) //Get respone to initialization message 
		{ 
			if (!m_pRecvBuffer) 
				m_pRecvBuffer=new char[2]; 
			int numread=ReceiveNext(m_pRecvBuffer+m_nRecvBufferPos,2-m_nRecvBufferPos); 
			if (numread==SOCKET_ERROR) 
			{ 
				if (WSAGetLastError()!=WSAEWOULDBLOCK) 
				{ 
					DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, PROXYERROR_REQUESTFAILED, 0); 
					if (m_nProxyOpID==PROXYOP_CONNECT) 
						TriggerEvent(FD_CONNECT, WSAGetLastError(), TRUE); 
					else 
						TriggerEvent(FD_ACCEPT, WSAGetLastError(), TRUE); 
					Reset(); 
				} 
				return; 
			} 
			m_nRecvBufferPos+=numread; 
			if (m_nRecvBufferPos==2) 
			{ 
 
				if (m_pRecvBuffer[0]!=5) 
				{ 
					DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, PROXYERROR_REQUESTFAILED, 0); 
					if (m_nProxyOpID==PROXYOP_CONNECT) 
						TriggerEvent(FD_CONNECT, WSAECONNABORTED, TRUE); 
					else 
						TriggerEvent(FD_ACCEPT, WSAECONNABORTED, TRUE); 
					Reset(); 
					ClearBuffer(); 
					return; 
				} 
				if (m_pRecvBuffer[1]) 
				{ //Auth needed 
					if (m_pRecvBuffer[1]!=2) 
					{ //Unknown auth type 
						DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, PROXYERROR_AUTHTYPEUNKNOWN, 0); 
						if (m_nProxyOpID==PROXYOP_CONNECT) 
							TriggerEvent(FD_CONNECT, WSAECONNABORTED, TRUE); 
						else 
							TriggerEvent(FD_ACCEPT, WSAECONNABORTED, TRUE); 
						Reset(); 
						ClearBuffer(); 
						return; 
					} 
 
					if (!m_ProxyData.bUseLogon) 
					{ 
						DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, PROXYERROR_AUTHNOLOGON, 0); 
						if (m_nProxyOpID==PROXYOP_CONNECT) 
							TriggerEvent(FD_CONNECT, WSAECONNABORTED, TRUE); 
						else 
							TriggerEvent(FD_ACCEPT, WSAECONNABORTED, TRUE); 
						Reset(); 
						ClearBuffer(); 
						return; 
					} 
					//Send authentication 
					LPCSTR lpszAsciiUser = m_ProxyData.pProxyUser; 
					LPCSTR lpszAsciiPass = m_ProxyData.pProxyPass; 
					ASSERT(strlen(lpszAsciiUser)<=255); 
					ASSERT(strlen(lpszAsciiPass)<=255); 
					unsigned char *buffer = new unsigned char[3 + (lpszAsciiUser?strlen(lpszAsciiUser):0) + (lpszAsciiPass?strlen(lpszAsciiPass):0) + 1]; 
					sprintf((char *)buffer, "  %s %s", lpszAsciiUser?lpszAsciiUser:"", lpszAsciiPass?lpszAsciiPass:""); 
					buffer[0]=5; 
					buffer[1]=static_cast(strlen(lpszAsciiUser)); 
					buffer[2+strlen(lpszAsciiUser)]=static_cast(strlen(lpszAsciiPass)); 
					int len=3+strlen(lpszAsciiUser)+strlen(lpszAsciiPass); 
					int res=SendNext(buffer,len); 
					delete [] buffer; 
					if (res==SOCKET_ERROR || resstrlen(m_pStrBuffer)) ? strlen(m_pStrBuffer) : strlen(start))) 
			{ 
				DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, PROXYERROR_REQUESTFAILED, (int)_T("No valid HTTP reponse")); 
				Reset(); 
				ClearBuffer(); 
				TriggerEvent(FD_CONNECT, WSAECONNABORTED, TRUE ); 
				return; 
			} 
			char *pos = strstr(m_pStrBuffer, "\r\n"); 
			if (pos) 
			{ 
				char *pos2 = strstr(m_pStrBuffer, " "); 
				if (!pos2 || *(pos2+1)!='2' || pos2>pos) 
				{ 
					char *tmp = new char[pos-m_pStrBuffer + 1]; 
					tmp[pos-m_pStrBuffer] = 0; 
					strncpy(tmp, m_pStrBuffer, pos-m_pStrBuffer); 
					DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, PROXYERROR_REQUESTFAILED, (int)tmp); 
					delete [] tmp; 
					Reset(); 
					ClearBuffer(); 
					TriggerEvent(FD_CONNECT, WSAECONNABORTED, TRUE ); 
					return; 
				} 
			} 
			if (strlen(m_pStrBuffer)>3 && !memcmp(m_pStrBuffer+strlen(m_pStrBuffer)-4, "\r\n\r\n", 4)) //End of the HTTP header 
			{ 
				Reset(); 
				ClearBuffer(); 
				TriggerEvent(FD_CONNECT, 0, TRUE); 
				TriggerEvent(FD_READ, 0, TRUE); 
				TriggerEvent(FD_WRITE, 0, TRUE); 
				return; 
			} 
		} 
	} 
} 
 
BOOL CAsyncProxySocketLayer::Connect( LPCTSTR lpszHostAddress, UINT nHostPort ) 
{ 
	if (!m_ProxyData.nProxyType) 
		//Connect normally because there is no proxy 
		return ConnectNext(lpszHostAddress, nHostPort); 
 
	USES_CONVERSION; 
 
	//Translate the host address 
	ASSERT(lpszHostAddress != NULL); 
 
	SOCKADDR_IN sockAddr; 
	memset(&sockAddr,0,sizeof(sockAddr)); 
 
	LPCSTR lpszAscii = T2A((LPTSTR)lpszHostAddress); 
	sockAddr.sin_family = AF_INET; 
	sockAddr.sin_addr.s_addr = inet_addr(lpszAscii); 
 
 
	if (sockAddr.sin_addr.s_addr == INADDR_NONE) 
	{ 
		LPHOSTENT lphost; 
		lphost = gethostbyname(lpszAscii); 
		if (lphost != NULL) 
			sockAddr.sin_addr.s_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr; 
		else 
		{ 
			//Can't resolve hostname 
			if (m_ProxyData.nProxyType==PROXYTYPE_SOCKS4A || 
				m_ProxyData.nProxyType==PROXYTYPE_SOCKS5 || 
				m_ProxyData.nProxyType==PROXYTYPE_HTTP11) 
			{ //Can send domain names to proxy 
 
				//Conect to proxy server 
				BOOL res=ConnectNext(m_ProxyData.pProxyHost, m_ProxyData.nProxyPort); 
				if (!res) 
				{ 
					if (WSAGetLastError()!=WSAEWOULDBLOCK) 
					{ 
						DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, PROXYERROR_NOCONN, WSAGetLastError()); 
						return FALSE; 
					} 
				} 
				m_nProxyPeerPort=htons((u_short)nHostPort); 
				m_nProxyPeerIp=0; 
				delete [] m_pProxyPeerHost; 
				m_pProxyPeerHost = NULL; // 'new' may throw an exception 
				m_pProxyPeerHost = new char[strlen(lpszHostAddress)+1]; 
				strcpy(m_pProxyPeerHost, lpszHostAddress); 
				m_nProxyOpID=PROXYOP_CONNECT; 
				return TRUE; 
			} 
			else 
			{ 
				DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, PROXYERROR_CANTRESOLVEHOST, 0); 
				WSASetLastError(WSAEINVAL); 
				return FALSE; 
			} 
		} 
	} 
 
	sockAddr.sin_port = htons((u_short)nHostPort); 
	BOOL res=CAsyncProxySocketLayer::Connect((SOCKADDR*)&sockAddr, sizeof(sockAddr)); 
	if (res || WSAGetLastError()==WSAEWOULDBLOCK) 
	{ 
		delete [] m_pProxyPeerHost; 
		m_pProxyPeerHost = NULL; // 'new' may throw an exception 
		m_pProxyPeerHost = new char[strlen(lpszHostAddress)+1]; 
		strcpy(m_pProxyPeerHost, lpszHostAddress); 
	} 
	return res; 
 
} 
 
BOOL CAsyncProxySocketLayer::Connect( const SOCKADDR* lpSockAddr, int nSockAddrLen ) 
{ 
	if (!m_ProxyData.nProxyType) 
		//Connect normally because there is no proxy 
		return ConnectNext(lpSockAddr, nSockAddrLen ); 
 
	LPSOCKADDR_IN sockAddr=(LPSOCKADDR_IN)lpSockAddr; 
 
	//Save server details 
	m_nProxyPeerIp=sockAddr->sin_addr.S_un.S_addr; 
	m_nProxyPeerPort=sockAddr->sin_port; 
	delete [] m_pProxyPeerHost; 
	m_pProxyPeerHost = NULL; 
 
	m_nProxyOpID=PROXYOP_CONNECT; 
 
	BOOL res = ConnectNext(m_ProxyData.pProxyHost, m_ProxyData.nProxyPort); 
	if (!res) 
	{ 
		if (WSAGetLastError()!=WSAEWOULDBLOCK) 
		{ 
			DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, PROXYERROR_NOCONN, WSAGetLastError()); 
			return FALSE; 
		} 
	} 
 
	return res; 
} 
 
void CAsyncProxySocketLayer::OnConnect(int nErrorCode) 
{ 
	if (m_ProxyData.nProxyType==PROXYTYPE_NOPROXY) 
	{ 
		TriggerEvent(FD_CONNECT, nErrorCode, TRUE); 
		return; 
	} 
	ASSERT(m_nProxyOpID); 
	if (!m_nProxyOpID) 
	{ 
		//This should not happen 
		return; 
	}; 
 
	if (nErrorCode) 
	{ //Can't connect to proxy 
		DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, PROXYERROR_NOCONN, nErrorCode); 
		if (m_nProxyOpID==PROXYOP_CONNECT) 
			TriggerEvent(FD_CONNECT, nErrorCode, TRUE); 
		else 
			TriggerEvent(FD_ACCEPT, nErrorCode, TRUE); 
		Reset(); 
		ClearBuffer(); 
		return; 
	} 
	if (m_nProxyOpID==PROXYOP_CONNECT || m_nProxyOpID==PROXYOP_LISTEN) 
	{ 
		if (m_nProxyOpState) 
			//Somehow OnConnect has been called more than once 
			return; 
		ASSERT(m_ProxyData.nProxyType!=PROXYTYPE_NOPROXY); 
		ClearBuffer(); 
		//Send the initial request 
		if (m_ProxyData.nProxyType==PROXYTYPE_SOCKS4 || m_ProxyData.nProxyType==PROXYTYPE_SOCKS4A) 
		{ //SOCKS4 proxy 
			//Send request 
			LPCSTR lpszAscii = m_pProxyPeerHost?m_pProxyPeerHost:""; 
			char *command=new char [9+strlen(lpszAscii)+1]; 
			memset(command,0,9+strlen(lpszAscii)+1); 
			int len=9; 
			command[0]=4; 
			command[1]=(m_nProxyOpID==PROXYOP_CONNECT)?1:2; //CONNECT or BIND request 
			memcpy(&command[2],&m_nProxyPeerPort,2); //Copy target address 
			if (!m_nProxyPeerIp) 
			{ 
				ASSERT(m_ProxyData.nProxyType==PROXYTYPE_SOCKS4A); 
				ASSERT(strcmp(lpszAscii, "")); 
				//Set the IP to 0.0.0.x (x is nonzero) 
				command[4]=0; 
				command[5]=0; 
				command[6]=0; 
				command[7]=1; 
				//Add host as URL 
				strcpy(&command[9],lpszAscii); 
				len+=strlen(lpszAscii)+1; 
			} 
			else 
				memcpy(&command[4],&m_nProxyPeerIp,4); 
			int res=SendNext(command,len); //Send command 
			delete [] command; 
			int nErrorCode=WSAGetLastError(); 
			if (res==SOCKET_ERROR)//nErrorCode!=WSAEWOULDBLOCK) 
			{ 
				DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, PROXYERROR_REQUESTFAILED, 0); 
				if (m_nProxyOpID==PROXYOP_CONNECT) 
					TriggerEvent(FD_CONNECT, (nErrorCode==WSAEWOULDBLOCK)?WSAECONNABORTED:nErrorCode, TRUE); 
				else 
					TriggerEvent(FD_ACCEPT, nErrorCode, TRUE); 
				Reset(); 
				ClearBuffer(); 
				return; 
			} 
			else if (res>8) % 256, (m_nProxyPeerIp>>16) %256, m_nProxyPeerIp>>24); 
			} 
			if (!m_ProxyData.bUseLogon) 
				sprintf(str, "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n\r\n", pHost, ntohs(m_nProxyPeerPort), 
					pHost, ntohs(m_nProxyPeerPort)); 
			else 
			{ 
				sprintf(str, "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n", pHost, ntohs(m_nProxyPeerPort), 
					pHost, ntohs(m_nProxyPeerPort)); 
 
				char userpass[4096]; 
				sprintf(userpass, "%s:%s", m_ProxyData.pProxyUser?m_ProxyData.pProxyUser:"", m_ProxyData.pProxyPass?m_ProxyData.pProxyPass:""); 
				char base64str[4096]; 
 
				CBase64Coding base64coding; 
				if (!base64coding.Encode(userpass, strlen(userpass), base64str)) 
				{ 
					DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, PROXYERROR_REQUESTFAILED, 0); 
					if (m_nProxyOpID==PROXYOP_CONNECT) 
						TriggerEvent(FD_CONNECT, WSAECONNABORTED, TRUE); 
					else 
						TriggerEvent(FD_ACCEPT, WSAECONNABORTED, TRUE); 
					Reset(); 
					ClearBuffer(); 
					delete [] pHost; 
					return; 
				} 
				strcat(str, "Authorization: Basic "); 
				strcat(str, base64str); 
				strcat(str, "\r\nProxy-Authorization: Basic "); 
				strcat(str, base64str); 
				strcat(str, "\r\n\r\n"); 
			} 
			delete [] pHost; 
 
			int numsent=SendNext(str, strlen(str) ); 
			int nErrorCode=WSAGetLastError(); 
			if (numsent==SOCKET_ERROR)//nErrorCode!=WSAEWOULDBLOCK) 
			{ 
				DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, PROXYERROR_REQUESTFAILED, 0); 
				if (m_nProxyOpID==PROXYOP_CONNECT) 
					TriggerEvent(FD_CONNECT, (nErrorCode==WSAEWOULDBLOCK)?WSAECONNABORTED:nErrorCode, TRUE); 
				else 
					TriggerEvent(FD_ACCEPT, nErrorCode, TRUE); 
				Reset(); 
				ClearBuffer(); 
				return; 
			} 
			else if (  numsent < static_cast( strlen(str) )  ) 
			{ 
				DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, PROXYERROR_REQUESTFAILED, 0); 
				if (m_nProxyOpID==PROXYOP_CONNECT) 
					TriggerEvent(FD_CONNECT, WSAECONNABORTED, TRUE); 
				else 
					TriggerEvent(FD_ACCEPT, WSAECONNABORTED, TRUE); 
				Reset(); 
				ClearBuffer(); 
				return; 
			} 
			m_nProxyOpState++; 
			return; 
		} 
		else 
			ASSERT(FALSE); 
		//Now we'll wait for the response, handled in OnReceive 
		m_nProxyOpState++; 
	} 
} 
 
void CAsyncProxySocketLayer::ClearBuffer() 
{ 
	delete [] m_pStrBuffer; 
	m_pStrBuffer = NULL; 
	if (m_pRecvBuffer) 
	{ 
		delete [] m_pRecvBuffer; 
		m_pRecvBuffer=0; 
	} 
	m_nRecvBufferLen=0; 
	m_nRecvBufferPos=0; 
 
} 
 
BOOL CAsyncProxySocketLayer::Listen( int nConnectionBacklog) 
{ 
	if (GetProxyType()==PROXYTYPE_NOPROXY) 
		return ListenNext(nConnectionBacklog); 
 
	//Connect to proxy server 
	BOOL res=ConnectNext(m_ProxyData.pProxyHost, m_ProxyData.nProxyPort); 
	if (!res) 
	{ 
		if (WSAGetLastError()!=WSAEWOULDBLOCK) 
		{ 
			DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, PROXYERROR_NOCONN, WSAGetLastError()); 
			return FALSE; 
		} 
	} 
	m_nProxyPeerPort=0; 
	m_nProxyPeerIp=(unsigned int)nConnectionBacklog; 
 
	m_nProxyOpID=PROXYOP_LISTEN; 
	return TRUE; 
} 
 
#ifdef _AFX 
BOOL CAsyncProxySocketLayer::GetPeerName(CString &rPeerAddress, UINT &rPeerPort) 
{ 
	if (m_ProxyData.nProxyType==PROXYTYPE_NOPROXY) 
		return GetPeerNameNext(rPeerAddress, rPeerPort); 
 
	if (GetLayerState()==notsock) 
	{ 
		WSASetLastError(WSAENOTSOCK); 
		return FALSE; 
	} 
	else if (GetLayerState()!=connected) 
	{ 
		WSASetLastError(WSAENOTCONN); 
		return FALSE; 
	} 
	else if (!m_nProxyPeerIp || !m_nProxyPeerPort) 
	{ 
		WSASetLastError(WSAENOTCONN); 
		return FALSE; 
	} 
 
	ASSERT(m_ProxyData.nProxyType); 
	BOOL res=GetPeerNameNext( rPeerAddress, rPeerPort ); 
	if (res) 
	{ 
		rPeerPort=ntohs(m_nProxyPeerPort); 
		rPeerAddress.Format(_T("%d.%d.%d.%d"), m_nProxyPeerIp%256,(m_nProxyPeerIp>>8)%256,(m_nProxyPeerIp>>16)%256, m_nProxyPeerIp>>24); 
	} 
	return res; 
} 
#endif 
 
BOOL CAsyncProxySocketLayer::GetPeerName( SOCKADDR* lpSockAddr, int* lpSockAddrLen ) 
{ 
	if (m_ProxyData.nProxyType==PROXYTYPE_NOPROXY) 
		return GetPeerNameNext(lpSockAddr, lpSockAddrLen); 
 
	if (GetLayerState()==notsock) 
	{ 
		WSASetLastError(WSAENOTSOCK); 
		return FALSE; 
	} 
	else if (GetLayerState()!=connected) 
	{ 
		WSASetLastError(WSAENOTCONN); 
		return FALSE; 
	} 
	else if (!m_nProxyPeerIp || !m_nProxyPeerPort) 
	{ 
		WSASetLastError(WSAENOTCONN); 
		return FALSE; 
	} 
 
	ASSERT(m_ProxyData.nProxyType); 
	BOOL res=GetPeerNameNext(lpSockAddr,lpSockAddrLen); 
	if (res) 
	{ 
		LPSOCKADDR_IN addr=(LPSOCKADDR_IN)lpSockAddr; 
		addr->sin_port=m_nProxyPeerPort; 
		addr->sin_addr.S_un.S_addr=m_nProxyPeerIp; 
	} 
	return res; 
} 
 
int CAsyncProxySocketLayer::GetProxyType() const 
{ 
	return m_ProxyData.nProxyType; 
} 
 
void CAsyncProxySocketLayer::Close() 
{ 
	delete [] m_ProxyData.pProxyHost; 
	delete [] m_ProxyData.pProxyUser; 
	delete [] m_ProxyData.pProxyPass; 
	delete [] m_pProxyPeerHost; 
	m_ProxyData.pProxyHost = NULL; 
	m_ProxyData.pProxyUser = NULL; 
	m_ProxyData.pProxyPass = NULL; 
	m_pProxyPeerHost = NULL; 
	ClearBuffer(); 
	Reset(); 
	CloseNext(); 
} 
 
void CAsyncProxySocketLayer::Reset() 
{ 
	m_nProxyOpState=0; 
	m_nProxyOpID=0; 
} 
 
 
int CAsyncProxySocketLayer::Send(const void* lpBuf, int nBufLen, int nFlags) 
{ 
	if (m_nProxyOpID) 
	{ 
		WSASetLastError(WSAEWOULDBLOCK); 
		return SOCKET_ERROR; 
	} 
 
	return SendNext(lpBuf, nBufLen, nFlags); 
} 
 
int CAsyncProxySocketLayer::Receive(void* lpBuf, int nBufLen, int nFlags) 
{ 
	if (m_nProxyOpID) 
	{ 
		WSASetLastError(WSAEWOULDBLOCK); 
		return SOCKET_ERROR; 
	} 
 
	return ReceiveNext(lpBuf, nBufLen, nFlags); 
} 
 
BOOL CAsyncProxySocketLayer::PrepareListen(unsigned long ip) 
{ 
	if (GetLayerState()!=notsock && GetLayerState()!=unconnected) 
		return FALSE; 
	m_nProxyPeerIp=ip; 
	return TRUE; 
} 
 
BOOL CAsyncProxySocketLayer::Accept( CAsyncSocketEx& rConnectedSocket, SOCKADDR* lpSockAddr /*=NULL*/, int* lpSockAddrLen /*=NULL*/ ) 
{ 
	if (!m_ProxyData.nProxyType) 
		return AcceptNext(rConnectedSocket, lpSockAddr, lpSockAddrLen); 
 
	GetPeerName(lpSockAddr, lpSockAddrLen); 
	return TRUE; 
} 
 
CString GetProxyError(UINT nError) 
{ 
	if (nError == PROXYERROR_NOERROR) 
		return _T("No error"); 
	else if (nError == PROXYERROR_NOCONN) 
		return _T("Can't connect to proxy server"); 
	else if (nError == PROXYERROR_REQUESTFAILED) 
		return _T("Request failed, can't send data"); 
	else if (nError == PROXYERROR_AUTHREQUIRED) 
		return _T("Authentication required"); 
	else if (nError == PROXYERROR_AUTHTYPEUNKNOWN) 
		return _T("Authtype unknown or not supported"); 
	else if (nError == PROXYERROR_AUTHFAILED) 
		return _T("Authentication failed"); 
	else if (nError == PROXYERROR_AUTHNOLOGON) 
		return _T("AuthNoLogon"); 
	else if (nError == PROXYERROR_CANTRESOLVEHOST) 
		return _T("Can't resolve host"); 
	else if (nError == PROXYSTATUS_LISTENSOCKETCREATED) 
		return _T("Listen socket created"); 
	else{ 
		CString strError; 
		strError.Format("Error: %u", nError); 
		return strError; 
	} 
}