SocMFC.cpp
上传用户:dengkfang
上传日期:2008-12-30
资源大小:5233k
文件大小:35k
源码类别:

CA认证

开发平台:

Visual C++

  1. /*
  2. Module : SocMFC.cpp
  3. Purpose: Implementation for an MFC wrapper class for sockets
  4. Created: PJN / 05-08-1998
  5. History: 03-03-2003 1. Addition of a number of preprocessor defines, namely W3MFC_EXT_CLASS, 
  6.                     THRDPOOL_EXT_CLASS and SOCKMFC_EXT_CLASS. This allows the classes to easily 
  7.                     be added and exported from a MFC extension dll.
  8.                     2. Now implements support for connecting via Socks 4 and Socks 5 proxies
  9.          21-09-2003 1. Now supports UDP sockets.
  10.                     2. Now supports UDP relaying via Socks 5 proxy.
  11.          26-09-2003 1. Now supports connection via HTTP proxies which support the CONNECT verb
  12.          13-01-2004 1. Used newer form of #pragma pack to avoid problems with non standard 
  13.                     packing sizes.
  14.          25-10-2004 1. Updated to compile cleanly when Detect 64 bit issues and Force conformance 
  15.                     in for loop options are enabled in Visual Studio .NET
  16.          29-12-2004 Almost all of the following updates were to match the functionality provided
  17.                     by the MFC CAsyncSocket class but without the overhead of hidden windows and 
  18.                     its async behaviour.
  19.                     1. Now automatically links to Winsock via #pragma comment
  20.                     2. Addition of a GetPeerName method.
  21.                     3. Replaced all calls to ZeroMemory to memset.
  22.                     4. Addtion of a GetSockName method.
  23.                     5. Addition of a SetSockOpt method.
  24.                     6. Addition of a Flags parameter to Receive method.
  25.                     7. Addition of a IOCtl method.
  26.                     8. Optimized the code in Listen.
  27.                     9. Addition of a ReceiveFrom method.
  28.                     10. Addition of a ShutDown method.
  29.                     11. Optimized the code in Close.
  30.                     12. Remove of pszLocalBoundAddress parameter from Connect methods to make it 
  31.                     consistent with CAsyncSocket.
  32.                     13. Addition of a Flags parameter to Send method.
  33.                     14. Optimized code in CWSocket destructor
  34.                     15. Addition of an overloaded Create method which allows all of the socket
  35.                     parameters to be set
  36.                     16. Use of _tcslen has been minimized when NULL string parameters can be passed
  37.                     to various CWSocket methods.
  38.                     17. Change of various parameter names to be consistent with names as used in
  39.                     CAsyncSocket.
  40.          31-01-2005 1. Fixed a bug in CWSocket::Receive where it throws an error when a graceful 
  41.                     disconnect occurs. Now the code only throws an exception if the return value
  42.                     from recv is SOCKET_ERROR
  43.          01-05-2005 1. Send method now uses a const void* parameter.
  44.          21-06-2005 1. Provision of connect methods which allows a timeout to be specified. Please note
  45.                     that if you use a host name in these calls as opposed to an IP address, the DNS
  46.                     lookup is still done using the OS supplied timeout. Only the actual connection
  47.                     to the server is implemented using a timeout after the DNS lookup is done (if it
  48.                     is necessary).
  49. Copyright (c) 2002 - 2005 by PJ Naughter.  (Web: www.naughter.com, Email: pjna@naughter.com)
  50. All rights reserved.
  51. Copyright / Usage Details:
  52. You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise) 
  53. when your product is released in binary form. You are allowed to modify the source code in any way you want 
  54. except you cannot modify the copyright details at the top of each module. If you want to distribute source 
  55. code with your application, then you are only allowed to distribute versions released by the author. This is 
  56. to maintain a single distribution point for the source code. 
  57. */
  58. /////////////////// Includes //////////////////////////////////////////////////
  59. #include "stdafx.h"
  60. #include "SocMFC.h"
  61. #include "Base64.h"
  62. /////////////////// Macros / Defines //////////////////////////////////////////
  63. #ifdef _DEBUG
  64. #define new DEBUG_NEW
  65. #undef THIS_FILE
  66. static char THIS_FILE[] = __FILE__;
  67. #endif
  68. #ifndef __AFXPRIV_H__
  69. #pragma message("To avoid this message please put afxpriv.h in your PCH (normally stdafx.h)")
  70. #include <afxpriv.h>
  71. #endif
  72. #pragma comment(lib, "wsock32.lib")
  73. ///////////////// Implementation //////////////////////////////////////////////
  74. #pragma pack(push, 1)
  75. struct WSOCKET_SOCK4_CONNECT_REQUEST
  76. {
  77.   BYTE    VN;
  78.   BYTE    CD;
  79.   WORD    DSTPORT;
  80.   in_addr DSTIP;
  81.   BYTE    USERID[1];
  82. };
  83. struct WSOCKET_SOCKS4_CONNECT_REPLY
  84. {
  85.   BYTE    VN;
  86.   BYTE    CD;
  87.   WORD    DSTPORT;
  88.   in_addr DSTIP;
  89. };
  90. struct WSOCKET_SOCKS5_IDENTIFIER_PACKET
  91. {
  92.   BYTE VER;
  93.   BYTE NMETHODS;
  94.   BYTE METHODS[255];
  95. };
  96. struct WSOCKET_SOCKS5_METHODSELECTION_MESSAGE
  97. {
  98.   BYTE VER;
  99.   BYTE METHOD;
  100. };
  101. struct WSOCKET_SOCKS5_BASE_REQUEST_DETAILS
  102. {
  103.   BYTE VER;
  104.   BYTE CMD;
  105.   BYTE RSV;
  106.   BYTE ATYP;
  107. };
  108. struct WSOCKET_SOCKS5_IP4_REQUEST_DETAILS
  109. {
  110.   WSOCKET_SOCKS5_BASE_REQUEST_DETAILS Base;
  111.   in_addr                     DST_IP;
  112.   WORD                        DSTPORT;
  113. };
  114. struct WSOCKET_SOCKS5_HOST_DETAILS
  115. {
  116.   BYTE LENGTH;
  117.   BYTE HOST[255];
  118. };
  119. struct WSOCKET_SOCKS5_HOSTNAME_REQUEST_DETAILS
  120. {
  121.   WSOCKET_SOCKS5_BASE_REQUEST_DETAILS Base;
  122.   WSOCKET_SOCKS5_HOST_DETAILS         DST_HOST;
  123.   WORD                                DSTPORT;
  124. };
  125. struct WSOCKET_SOCKS5_USERNAME_AUTHENTICATION_REPLY
  126. {
  127.   BYTE VER;
  128.   BYTE STATUS;
  129. };
  130. #pragma pack(pop)
  131. ////////// Exception handling code
  132. void AfxThrowWSocketException(int nError /* = 0 */)
  133. {
  134. if (nError == 0)
  135. nError = ::WSAGetLastError();
  136. CWSocketException* pException = new CWSocketException(nError);
  137. TRACE(_T("Warning: throwing CWSocketException for error %dn"), nError);
  138. THROW(pException);
  139. }
  140. BOOL CWSocketException::GetErrorMessage(LPTSTR pstrError, UINT nMaxError, PUINT pnHelpContext)
  141. {
  142. ASSERT(pstrError != NULL && AfxIsValidString(pstrError, nMaxError));
  143. if (pnHelpContext != NULL)
  144. *pnHelpContext = 0;
  145. LPTSTR lpBuffer;
  146. BOOL bRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  147.                       NULL,  m_nError, MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT),
  148.                       (LPTSTR) &lpBuffer, 0, NULL);
  149. if (bRet == FALSE)
  150. *pstrError = '';
  151. else
  152. {
  153. lstrcpyn(pstrError, lpBuffer, nMaxError);
  154. bRet = TRUE;
  155. LocalFree(lpBuffer);
  156. }
  157. return bRet;
  158. }
  159. CString CWSocketException::GetErrorMessage()
  160. {
  161.   CString rVal;
  162.   LPTSTR pstrError = rVal.GetBuffer(4096);
  163.   GetErrorMessage(pstrError, 4096, NULL);
  164.   rVal.ReleaseBuffer();
  165.   return rVal;
  166. }
  167. CWSocketException::CWSocketException(int nError)
  168. {
  169. m_nError = nError;
  170. }
  171. CWSocketException::~CWSocketException()
  172. {
  173. }
  174. IMPLEMENT_DYNAMIC(CWSocketException, CException)
  175. #ifdef _DEBUG
  176. void CWSocketException::Dump(CDumpContext& dc) const
  177. {
  178. CObject::Dump(dc);
  179. dc << "m_nError = " << m_nError;
  180. }
  181. #endif
  182. ////////// The main class /////////////////////////////////////
  183. CWSocket::CWSocket() : m_hSocket(INVALID_SOCKET)
  184. {
  185. }
  186. CWSocket::~CWSocket()
  187. {
  188.   if (m_hSocket != INVALID_SOCKET)
  189.     Close();
  190. }
  191. void CWSocket::Attach(SOCKET hSocket)
  192. {
  193.   //Validate our parameters
  194.   ASSERT(hSocket != INVALID_SOCKET);
  195.   if (m_hSocket != INVALID_SOCKET)
  196.     Close();
  197.   m_hSocket = hSocket;
  198. }
  199. SOCKET CWSocket::Detach()
  200. {
  201.   SOCKET socket = m_hSocket;
  202.   m_hSocket = INVALID_SOCKET;
  203.   return socket;
  204. }
  205. void CWSocket::GetPeerName(CString& sPeerAddress, UINT& nPeerPort)
  206. {
  207.   //Validate our parameters
  208.   ASSERT(IsCreated()); //must have been created first
  209. SOCKADDR_IN sockAddr;
  210. memset(&sockAddr, 0, sizeof(sockAddr));
  211. int nSockAddrLen = sizeof(sockAddr);
  212. GetPeerName((SOCKADDR*)&sockAddr, &nSockAddrLen);
  213. nPeerPort = ntohs(sockAddr.sin_port);
  214. sPeerAddress = inet_ntoa(sockAddr.sin_addr);
  215. }
  216. void CWSocket::GetSockName(CString& sSocketAddress, UINT& nSocketPort)
  217. {
  218.   //Validate our parameters
  219.   ASSERT(IsCreated()); //must have been created first
  220. SOCKADDR_IN sockAddr;
  221. memset(&sockAddr, 0, sizeof(sockAddr));
  222. int nSockAddrLen = sizeof(sockAddr);
  223. GetSockName((SOCKADDR*)&sockAddr, &nSockAddrLen);
  224. nSocketPort = ntohs(sockAddr.sin_port);
  225. sSocketAddress = inet_ntoa(sockAddr.sin_addr);
  226. }
  227. void CWSocket::GetPeerName(SOCKADDR* lpSockAddr, int* lpSockAddrLen)
  228.   //Validate our parameters
  229.   ASSERT(IsCreated()); //Must have been created first
  230.   if (getpeername(m_hSocket, lpSockAddr, lpSockAddrLen) == SOCKET_ERROR)
  231.     AfxThrowWSocketException();
  232. }
  233. void CWSocket::GetSockName(SOCKADDR* lpSockAddr, int* lpSockAddrLen)
  234.   //Validate our parameters
  235.   ASSERT(IsCreated()); //Must have been created first
  236.   if (getsockname(m_hSocket, lpSockAddr, lpSockAddrLen) == SOCKET_ERROR)
  237.     AfxThrowWSocketException();
  238. }
  239. void CWSocket::Accept(CWSocket& connectedSocket, sockaddr_in& clientAddress)
  240. {
  241.   ASSERT(IsCreated());               //must have been created first
  242.   ASSERT(!connectedSocket.IsCreated()); //Must be an unitialized socket
  243.   //Call the SDK accept function  
  244.   int nSize = sizeof(sockaddr_in);
  245.   SOCKET socket = accept(m_hSocket, (sockaddr*) &clientAddress, &nSize);
  246.   if (socket == INVALID_SOCKET)
  247.     AfxThrowWSocketException(); 
  248.   //Wrap the return value up into a C++ instance
  249.   connectedSocket.Attach(socket);
  250. }
  251. void CWSocket::SetSockOpt(int nOptionName, const void* lpOptionValue, int nOptionLen, int nLevel)
  252.   //Validate our parameters
  253.   ASSERT(IsCreated()); //Must have been created first
  254.   if (setsockopt(m_hSocket, nLevel, nOptionName, (LPCSTR)lpOptionValue, nOptionLen) == SOCKET_ERROR)
  255.     AfxThrowWSocketException();
  256. }
  257. void CWSocket::GetSockOpt(int nOptionName, void* lpOptionValue, int* lpOptionLen, int nLevel)
  258.   //Validate our parameters
  259.   ASSERT(IsCreated()); //Must have been created first
  260.   if (getsockopt(m_hSocket, nLevel, nOptionName, (LPSTR)lpOptionValue, lpOptionLen) == SOCKET_ERROR)
  261.     AfxThrowWSocketException();
  262. }
  263. void CWSocket::Bind(const SOCKADDR* lpSockAddr, int nSockAddrLen)
  264.   //Validate our parameters
  265.   ASSERT(IsCreated()); //Must have been created first
  266.   if (bind(m_hSocket, lpSockAddr, nSockAddrLen) == SOCKET_ERROR)
  267.     AfxThrowWSocketException();
  268. }
  269. void CWSocket::Bind(UINT nSocketPort, LPCTSTR lpszSocketAddress)
  270. {
  271. USES_CONVERSION;
  272.   //Setup the structure used in sdk "bind" calls
  273.   SOCKADDR_IN sockAddr;
  274.   memset(&sockAddr, 0, sizeof(sockAddr));
  275.   sockAddr.sin_family = AF_INET;
  276.   sockAddr.sin_port = htons((u_short)nSocketPort);
  277.   //Do we need to bind to a specific IP address?
  278.   if (lpszSocketAddress)
  279.   {
  280.     //Convert to an ASCII string
  281.     LPSTR lpszAscii = T2A((LPTSTR) lpszSocketAddress);
  282.     sockAddr.sin_addr.s_addr = inet_addr(lpszAscii);
  283.   //If the address is not dotted notation, then do a DNS 
  284.   //lookup of it.
  285.   if (sockAddr.sin_addr.s_addr == INADDR_NONE)
  286.   {
  287.   LPHOSTENT lphost;
  288.   lphost = gethostbyname(lpszAscii);
  289.   if (lphost != NULL)
  290.   sockAddr.sin_addr.s_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr;
  291.   else
  292.   {
  293.         AfxThrowWSocketException(WSAEINVAL); 
  294.   return;
  295.   }
  296.     }
  297.   }
  298.   else
  299.     sockAddr.sin_addr.s_addr = htonl(INADDR_ANY); //Bind to any IP address;
  300.   Bind((SOCKADDR*) &sockAddr, sizeof(sockAddr));
  301. }
  302. void CWSocket::Close()
  303. {
  304. if (m_hSocket != INVALID_SOCKET)
  305. {
  306. closesocket(m_hSocket);
  307. m_hSocket = INVALID_SOCKET;
  308. }
  309. }
  310. void CWSocket::Connect(const SOCKADDR* lpSockAddr, int nSockAddrLen)
  311. {
  312.   //Validate our parameters
  313.   ASSERT(IsCreated()); //must have been created first
  314. if (connect(m_hSocket, lpSockAddr, nSockAddrLen) == SOCKET_ERROR)
  315.     AfxThrowWSocketException();
  316. }
  317. void CWSocket::Connect(LPCTSTR lpszHostAddress, UINT nHostPort)
  318. {
  319. USES_CONVERSION;
  320.   //Validate our parameters
  321.   ASSERT(IsCreated());             //must have been created first
  322.   ASSERT(lpszHostAddress);          //Must have a valid host
  323.   //Work out the IP address of the machine we want to connect to
  324. LPSTR lpszAscii = T2A((LPTSTR) lpszHostAddress);
  325. //Determine if the address is in dotted notation
  326. SOCKADDR_IN sockAddr;
  327. memset(&sockAddr, 0, sizeof(sockAddr));
  328. sockAddr.sin_family = AF_INET;
  329. sockAddr.sin_port = htons((u_short)nHostPort);
  330. sockAddr.sin_addr.s_addr = inet_addr(lpszAscii);
  331. //If the address is not dotted notation, then do a DNS 
  332. //lookup of it.
  333. if (sockAddr.sin_addr.s_addr == INADDR_NONE)
  334. {
  335. LPHOSTENT lphost = gethostbyname(lpszAscii);
  336. if (lphost != NULL)
  337. sockAddr.sin_addr.s_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr;
  338. else
  339.       AfxThrowWSocketException(); 
  340. }
  341.   //Call the other version of Connect which does the actual work
  342. Connect((SOCKADDR*)&sockAddr, sizeof(sockAddr));
  343. }
  344. #ifdef _WINSOCK2API_
  345. void CWSocket::Connect(const SOCKADDR* lpSockAddr, int nSockAddrLen, DWORD dwConnectionTimeout, BOOL bResetToBlockingMode)
  346. {
  347.   //Create an event to wait on
  348.   WSAEVENT hConnectedEvent = WSACreateEvent();
  349.   if (hConnectedEvent == WSA_INVALID_EVENT)
  350.     AfxThrowWSocketException();
  351.   //Setup event selection on the socket
  352.   if (WSAEventSelect(m_hSocket, hConnectedEvent, FD_CONNECT) == SOCKET_ERROR)
  353.   {
  354.     //Hive away the last error
  355.     DWORD dwLastError = GetLastError();
  356.     //Close the event before we return
  357.     WSACloseEvent(hConnectedEvent);
  358.     //Throw the exception that we could not setup event selection
  359.     AfxThrowWSocketException(dwLastError);
  360.   }
  361.   //Call the SDK "connect" function
  362.   int nConnected = connect(m_hSocket, lpSockAddr, nSockAddrLen);
  363.   if (nConnected == SOCKET_ERROR)
  364.   {
  365.     //Check to see if the call should be completed by waiting for the event to be signalled
  366.     DWORD dwLastError = GetLastError();
  367.     if (dwLastError == WSAEWOULDBLOCK)
  368.     {
  369.       DWORD dwWait = WaitForSingleObject(hConnectedEvent, dwConnectionTimeout);
  370.       if (dwWait == WAIT_OBJECT_0)
  371.       {
  372.         //Get the error value returned using WSAEnumNetworkEvents
  373.         WSANETWORKEVENTS networkEvents;
  374.         int nEvents = WSAEnumNetworkEvents(m_hSocket, hConnectedEvent, &networkEvents);
  375.         if (nEvents == SOCKET_ERROR)
  376.         {
  377.           //Hive away the last error
  378.           DWORD dwLastError = GetLastError();
  379.           //Close the event before we return
  380.           WSACloseEvent(hConnectedEvent);
  381.           //Throw the exception that we could not call WSAEnumNetworkEvents
  382.           AfxThrowWSocketException(dwLastError);
  383.         }
  384.         else
  385.         {
  386.           ASSERT(networkEvents.lNetworkEvents & FD_CONNECT);
  387.           //Has an error occured in the connect call
  388.           if (networkEvents.iErrorCode[FD_CONNECT_BIT] != ERROR_SUCCESS)
  389.           {
  390.             //Close the event before we return
  391.             WSACloseEvent(hConnectedEvent);
  392.             //Throw the exception that an error has occurred in calling connect
  393.             AfxThrowWSocketException(networkEvents.iErrorCode[FD_CONNECT_BIT]);
  394.           }
  395.         }
  396.       }
  397.       else
  398.       {
  399.         //Close the event before we return
  400.         WSACloseEvent(hConnectedEvent);
  401.         //Throw the exception that we could not connect in a timely fashion
  402.         AfxThrowWSocketException(ERROR_TIMEOUT);
  403.       }
  404.     }
  405.     else
  406.     {
  407.       //Close the event before we return
  408.       WSACloseEvent(hConnectedEvent);
  409.       //Throw the exception that the connect call failed unexpectedly
  410.       AfxThrowWSocketException(dwLastError);
  411.     }
  412.   }
  413.   //Remove the event notification on the socket
  414.   WSAEventSelect(m_hSocket, hConnectedEvent, 0);
  415.   //Destroy the event now that we are finished with it
  416.   WSACloseEvent(hConnectedEvent);
  417.   //Reset the socket to blocking mode if required
  418.   if (bResetToBlockingMode)
  419.   {
  420.     DWORD dwNonBlocking = 0;
  421.     if (ioctlsocket(m_hSocket, FIONBIO, &dwNonBlocking) == SOCKET_ERROR)
  422.     {
  423.       //Throw the exception that we could not reset the socket to blocking mode
  424.       AfxThrowWSocketException();
  425.     }
  426.   }    
  427. }
  428. void CWSocket::Connect(LPCTSTR lpszHostAddress, UINT nHostPort, DWORD dwConnectionTimeout, BOOL bResetToBlockingMode)
  429. {
  430. USES_CONVERSION;
  431.   //Validate our parameters
  432.   ASSERT(IsCreated());             //must have been created first
  433.   ASSERT(lpszHostAddress);          //Must have a valid host
  434.   //Work out the IP address of the machine we want to connect to
  435. LPSTR lpszAscii = T2A((LPTSTR) lpszHostAddress);
  436. //Determine if the address is in dotted notation
  437. SOCKADDR_IN sockAddr;
  438. memset(&sockAddr, 0, sizeof(sockAddr));
  439. sockAddr.sin_family = AF_INET;
  440. sockAddr.sin_port = htons((u_short)nHostPort);
  441. sockAddr.sin_addr.s_addr = inet_addr(lpszAscii);
  442. //If the address is not dotted notation, then do a DNS 
  443. //lookup of it.
  444. if (sockAddr.sin_addr.s_addr == INADDR_NONE)
  445. {
  446. LPHOSTENT lphost = gethostbyname(lpszAscii);
  447. if (lphost != NULL)
  448. sockAddr.sin_addr.s_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr;
  449. else
  450.       AfxThrowWSocketException(); 
  451. }
  452.   //Call the other version of Connect which does the actual work
  453.   Connect((SOCKADDR*)&sockAddr, sizeof(sockAddr), dwConnectionTimeout, bResetToBlockingMode);
  454. }
  455. #endif //_WINSOCK2API_
  456. int CWSocket::Receive(void* lpBuf, int nBufLen, int nFlags)
  457. {
  458.   //Validate our parameters
  459.   ASSERT(IsCreated()); //must have been created first
  460.   int nReceived = recv(m_hSocket, (LPSTR) lpBuf, nBufLen, nFlags); 
  461.   if (nReceived == SOCKET_ERROR)
  462.     AfxThrowWSocketException();
  463.   return nReceived;
  464. }
  465. int CWSocket::ReceiveFrom(void* lpBuf, int nBufLen, SOCKADDR* lpSockAddr, int* lpSockAddrLen, int nFlags)
  466.   //Validate our parameters
  467.   ASSERT(IsCreated()); //must have been created first
  468.   int nReceived = recvfrom(m_hSocket, (LPSTR) lpBuf, nBufLen, nFlags, lpSockAddr, lpSockAddrLen);
  469.   if (nReceived == SOCKET_ERROR)
  470.     AfxThrowWSocketException();
  471.   return nReceived;
  472. }
  473. int CWSocket::ReceiveFrom(void* lpBuf, int nBufLen, CString& sSocketAddress, UINT& nSocketPort, int nFlags)
  474. {
  475.   //Validate our parameters
  476.   ASSERT(IsCreated()); //must have been created first
  477. SOCKADDR_IN sockAddr;
  478. memset(&sockAddr, 0, sizeof(sockAddr));
  479. int nSockAddrLen = sizeof(sockAddr);
  480. int nResult = ReceiveFrom(lpBuf, nBufLen, (SOCKADDR*)&sockAddr, &nSockAddrLen, nFlags);
  481. nSocketPort = ntohs(sockAddr.sin_port);
  482. sSocketAddress = inet_ntoa(sockAddr.sin_addr);
  483. return nResult;
  484. }
  485. void CWSocket::Send(const void* pBuffer, int nBufLen, int nFlags)
  486. {
  487.   ASSERT(IsCreated()); //must have been created first
  488.   if (send(m_hSocket, (char*) pBuffer, nBufLen, nFlags) == SOCKET_ERROR)
  489.     AfxThrowWSocketException();
  490. }
  491. int CWSocket::SendTo(const void* lpBuf, int nBufLen, const SOCKADDR* lpSockAddr, int nSockAddrLen, int nFlags)
  492.   //Validate our parameters
  493.   ASSERT(IsCreated()); //must have been created first
  494.   int nSent = sendto(m_hSocket, (LPSTR) lpBuf, nBufLen, nFlags, lpSockAddr, nSockAddrLen);
  495.   if (nSent == SOCKET_ERROR)
  496.     AfxThrowWSocketException();
  497.   return nSent; 
  498. }
  499. int CWSocket::SendTo(const void* lpBuf, int nBufLen, UINT nHostPort, LPCTSTR lpszHostAddress, int nFlags)
  500. {
  501.   //Validate our parameters
  502.   ASSERT(IsCreated()); //must have been created first
  503. USES_CONVERSION;
  504.   //Determine if the address is in dotted notation
  505. SOCKADDR_IN sockAddr;
  506. memset(&sockAddr, 0, sizeof(sockAddr));
  507. sockAddr.sin_family = AF_INET;
  508. sockAddr.sin_port = htons((u_short)nHostPort);
  509. if (lpszHostAddress == NULL)
  510. sockAddr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
  511. else
  512. {
  513.   //If the address is not dotted notation, then do a DNS 
  514.   //lookup of it.
  515.   LPSTR lpszAscii = T2A((LPTSTR)lpszHostAddress);
  516. sockAddr.sin_addr.s_addr = inet_addr(lpszAscii);
  517. if (sockAddr.sin_addr.s_addr == INADDR_NONE)
  518. {
  519. LPHOSTENT lphost = gethostbyname(lpszAscii);
  520. if (lphost != NULL)
  521. sockAddr.sin_addr.s_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr;
  522. else
  523. AfxThrowWSocketException();
  524. }
  525. }
  526. return SendTo(lpBuf, nBufLen, (SOCKADDR*)&sockAddr, sizeof(sockAddr), nFlags);
  527. }
  528. void CWSocket::IOCtl(long lCommand, DWORD* lpArgument)
  529.   //Validate our parameters
  530.   ASSERT(IsCreated()); //must have been created first
  531.   if (ioctlsocket(m_hSocket, lCommand, lpArgument) == SOCKET_ERROR)
  532.     AfxThrowWSocketException();
  533. }
  534. void CWSocket::Listen(int nConnectionBacklog)
  535. {
  536.   //Validate our parameters
  537.   ASSERT(IsCreated()); //must have been created first
  538.   if (listen(m_hSocket, nConnectionBacklog) == SOCKET_ERROR)
  539.     AfxThrowWSocketException();
  540. }
  541. void CWSocket::ShutDown(int nHow)
  542.   //Validate our parameters
  543.   ASSERT(IsCreated()); //must have been created first
  544.   if (shutdown(m_hSocket, nHow) == SOCKET_ERROR)
  545.     AfxThrowWSocketException();
  546. }
  547. void CWSocket::Create(BOOL bUDP)
  548. {
  549.   //Validate our parameters
  550.   ASSERT(!IsCreated()); //must not have been already created
  551.   if (bUDP)
  552.     Create(SOCK_DGRAM, 0, PF_INET);
  553.   else
  554.     Create(SOCK_STREAM, 0, PF_INET);
  555. }
  556. void CWSocket::Create(int nSocketType, int nProtocolType, int nAddressFormat)
  557. {
  558.   //Validate our parameters
  559.   ASSERT(!IsCreated()); //must not have been already created
  560. m_hSocket = socket(nAddressFormat, nSocketType, nProtocolType);
  561.   if (m_hSocket == INVALID_SOCKET)
  562.     AfxThrowWSocketException();
  563. }
  564. void CWSocket::ConnectViaSocks4(LPCTSTR lpszHostAddress, UINT nHostPort, LPCTSTR lpszSocksServer, UINT nSocksPort, DWORD dwConnectionTimeout)
  565. {
  566. USES_CONVERSION;
  567.   ASSERT(IsCreated()); //must have been created first
  568.   //connect to the proxy
  569.   Connect(lpszSocksServer, nSocksPort);
  570.   try
  571.   {
  572.     //Fill in a connection request packet
  573.     WSOCKET_SOCK4_CONNECT_REQUEST request;
  574.     request.VN = 4;
  575.     request.CD = 1;
  576.     request.DSTPORT = htons((u_short) nHostPort);
  577.   //Determine if the address is in dotted notation
  578.   LPSTR lpszAscii = T2A((LPTSTR) lpszHostAddress);
  579.   request.DSTIP.S_un.S_addr = inet_addr(lpszAscii);
  580.   //If the address is not dotted notation, then do a DNS 
  581.   //lookup of it, since Socks 4 does not support DNS proxying
  582.   if (request.DSTIP.S_un.S_addr == INADDR_NONE)
  583.   {
  584.   LPHOSTENT lphost = gethostbyname(lpszAscii);
  585.   if (lphost != NULL)
  586.   request.DSTIP.S_un.S_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr;
  587.   else
  588.         AfxThrowWSocketException(); 
  589.   }
  590.     request.USERID[0] = 0;
  591.     Send(&request, sizeof(request));
  592.     //Wait for the connection reply
  593.     WSOCKET_SOCKS4_CONNECT_REPLY reply;
  594.     memset(&reply, 0, sizeof(reply));
  595.     int nDataReceived = 0;
  596.     while (nDataReceived < sizeof(reply))
  597.     {
  598.       if (IsReadible(dwConnectionTimeout))
  599.       {
  600.         int nData = Receive(((BYTE*) &reply) + nDataReceived, sizeof(reply) - nDataReceived);
  601.         nDataReceived += nData;
  602.       }
  603.       else
  604.         AfxThrowWSocketException(WSAETIMEDOUT);
  605.     }
  606.     //Validate the response
  607.     if ((reply.VN != 0) || (reply.CD != 90))
  608.       AfxThrowWSocketException(ERROR_BAD_NET_RESP);
  609.   }
  610.   catch(CWSocketException* pEx)
  611.   {
  612.     //Close the socket before we rethrow the exception
  613.     int nError = pEx->m_nError;
  614.     pEx->Delete();
  615.     Close();
  616.     AfxThrowWSocketException(nError);
  617.   }
  618. }
  619. void CWSocket::ConnectViaSocks5(LPCTSTR lpszHostAddress, UINT nHostPort, LPCTSTR lpszSocksServer, UINT nSocksPort, LPCTSTR lpszUserName, LPCTSTR lpszPassword, DWORD dwConnectionTimeout, BOOL bUDP)
  620. {
  621.   USES_CONVERSION;
  622.   ASSERT(IsCreated()); //must have been created first
  623.   //connect to the proxy
  624.   Connect(lpszSocksServer, nSocksPort);
  625.   try
  626.   {  
  627.     BOOL bAuthenticate = (lpszUserName != NULL);
  628.     //Fill in a connection request packet
  629.     WSOCKET_SOCKS5_IDENTIFIER_PACKET request;
  630.     request.VER = 5;
  631.     request.NMETHODS = 1;
  632.     request.METHODS[0] = 0;
  633.     if (bAuthenticate)
  634.     {
  635.       request.NMETHODS++;
  636.       request.METHODS[1] = 2;
  637.     }
  638.     Send(&request, bAuthenticate ? 4 : 3);
  639.     //Wait for the connection reply
  640.     WSOCKET_SOCKS5_METHODSELECTION_MESSAGE reply;
  641.     memset(&reply, 0, sizeof(reply));
  642.     int nDataReceived = 0;
  643.     while (nDataReceived < sizeof(reply))
  644.     {
  645.       if (IsReadible(dwConnectionTimeout))
  646.       {
  647.         int nData = Receive(((BYTE*) &reply) + nDataReceived, sizeof(reply) - nDataReceived);
  648.         nDataReceived += nData;
  649.       }
  650.       else
  651.         AfxThrowWSocketException(WSAETIMEDOUT);
  652.     }
  653.     //Validate the response
  654.     if ((bAuthenticate && ((reply.METHOD != 0) && (reply.METHOD != 2))) || (!bAuthenticate && (reply.METHOD != 0)))
  655.       AfxThrowWSocketException(WSAECONNREFUSED);
  656.     if (bAuthenticate && reply.METHOD == 2)
  657.     {
  658.       LPSTR pszAsciiUserName = T2A((LPTSTR) lpszUserName);
  659.       LPSTR pszAsciiPassword = T2A((LPTSTR) lpszPassword);
  660.       int nUserNameLength = (int) strlen(pszAsciiUserName);
  661.       int nPasswordLength = 0;
  662.       if (pszAsciiPassword)
  663.         nPasswordLength = (int) strlen(pszAsciiPassword);
  664.       if ((nUserNameLength > 255) || (nPasswordLength > 255))
  665.         AfxThrowWSocketException(ERROR_INVALID_PARAMETER);
  666.       int nUserRequestLength = 3 + nUserNameLength + nPasswordLength;
  667.       BYTE* pUserRequest = new BYTE[nUserRequestLength];
  668.       pUserRequest[0] = 1;
  669.       pUserRequest[1] = (BYTE) nUserNameLength;
  670.       CopyMemory(&(pUserRequest[2]), pszAsciiUserName, nUserNameLength);
  671.       pUserRequest[2 + nUserNameLength] = (BYTE) nPasswordLength;
  672.       CopyMemory(pUserRequest + 3 + nUserNameLength, pszAsciiPassword, nPasswordLength);
  673.       Send(pUserRequest, nUserRequestLength);
  674.       //Wait for the login reply
  675.       WSOCKET_SOCKS5_USERNAME_AUTHENTICATION_REPLY reply;
  676.       memset(&reply, 0, sizeof(reply));
  677.       int nDataReceived = 0;
  678.       while (nDataReceived < sizeof(reply))
  679.       {
  680.         if (IsReadible(dwConnectionTimeout))
  681.         {
  682.           int nData = Receive(((BYTE*) &reply) + nDataReceived, sizeof(reply) - nDataReceived);
  683.           nDataReceived += nData;
  684.         }
  685.         else
  686.           AfxThrowWSocketException(WSAETIMEDOUT);
  687.       }
  688.       if (reply.STATUS != 0)
  689.         AfxThrowWSocketException(ERROR_ACCESS_DENIED);
  690.     }
  691.   //Determine if the address is in dotted notation
  692.   LPSTR lpszAscii = T2A((LPTSTR) lpszHostAddress);
  693.   unsigned long nAddr = inet_addr(lpszAscii);
  694.   if (nAddr == INADDR_NONE)
  695.   {
  696.       //verify that the host name is less than 256 bytes which is the limit of the hostname which Socks5 can accomadate
  697.       int nHostLength = (int) strlen(lpszAscii);
  698.       if (nHostLength > 255)
  699.         AfxThrowWSocketException(ERROR_INVALID_PARAMETER);
  700.       WSOCKET_SOCKS5_HOSTNAME_REQUEST_DETAILS requestDetails;
  701.       memset(&requestDetails, 0, sizeof(requestDetails));
  702.       requestDetails.Base.VER = 5;
  703.       if (bUDP)
  704.         requestDetails.Base.CMD = 3;
  705.       else
  706.         requestDetails.Base.CMD = 1;
  707.       requestDetails.Base.ATYP = 3;
  708.       requestDetails.DST_HOST.LENGTH = (BYTE) nHostLength;
  709.       memcpy(requestDetails.DST_HOST.HOST, lpszAscii, nHostLength);
  710.       WORD* pPort = (WORD*) (requestDetails.DST_HOST.HOST + nHostLength);
  711.       *pPort = htons((u_short) nHostPort);
  712.       int nRequestDetailsSize = sizeof(requestDetails) - 256 + nHostLength + 1;
  713.       Send(&requestDetails, nRequestDetailsSize);
  714.   }
  715.     else
  716.     {
  717.       WSOCKET_SOCKS5_IP4_REQUEST_DETAILS requestDetails;
  718.       memset(&requestDetails, 0, sizeof(requestDetails));
  719.       requestDetails.Base.VER = 5;
  720.       requestDetails.Base.CMD = 1;
  721.       requestDetails.Base.ATYP = 1;
  722.       requestDetails.DST_IP.S_un.S_addr = nAddr;
  723.       requestDetails.DSTPORT = htons((u_short) nHostPort);
  724.       Send(&requestDetails, sizeof(requestDetails));
  725.     }
  726.     ReadSocks5ConnectReply(dwConnectionTimeout);
  727.   }
  728.   catch(CWSocketException* pEx)
  729.   {
  730.     //Close the socket before we rethrow the exception
  731.     int nError = pEx->m_nError;
  732.     pEx->Delete();
  733.     Close();
  734.     AfxThrowWSocketException(nError);
  735.   }
  736. }
  737. void CWSocket::ReadSocks5ConnectReply(DWORD dwTimeout)
  738. {
  739.   //The local variables which will receive the data
  740.   int nBufSize = max(sizeof(WSOCKET_SOCKS5_IP4_REQUEST_DETAILS), sizeof(WSOCKET_SOCKS5_HOSTNAME_REQUEST_DETAILS));
  741.   BYTE* pRawRequest = new BYTE[nBufSize];
  742.   
  743.   //retrieve the reponse
  744.   DWORD dwCurrentReadOffset = 0;
  745.   BOOL bMoreDataToRead = TRUE;
  746. while (bMoreDataToRead)
  747. {
  748.     if (IsReadible(dwTimeout))
  749.     {
  750.       int nBufRemaining = nBufSize - dwCurrentReadOffset;
  751.       int nData = Receive(pRawRequest + dwCurrentReadOffset, nBufRemaining);
  752.       //Increment the count of data received
  753.   dwCurrentReadOffset += nData;    
  754.       //Try to parse out what we received
  755.       if (dwCurrentReadOffset >= sizeof(WSOCKET_SOCKS5_BASE_REQUEST_DETAILS)) 
  756.       {
  757.         WSOCKET_SOCKS5_BASE_REQUEST_DETAILS* pBaseRequest = (WSOCKET_SOCKS5_BASE_REQUEST_DETAILS*) pRawRequest;
  758.         if (pBaseRequest->ATYP == 1)
  759.         {
  760.           //An IP 4 address type destination
  761.           bMoreDataToRead = (dwCurrentReadOffset < sizeof(WSOCKET_SOCKS5_IP4_REQUEST_DETAILS));
  762.           if (!bMoreDataToRead)
  763.           {
  764.             if (pBaseRequest->CMD != 0)
  765.             {
  766.               delete [] pRawRequest;
  767.               AfxThrowWSocketException(ERROR_BAD_NET_RESP);
  768.             }
  769.           }
  770.         }
  771.         else if (pBaseRequest->ATYP == 3)
  772.         {
  773.           //A domain name type destination
  774.           if (dwCurrentReadOffset > sizeof(WSOCKET_SOCKS5_BASE_REQUEST_DETAILS))
  775.           {
  776.             WSOCKET_SOCKS5_HOSTNAME_REQUEST_DETAILS* pHostnameRequest = (WSOCKET_SOCKS5_HOSTNAME_REQUEST_DETAILS*) pRawRequest;
  777.             bMoreDataToRead = (dwCurrentReadOffset < ((sizeof(WSOCKET_SOCKS5_HOSTNAME_REQUEST_DETAILS) - 256) + pHostnameRequest->DST_HOST.LENGTH));
  778.             if (!bMoreDataToRead)
  779.             {
  780.               if (pBaseRequest->CMD != 0)
  781.               {
  782.                 delete [] pRawRequest;
  783.                 AfxThrowWSocketException(ERROR_BAD_NET_RESP);
  784.               }
  785.             }
  786.           }
  787.         }
  788.         else
  789.         {
  790.           delete [] pRawRequest;
  791.           AfxThrowWSocketException(ERROR_INVALID_PARAMETER);
  792.         }
  793.       }
  794.     }
  795.     else
  796.     {
  797.       delete [] pRawRequest;
  798.       AfxThrowWSocketException(WSAETIMEDOUT);
  799.     }
  800.   }
  801.   delete [] pRawRequest;
  802. }
  803. BOOL CWSocket::IsReadible(DWORD dwTimeout)
  804. {
  805.   ASSERT(IsCreated()); //must have been created first
  806.   timeval timeout;
  807.   timeout.tv_sec = dwTimeout/1000;
  808.   timeout.tv_usec = (dwTimeout%1000)*1000;
  809.   fd_set fds;
  810.   FD_ZERO(&fds);
  811.   FD_SET(m_hSocket, &fds);
  812.   int nStatus = select(0, &fds, NULL, NULL, &timeout);
  813.   if (nStatus == SOCKET_ERROR)
  814.     AfxThrowWSocketException();
  815.   return !(nStatus == 0);
  816. }
  817. BOOL CWSocket::IsWritable(DWORD dwTimeout)
  818. {
  819.   ASSERT(IsCreated()); //must have been created first
  820.   timeval timeout;
  821.   timeout.tv_sec = dwTimeout/1000;
  822.   timeout.tv_usec = (dwTimeout%1000)*1000;
  823.   fd_set fds;
  824.   FD_ZERO(&fds);
  825.   FD_SET(m_hSocket, &fds);
  826.   int nStatus = select(0, NULL, &fds, NULL, &timeout);
  827.   if (nStatus == SOCKET_ERROR)
  828.     AfxThrowWSocketException();
  829.   return !(nStatus == 0);
  830. }
  831. BOOL CWSocket::IsCreated() const
  832. {
  833.   return (m_hSocket != INVALID_SOCKET);
  834. }
  835. CWSocket::operator SOCKET()
  836. {
  837.   return m_hSocket;
  838. }
  839. void CWSocket::ConnectViaHTTPProxy(LPCTSTR lpszHostAddress, UINT nHostPort, LPCTSTR lpszHTTPProxy, UINT nHTTPProxyPort, CString& sProxyResponse, LPCTSTR lpszUserName, LPCTSTR lpszPassword, DWORD dwConnectionTimeout, LPCTSTR lpszUserAgent)
  840. {
  841.   USES_CONVERSION;
  842.   ASSERT(IsCreated()); //must have been created first
  843.   //connect to the proxy
  844.   Connect(lpszHTTPProxy, nHTTPProxyPort);
  845.   try
  846.   {  
  847.     //Form the HTTP CONNECT request header
  848.     CString sLine;
  849.     sLine.Format(_T("CONNECT %s:%d HTTP/1.0rn"), lpszHostAddress, nHostPort);
  850.     CString sRequest(sLine);
  851.     
  852.     //Form the authorization line if required  
  853.     if (lpszUserName != NULL)
  854.     {
  855.       //Base64 encode the username password combination
  856.       CBase64 base64;
  857.       CString sUserNamePassword;
  858.       sUserNamePassword.Format(_T("%s:%s"), lpszUserName, lpszPassword);
  859.       char* pszUserNamePassword = T2A((LPTSTR) (LPCTSTR) sUserNamePassword);
  860.       int nUserNamePasswordLength = (int) strlen(pszUserNamePassword);
  861.       int nEncodedLength = base64.EncodeGetRequiredLength(nUserNamePasswordLength);
  862.       LPSTR pszEncoded = (LPSTR) _alloca(nEncodedLength + 1);
  863.       base64.Encode((const BYTE*) pszUserNamePassword, nUserNamePasswordLength, pszEncoded, &nEncodedLength);
  864.       pszEncoded[nEncodedLength] = '';
  865.       //Form the Authorization header line and add it to the request
  866.       sLine.Format(_T("Proxy-authorization: Basic %srn"), A2T(pszEncoded));
  867.       sRequest += sLine;
  868.     }
  869.     //Form the user agent line if required
  870.     if (lpszUserAgent != NULL)
  871.     {
  872.       //Add the User Agent line to the request
  873.       sLine.Format(_T("User-Agent: %srn"), lpszUserAgent);
  874.       sRequest += sLine;
  875.     }
  876.     //Add the final line feed to the request
  877.     sRequest += _T("rn");
  878.     //Finally send the request to the HTTP proxy
  879.     LPSTR pszRequest = T2A((LPTSTR) (LPCTSTR) sRequest);
  880.     Send(pszRequest, (int) strlen(pszRequest));
  881.     //Read the proxy response
  882.     ReadHTTPProxyResponse(dwConnectionTimeout, sProxyResponse);
  883.     //Next make sure that we got a HTTP code of 200 to indicate success
  884.     int nFirstSpace = sProxyResponse.Find(_T(" "));
  885.     if (nFirstSpace != -1)
  886.     {
  887.       CString sResponseCode = sProxyResponse.Right(sProxyResponse.GetLength() - nFirstSpace - 1);
  888.       int nResponseCode = _ttoi(sResponseCode);
  889.       if (nResponseCode != 200)
  890.         AfxThrowWSocketException(ERROR_CONNECTION_REFUSED);
  891.     }
  892.   }
  893.   catch(CWSocketException* pEx)
  894.   {
  895.     //Close the socket before we rethrow the exception
  896.     int nError = pEx->m_nError;
  897.     pEx->Delete();
  898.     Close();
  899.     AfxThrowWSocketException(nError);
  900.   }
  901. }
  902. void CWSocket::ReadHTTPProxyResponse(DWORD dwTimeout, CString& sResponse)
  903. {
  904.   USES_CONVERSION;
  905.   ASSERT(IsCreated()); //must have been created first
  906.   //The local variables which will receive the data
  907.   DWORD dwGrowBy = 4096;
  908.   BYTE* pRawRequest = new BYTE[dwGrowBy];
  909.   DWORD dwBufSize = dwGrowBy;
  910.   DWORD dwRawRequestSize = 0;
  911.   
  912.   //retrieve the reponse
  913.   BOOL bMoreDataToRead = TRUE;
  914. while (bMoreDataToRead)
  915. {
  916.     //check the socket for readability
  917.     if (!IsReadible(dwTimeout))
  918.     {
  919.       //Null terminate the data
  920.      pRawRequest[dwRawRequestSize] = '';
  921.       TRACE(_T("CWSocket::ReadHTTPProxyResponse, Timed out waiting for response from socketn"));
  922. AfxThrowWSocketException(WSAETIMEDOUT);
  923.     }
  924. //receive the data from the socket
  925.     dwRawRequestSize += Receive(pRawRequest + dwRawRequestSize, 1);
  926.     //NULL terminate the data received
  927.   pRawRequest[dwRawRequestSize] = '';
  928.     //Check to see if the terminator character(s) have been found
  929.     if (dwRawRequestSize >= 4)
  930.     {
  931.       bMoreDataToRead = !((pRawRequest[dwRawRequestSize-4] == 'r') && (pRawRequest[dwRawRequestSize-3] == 'n') &&
  932.                           (pRawRequest[dwRawRequestSize-2] == 'r') && (pRawRequest[dwRawRequestSize-1] == 'n'));
  933.     }
  934.     if (dwRawRequestSize >= dwBufSize) //No space left in the current buffer
  935.     {
  936.       //Allocate the new receive buffer
  937.       dwBufSize += dwGrowBy; //Grow the buffer by the specified amount
  938.       LPBYTE pNewBuf = new BYTE[dwBufSize];
  939.       //copy the old contents over to the new buffer and assign 
  940.       //the new buffer to the local variable used for retreiving 
  941.       //from the socket
  942.       CopyMemory(pNewBuf, pRawRequest, dwRawRequestSize);
  943.       delete [] pRawRequest;
  944.       pRawRequest = pNewBuf;
  945.     }
  946. }
  947.   //Form the CString out parameter
  948.   sResponse = A2T((char*) pRawRequest);
  949. }