www.gusucode.com > eMule电驴下载VC++源代码-源码程序 > eMule电驴下载VC++源代码-源码程序\code\srchybrid\AsyncProxySocketLayer.cpp
//Download by http://www.NewXing.com /*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<unsigned char>(strlen(lpszAsciiUser)); buffer[2+strlen(lpszAsciiUser)]=static_cast<unsigned char>(strlen(lpszAsciiPass)); int len=3+strlen(lpszAsciiUser)+strlen(lpszAsciiPass); int res=SendNext(buffer,len); delete [] buffer; if (res==SOCKET_ERROR || res<len) { if ((WSAGetLastError()!=WSAEWOULDBLOCK) || res<len) { DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, PROXYERROR_REQUESTFAILED, 0); if (m_nProxyOpID==PROXYOP_CONNECT) TriggerEvent(FD_CONNECT, WSAGetLastError(), TRUE); else TriggerEvent(FD_ACCEPT, WSAGetLastError(), TRUE); Reset(); return; } } ClearBuffer(); m_nProxyOpState++; return; } } //No auth needed //Send connection request LPCSTR lpszAsciiHost = m_pProxyPeerHost?m_pProxyPeerHost:""; char *command=new char[10+strlen(lpszAsciiHost)+1]; memset(command,0,10+strlen(lpszAsciiHost)+1); command[0]=5; command[1]=(m_nProxyOpID==PROXYOP_CONNECT)?1:2; command[2]=0; command[3]=m_nProxyPeerIp?1:3; int len=4; if (m_nProxyPeerIp) { memcpy(&command[len],&m_nProxyPeerIp,4); len+=4; } else { command[len]=strlen(lpszAsciiHost); strcpy(&command[len+1],lpszAsciiHost); len+=strlen(lpszAsciiHost)+1; } memcpy(&command[len],&m_nProxyPeerPort,2); len+=2; int res=SendNext(command,len); delete [] command; if (res==SOCKET_ERROR || res<len) { if ( ( WSAGetLastError()!=WSAEWOULDBLOCK) || res<len) { 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_nProxyOpState+=2; ClearBuffer(); return; } else if (m_nProxyOpState==2) {//Response to the auth request 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[1]!=0) { DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, PROXYERROR_AUTHFAILED, 0); if (m_nProxyOpID==PROXYOP_CONNECT) TriggerEvent(FD_CONNECT, WSAECONNABORTED, TRUE); else TriggerEvent(FD_ACCEPT, WSAECONNABORTED, TRUE); Reset(); ClearBuffer(); return; } LPCSTR lpszAsciiHost = m_pProxyPeerHost?m_pProxyPeerHost:""; char *command=new char[10+strlen(lpszAsciiHost)+1]; memset(command,0,10+strlen(lpszAsciiHost)+1); command[0]=5; command[1]=(m_nProxyOpID==PROXYOP_CONNECT)?1:2; command[2]=0; command[3]=m_nProxyPeerIp?1:3; int len=4; if (m_nProxyPeerIp) { memcpy(&command[len],&m_nProxyPeerIp,4); len+=4; } else { command[len]=strlen(lpszAsciiHost); strcpy(&command[len+1],lpszAsciiHost); len+=strlen(lpszAsciiHost)+1; } memcpy(&command[len],&m_nProxyPeerPort,2); len+=2; int res=SendNext(command,len); delete [] command; if (res==SOCKET_ERROR || res<len) { if ((WSAGetLastError()!=WSAEWOULDBLOCK) || res<len) { 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_nProxyOpState++; ClearBuffer(); return; } } else if (m_nProxyOpState==3) {//Response to the connection request if (!m_pRecvBuffer) { m_pRecvBuffer=new char[10]; m_nRecvBufferLen=5; } int numread=ReceiveNext(m_pRecvBuffer+m_nRecvBufferPos,m_nRecvBufferLen-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==m_nRecvBufferLen) { //Check for errors if (m_pRecvBuffer[1]!=0 || 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_nRecvBufferLen==5) { //Check which kind of address the response contains if (m_pRecvBuffer[3]==1) m_nRecvBufferLen=10; else { char *tmp=new char[m_nRecvBufferLen+=m_pRecvBuffer[4]+2]; memcpy(tmp,m_pRecvBuffer,5); delete [] m_pRecvBuffer; m_pRecvBuffer=tmp; m_nRecvBufferLen+=m_pRecvBuffer[4]+2; } return; } if (m_nProxyOpID==PROXYOP_CONNECT) { //OK, we are connected with the remote server Reset(); ClearBuffer(); TriggerEvent(FD_CONNECT, 0, TRUE); TriggerEvent(FD_READ, 0, TRUE); TriggerEvent(FD_WRITE, 0, TRUE); } else { //Listen socket created m_nProxyOpState++; unsigned long ip; int port; ASSERT(m_pRecvBuffer[3]==1); memcpy(&ip,&m_pRecvBuffer[4],4); memcpy(&port,&m_pRecvBuffer[8],2); t_ListenSocketCreatedStruct data; data.ip=ip; data.nPort=port; DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, PROXYSTATUS_LISTENSOCKETCREATED, (int)&data); } ClearBuffer(); } } else if (m_nProxyOpState==4) { if (!m_pRecvBuffer) m_pRecvBuffer=new char[10]; int numread=ReceiveNext(m_pRecvBuffer+m_nRecvBufferPos,10-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==10) { if (m_pRecvBuffer[1]!=0) { DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, PROXYERROR_REQUESTFAILED, 0); if (m_nProxyOpID==PROXYOP_CONNECT) TriggerEvent(FD_CONNECT, WSAECONNABORTED, TRUE); else { VERIFY(m_nProxyOpID==PROXYOP_LISTEN); 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); } } } if (m_ProxyData.nProxyType==PROXYTYPE_HTTP11) { ASSERT (m_nProxyOpID==PROXYOP_CONNECT); char buffer[9]={0}; for(;;) { int numread = ReceiveNext(buffer, m_pStrBuffer?1:8); if (numread==SOCKET_ERROR) { int nError=WSAGetLastError(); if (nError!=WSAEWOULDBLOCK) { DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, PROXYERROR_REQUESTFAILED, 0); Reset(); ClearBuffer(); TriggerEvent(FD_CONNECT, nError, TRUE ); } return; } //Response begins with HTTP/ if (!m_pStrBuffer) { m_pStrBuffer = new char[strlen(buffer) + 1]; strcpy(m_pStrBuffer, buffer); } else { char *tmp = m_pStrBuffer; m_pStrBuffer = new char[strlen(tmp) + strlen(buffer) + 1]; strcpy(m_pStrBuffer, tmp); strcpy(m_pStrBuffer + strlen(tmp), buffer); delete [] tmp; } memset(buffer, 0, 9); const char start[] = "HTTP/"; if (memcmp(start, m_pStrBuffer, (strlen(start)>strlen(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<len) { 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; } } else if (m_ProxyData.nProxyType==PROXYTYPE_SOCKS5) { //SOCKS5 proxy //Send initialization request unsigned char command[10]; memset(command,0,10); command[0]=5; //CAsyncProxySocketLayer supports to logon types: No logon and //cleartext username/password (if set) logon command[1]=m_ProxyData.bUseLogon?2:1; //Number of logon types command[2]=m_ProxyData.bUseLogon?2:0; //2=user/pass, 0=no logon int len=m_ProxyData.bUseLogon?4:3; //length of request int res=SendNext(command,len); 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<len) { 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; } } else if (m_ProxyData.nProxyType==PROXYTYPE_HTTP11) { char str[4096]; //This should be large enough char * pHost = NULL; if (m_pProxyPeerHost && *m_pProxyPeerHost) { pHost = new char[strlen(m_pProxyPeerHost)+1]; strcpy(pHost, m_pProxyPeerHost); } else { pHost = new char[16]; sprintf(pHost, "%d.%d.%d.%d", m_nProxyPeerIp%256, (m_nProxyPeerIp>>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<int>( 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; } }