📄 socmfc.cpp
字号:
/*
Module : SocMFC.cpp
Purpose: Implementation for an MFC wrapper class for sockets
Created: PJN / 05-08-1998
History: 03-03-2003 1. Addition of a number of preprocessor defines, namely W3MFC_EXT_CLASS,
THRDPOOL_EXT_CLASS and SOCKMFC_EXT_CLASS. This allows the classes to easily
be added and exported from a MFC extension dll.
2. Now implements support for connecting via Socks 4 and Socks 5 proxies
21-09-2003 1. Now supports UDP sockets.
2. Now supports UDP relaying via Socks 5 proxy.
26-09-2003 1. Now supports connection via HTTP proxies which support the CONNECT verb
13-01-2004 1. Used newer form of #pragma pack to avoid problems with non standard
packing sizes.
25-10-2004 1. Updated to compile cleanly when Detect 64 bit issues and Force conformance
in for loop options are enabled in Visual Studio .NET
29-12-2004 Almost all of the following updates were to match the functionality provided
by the MFC CAsyncSocket class but without the overhead of hidden windows and
its async behaviour.
1. Now automatically links to Winsock via #pragma comment
2. Addition of a GetPeerName method.
3. Replaced all calls to ZeroMemory to memset.
4. Addtion of a GetSockName method.
5. Addition of a SetSockOpt method.
6. Addition of a Flags parameter to Receive method.
7. Addition of a IOCtl method.
8. Optimized the code in Listen.
9. Addition of a ReceiveFrom method.
10. Addition of a ShutDown method.
11. Optimized the code in Close.
12. Remove of pszLocalBoundAddress parameter from Connect methods to make it
consistent with CAsyncSocket.
13. Addition of a Flags parameter to Send method.
14. Optimized code in CWSocket destructor
15. Addition of an overloaded Create method which allows all of the socket
parameters to be set
16. Use of _tcslen has been minimized when NULL string parameters can be passed
to various CWSocket methods.
17. Change of various parameter names to be consistent with names as used in
CAsyncSocket.
31-01-2005 1. Fixed a bug in CWSocket::Receive where it throws an error when a graceful
disconnect occurs. Now the code only throws an exception if the return value
from recv is SOCKET_ERROR
01-05-2005 1. Send method now uses a const void* parameter.
21-06-2005 1. Provision of connect methods which allows a timeout to be specified. Please note
that if you use a host name in these calls as opposed to an IP address, the DNS
lookup is still done using the OS supplied timeout. Only the actual connection
to the server is implemented using a timeout after the DNS lookup is done (if it
is necessary).
Copyright (c) 2002 - 2005 by PJ Naughter. (Web: www.naughter.com, Email: pjna@naughter.com)
All rights reserved.
Copyright / Usage Details:
You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
when your product is released in binary form. You are allowed to modify the source code in any way you want
except you cannot modify the copyright details at the top of each module. If you want to distribute source
code with your application, then you are only allowed to distribute versions released by the author. This is
to maintain a single distribution point for the source code.
*/
/////////////////// Includes //////////////////////////////////////////////////
#include "stdafx.h"
#include "SocMFC.h"
#include "Base64.h"
/////////////////// Macros / Defines //////////////////////////////////////////
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#ifndef __AFXPRIV_H__
#pragma message("To avoid this message please put afxpriv.h in your PCH (normally stdafx.h)")
#include <afxpriv.h>
#endif
#pragma comment(lib, "wsock32.lib")
///////////////// Implementation //////////////////////////////////////////////
#pragma pack(push, 1)
struct WSOCKET_SOCK4_CONNECT_REQUEST
{
BYTE VN;
BYTE CD;
WORD DSTPORT;
in_addr DSTIP;
BYTE USERID[1];
};
struct WSOCKET_SOCKS4_CONNECT_REPLY
{
BYTE VN;
BYTE CD;
WORD DSTPORT;
in_addr DSTIP;
};
struct WSOCKET_SOCKS5_IDENTIFIER_PACKET
{
BYTE VER;
BYTE NMETHODS;
BYTE METHODS[255];
};
struct WSOCKET_SOCKS5_METHODSELECTION_MESSAGE
{
BYTE VER;
BYTE METHOD;
};
struct WSOCKET_SOCKS5_BASE_REQUEST_DETAILS
{
BYTE VER;
BYTE CMD;
BYTE RSV;
BYTE ATYP;
};
struct WSOCKET_SOCKS5_IP4_REQUEST_DETAILS
{
WSOCKET_SOCKS5_BASE_REQUEST_DETAILS Base;
in_addr DST_IP;
WORD DSTPORT;
};
struct WSOCKET_SOCKS5_HOST_DETAILS
{
BYTE LENGTH;
BYTE HOST[255];
};
struct WSOCKET_SOCKS5_HOSTNAME_REQUEST_DETAILS
{
WSOCKET_SOCKS5_BASE_REQUEST_DETAILS Base;
WSOCKET_SOCKS5_HOST_DETAILS DST_HOST;
WORD DSTPORT;
};
struct WSOCKET_SOCKS5_USERNAME_AUTHENTICATION_REPLY
{
BYTE VER;
BYTE STATUS;
};
#pragma pack(pop)
////////// Exception handling code
void AfxThrowWSocketException(int nError /* = 0 */)
{
if (nError == 0)
nError = ::WSAGetLastError();
CWSocketException* pException = new CWSocketException(nError);
TRACE(_T("Warning: throwing CWSocketException for error %d\n"), nError);
THROW(pException);
}
BOOL CWSocketException::GetErrorMessage(LPTSTR pstrError, UINT nMaxError, PUINT pnHelpContext)
{
ASSERT(pstrError != NULL && AfxIsValidString(pstrError, nMaxError));
if (pnHelpContext != NULL)
*pnHelpContext = 0;
LPTSTR lpBuffer;
BOOL bRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, m_nError, MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT),
(LPTSTR) &lpBuffer, 0, NULL);
if (bRet == FALSE)
*pstrError = '\0';
else
{
lstrcpyn(pstrError, lpBuffer, nMaxError);
bRet = TRUE;
LocalFree(lpBuffer);
}
return bRet;
}
CString CWSocketException::GetErrorMessage()
{
CString rVal;
LPTSTR pstrError = rVal.GetBuffer(4096);
GetErrorMessage(pstrError, 4096, NULL);
rVal.ReleaseBuffer();
return rVal;
}
CWSocketException::CWSocketException(int nError)
{
m_nError = nError;
}
CWSocketException::~CWSocketException()
{
}
IMPLEMENT_DYNAMIC(CWSocketException, CException)
#ifdef _DEBUG
void CWSocketException::Dump(CDumpContext& dc) const
{
CObject::Dump(dc);
dc << "m_nError = " << m_nError;
}
#endif
////////// The main class /////////////////////////////////////
CWSocket::CWSocket() : m_hSocket(INVALID_SOCKET)
{
}
CWSocket::~CWSocket()
{
if (m_hSocket != INVALID_SOCKET)
Close();
}
void CWSocket::Attach(SOCKET hSocket)
{
//Validate our parameters
ASSERT(hSocket != INVALID_SOCKET);
if (m_hSocket != INVALID_SOCKET)
Close();
m_hSocket = hSocket;
}
SOCKET CWSocket::Detach()
{
SOCKET socket = m_hSocket;
m_hSocket = INVALID_SOCKET;
return socket;
}
void CWSocket::GetPeerName(CString& sPeerAddress, UINT& nPeerPort)
{
//Validate our parameters
ASSERT(IsCreated()); //must have been created first
SOCKADDR_IN sockAddr;
memset(&sockAddr, 0, sizeof(sockAddr));
int nSockAddrLen = sizeof(sockAddr);
GetPeerName((SOCKADDR*)&sockAddr, &nSockAddrLen);
nPeerPort = ntohs(sockAddr.sin_port);
sPeerAddress = inet_ntoa(sockAddr.sin_addr);
}
void CWSocket::GetSockName(CString& sSocketAddress, UINT& nSocketPort)
{
//Validate our parameters
ASSERT(IsCreated()); //must have been created first
SOCKADDR_IN sockAddr;
memset(&sockAddr, 0, sizeof(sockAddr));
int nSockAddrLen = sizeof(sockAddr);
GetSockName((SOCKADDR*)&sockAddr, &nSockAddrLen);
nSocketPort = ntohs(sockAddr.sin_port);
sSocketAddress = inet_ntoa(sockAddr.sin_addr);
}
void CWSocket::GetPeerName(SOCKADDR* lpSockAddr, int* lpSockAddrLen)
{
//Validate our parameters
ASSERT(IsCreated()); //Must have been created first
if (getpeername(m_hSocket, lpSockAddr, lpSockAddrLen) == SOCKET_ERROR)
AfxThrowWSocketException();
}
void CWSocket::GetSockName(SOCKADDR* lpSockAddr, int* lpSockAddrLen)
{
//Validate our parameters
ASSERT(IsCreated()); //Must have been created first
if (getsockname(m_hSocket, lpSockAddr, lpSockAddrLen) == SOCKET_ERROR)
AfxThrowWSocketException();
}
void CWSocket::Accept(CWSocket& connectedSocket, sockaddr_in& clientAddress)
{
ASSERT(IsCreated()); //must have been created first
ASSERT(!connectedSocket.IsCreated()); //Must be an unitialized socket
//Call the SDK accept function
int nSize = sizeof(sockaddr_in);
SOCKET socket = accept(m_hSocket, (sockaddr*) &clientAddress, &nSize);
if (socket == INVALID_SOCKET)
AfxThrowWSocketException();
//Wrap the return value up into a C++ instance
connectedSocket.Attach(socket);
}
void CWSocket::SetSockOpt(int nOptionName, const void* lpOptionValue, int nOptionLen, int nLevel)
{
//Validate our parameters
ASSERT(IsCreated()); //Must have been created first
if (setsockopt(m_hSocket, nLevel, nOptionName, (LPCSTR)lpOptionValue, nOptionLen) == SOCKET_ERROR)
AfxThrowWSocketException();
}
void CWSocket::GetSockOpt(int nOptionName, void* lpOptionValue, int* lpOptionLen, int nLevel)
{
//Validate our parameters
ASSERT(IsCreated()); //Must have been created first
if (getsockopt(m_hSocket, nLevel, nOptionName, (LPSTR)lpOptionValue, lpOptionLen) == SOCKET_ERROR)
AfxThrowWSocketException();
}
void CWSocket::Bind(const SOCKADDR* lpSockAddr, int nSockAddrLen)
{
//Validate our parameters
ASSERT(IsCreated()); //Must have been created first
if (bind(m_hSocket, lpSockAddr, nSockAddrLen) == SOCKET_ERROR)
AfxThrowWSocketException();
}
void CWSocket::Bind(UINT nSocketPort, LPCTSTR lpszSocketAddress)
{
USES_CONVERSION;
//Setup the structure used in sdk "bind" calls
SOCKADDR_IN sockAddr;
memset(&sockAddr, 0, sizeof(sockAddr));
sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons((u_short)nSocketPort);
//Do we need to bind to a specific IP address?
if (lpszSocketAddress)
{
//Convert to an ASCII string
LPSTR lpszAscii = T2A((LPTSTR) lpszSocketAddress);
sockAddr.sin_addr.s_addr = inet_addr(lpszAscii);
//If the address is not dotted notation, then do a DNS
//lookup of it.
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
{
AfxThrowWSocketException(WSAEINVAL);
return;
}
}
}
else
sockAddr.sin_addr.s_addr = htonl(INADDR_ANY); //Bind to any IP address;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -