#include "stdafx.h"
#ifdef WIN32
#include <stdlib.h>
#ifndef UNDER_CE
#include <crtdbg.h>
#endif
#include <strsafe.h>
#endif
#include "SocketHandle.h"
// Jeff.add.
//#include "Wspiapi.h"
//#include "Ws2tcpip.h"
#include <MSTcpIP.h>


#ifndef BUFFER_SIZE
#define BUFFER_SIZE     64*1024
#endif
#ifndef SOCKHANDLE_TTL
#define SOCKHANDLE_TTL 5
#endif
#ifndef SOCKHANDLE_HOPS
#define SOCKHANDLE_HOPS 10
#endif
#define HOSTNAME_SIZE   MAX_PATH
#define STRING_LENGTH   40

#if !defined(PLATFORM_HAS_INETFUNC)
const char *_inet_ntop(int af, const void *src, char *dst, size_t cnt);
int _inet_pton(int af, const char *src, void *dst);
#endif

#ifdef WIN32
#ifndef UNDER_CE
#pragma comment(lib, "ws2_32.lib")
#else
#pragma comment(lib, "Ws2.lib")
#endif
#endif

#if 1
typedef struct STcpKeepAlive2
{
	DWORD onoff;
	DWORD keepalivetime;
	DWORD keepaliveinterval;
}TCP_KEEP_ALIVE2;

/************************************************************************/
/*  ������SetKeepLive[2/29/2016 IT];
/*  ����������TCP�����ʻ�ʱ��;
/*  ������;
/*  	[IN] Socket��Ҫ���õĿͻ���SOCKET;
/*  ���أ����óɹ�����TRUE;
/*  ע�⣺;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
BOOL SetKeepLive(IN SOCKET &Socket)
{
	const BYTE chOpt = 1; // True;
	// Set KeepAlive �����������, ��ֹ����˲���������;
	if (setsockopt(Socket, SOL_SOCKET, SO_KEEPALIVE, (char *)&chOpt, sizeof(chOpt)) == SOCKET_ERROR)
	{
		printf("���ÿͻ����ʻ����ʧ��1\n\n");
		return FALSE;
	}

	// ���ó�ʱ��ϸ��Ϣ;
	BYTE byRet[5] = {0};
	TCP_KEEP_ALIVE2	klive;
	klive.onoff = 1; // ����;
	klive.keepalivetime = 1000 * 15; // 3���ӳ�ʱ Keep Alive;
	klive.keepaliveinterval = 1000 * 5; // ���Լ��Ϊ5�� Resend if No-Reply;
	INT nResult = 
		WSAIoctl
		(
		Socket, 
		SIO_KEEPALIVE_VALS,
		&klive,
		sizeof(TCP_KEEP_ALIVE2),
		NULL,
		0,
		(unsigned long *)&byRet,
		0,
		NULL
		);

	if ( nResult == SOCKET_ERROR )
	{
		printf("���ÿͻ����ʻ����ʧ��2\n\n");
		return FALSE;
	}

	return TRUE;
}
#endif

CSocketHandle::CSocketHandle(): m_hSocket(INVALID_SOCKET)
{
	m_npendingSize = 0;
	memset(m_szpendingbuf,0,SOCKET_BUFFSIZE);
}

CSocketHandle::~CSocketHandle()
{
	Close();
}

bool CSocketHandle::IsOpen() const 
{
	return ( INVALID_SOCKET != m_hSocket );
}

SOCKET CSocketHandle::GetSocket() const
{
	return m_hSocket;
}

/************************************************************************/
/*  ������GetSocketType[2/29/2016 IT];
/*  ��������ȡ�׽�������;
/*  ������;
/*  ���أ�����-1��ʾ����һ����Ч���׽���;
/*  ע�⣺;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
int CSocketHandle::GetSocketType() const
{
	int type = -1;
	if ( INVALID_SOCKET != m_hSocket ) {
		socklen_t optlen = sizeof(int);
		if ( getsockopt(GetSocket(), SOL_SOCKET, SO_TYPE, reinterpret_cast<char*>(&type),&optlen) == SOCKET_ERROR)
		{
			SetLastError( WSAGetLastError() );
		}
	}
	return type;
}

/************************************************************************/
/*  ������Attach[2/29/2016 IT];
/*  ����������һ��SOCKET���,ʹ��Detach������Close�������ͷž��;
/*  ������;
/*  	[IN] sock��Ҫ���ӵ����е��׽��־��;
/*  ���أ��ɹ�����TRUE;
/*  ע�⣺�����п���ʧ��,��Ҫ���ӵ��׽�����һ����Чֵ���ֵ����ʹ��ʱ;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
bool CSocketHandle::Attach(IN SOCKET sock)
{
	if ( INVALID_SOCKET == m_hSocket )
	{
		m_hSocket = sock;
		return true;
	}
	return false;
}

/************************************************************************/
/*  ������Detach[2/29/2016 IT];
/*  ���������׽��ִ�������з������;
/*  ��������;
/*  ���أ�����ǰ�渽�ӵ��׽��־����INVALID_SOCKET;
/*  ע�⣺;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
SOCKET CSocketHandle::Detach()
{
	SOCKET sock = m_hSocket;
	::InterlockedExchange(reinterpret_cast<long*>(&m_hSocket), INVALID_SOCKET);
	return sock;
}

/************************************************************************/
/*  ������GetSockName[2/29/2016 IT];
/*  ��������ȡ�׽�����(���ص�ַ);
/*  ������;
/*  	[OUT] saddr_in�����ӳɹ�ʱ���صĵ�ǰ���ص�ַ�Ͷ˿ں�;
/*  ���أ��ɹ�����TRUE;
/*  ע�⣺ʹ��ǰ�������InitLibrary����;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
bool CSocketHandle::GetSockName(OUT SockAddrIn& saddr_in) const
{
	_ASSERTE( IsOpen() );
	if (IsOpen()) {
		socklen_t namelen = (socklen_t)saddr_in.Size();
		if (SOCKET_ERROR != getsockname(GetSocket(), saddr_in, &namelen))
		{
			return true;
		}
		SetLastError( WSAGetLastError() );
	}
	return false;
}

/************************************************************************/
/*  ������GetPeerName[2/29/2016 IT];
/*  ��������ȡ��Ե���׽ӽ���(��ȡPeer��ַ);;
/*  ������;
/*  	[OUT] saddr_in�� peer address and port (use only with TCP or client mode UDP);
/*  ���أ��ɹ�����TRUE;
/*  ע�⣺ʹ��ǰ�������InitLibrary����;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
bool CSocketHandle::GetPeerName(OUT SockAddrIn& saddr_in) const
{
	_ASSERTE( IsOpen() );
	if (IsOpen()) {
		socklen_t namelen = (socklen_t)saddr_in.Size();
		if (SOCKET_ERROR != getpeername(GetSocket(), saddr_in, &namelen))
		{
			return true;
		}
		SetLastError( WSAGetLastError() );
	}
	return false;
}

/************************************************************************/
/*  ������Close[2/29/2016 IT];
/*  �������ر��׽���;
/*  ������;
/*  ���أ�void;
/*  ע�⣺��������InitLibrary, CreateSocket, ConnectTo, IsOpen;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
void CSocketHandle::Close()
{
	if ( IsOpen() )
	{
		ShutdownConnection(static_cast<SOCKET>(::InterlockedExchange((LONG*)&m_hSocket, INVALID_SOCKET)));
	}
}

/************************************************************************/
/*  ������AddMembership[2/29/2016 IT];
/*  ���������Ӷಥ��ַ;
/*  ������;
/*  	[IN] pszIPAddr���ಥIP��;
/*  	[IN] pszNIC��IP��ַ�ӿڣ���������ʱ��ijһ�������кţ�;
/*  ���أ��ɹ�����TRUE;
/*  ע�⣺����InitLibrary����;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
bool CSocketHandle::AddMembership(IN LPCTSTR pszIPAddr, IN LPCTSTR pszNIC)
{
	_ASSERTE( IsOpen() );
	if ( IsOpen() )
	{
		int nType = 0;
		socklen_t nOptLen = sizeof(int);
		if ( SOCKET_ERROR != getsockopt(m_hSocket, SOL_SOCKET, SO_TYPE, (char*)&nType, &nOptLen))
		{
			if ( nType == SOCK_DGRAM )
			{
				// Setup interface for multicast traffic
				SockAddrIn mcastAddr;
				if (GetAddressInfo(pszIPAddr, NULL, AF_UNSPEC, mcastAddr))
				{
					SockAddrIn interfAddr;
					GetAddressInfo(pszNIC, NULL, mcastAddr.ss_family, interfAddr);
					if ( mcastAddr.ss_family == AF_INET )
					{
						int nTTL = SOCKHANDLE_TTL;
						if ( SOCKET_ERROR != setsockopt(m_hSocket, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&nTTL, sizeof(nTTL)))
						{
							ULONG ulNIC = interfAddr.GetIPAddr();
							if ( SOCKET_ERROR != setsockopt(m_hSocket, IPPROTO_IP, IP_MULTICAST_IF,(char *) &ulNIC, sizeof(ulNIC)))
							{
								ip_mreq mreq = { 0 };
								mreq.imr_multiaddr.s_addr = mcastAddr.GetIPAddr();
								mreq.imr_interface.s_addr = ulNIC;
								if ( SOCKET_ERROR != setsockopt(m_hSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char*)&mreq, sizeof(mreq)))
								{
									return true;
								}
							}
						}
					}
					else if ( mcastAddr.ss_family == AF_INET6 )
					{
						int nTTL = SOCKHANDLE_HOPS;
						if ( SOCKET_ERROR != setsockopt(m_hSocket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (const char*)&nTTL, sizeof(nTTL)))
						{
							ipv6_mreq mreq6 = { 0 };
							IN6_ADDR mcin6 = ((sockaddr_in6*)&mcastAddr)->sin6_addr;
							memcpy(&(mreq6.ipv6mr_multiaddr), &mcin6, sizeof(IN6_ADDR));
							if ( SOCKET_ERROR != setsockopt(m_hSocket, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (const char*)&mreq6, sizeof(mreq6)))
							{
								return true;
							}
						}
					}
					else
					{
						// invalid socket option
						WSASetLastError(WSAENOPROTOOPT);
					}
				}
			}
			else
			{
				// invalid socket option
				WSASetLastError(WSAENOPROTOOPT);
			}
		}
		SetLastError( WSAGetLastError() );
	}
	return false;
}

/************************************************************************/
/*  ������DropMembership[2/29/2016 IT];
/*  �������Ƴ��ಥ��ַ;
/*  ������;
/*  	[IN] pszIPAddr���ಥIP��;
/*  	[IN] pszNIC��IP��ַ�ӿڣ���������ʱ��ijһ�������кţ�;
/*  ���أ��ɹ�����TRUE;
/*  ע�⣺����InitLibrary����;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
bool CSocketHandle::DropMembership(LPCTSTR pszIPAddr, LPCTSTR pszNIC)
{
	_ASSERTE( IsOpen() );
	if ( IsOpen() )
	{
		int nType = 0;
		socklen_t nOptLen = sizeof(int);
		if ( SOCKET_ERROR != getsockopt(m_hSocket, SOL_SOCKET, SO_TYPE, (char*)&nType, &nOptLen))
		{
			if ( nType == SOCK_DGRAM )
			{
				SockAddrIn mcastAddr;
				if (GetAddressInfo(pszIPAddr, NULL, AF_UNSPEC, mcastAddr))
				{
					SockAddrIn interfAddr;
					GetAddressInfo(pszNIC, NULL, mcastAddr.ss_family, interfAddr);
					if ( mcastAddr.ss_family == AF_INET )
					{
						ip_mreq mreq;
						mreq.imr_multiaddr.s_addr = mcastAddr.GetIPAddr();
						mreq.imr_interface.s_addr = interfAddr.GetIPAddr();;
						if ( SOCKET_ERROR != setsockopt(m_hSocket, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const char*)&mreq, sizeof(mreq)))
						{
							return true;
						}
					}
					else if ( mcastAddr.ss_family == AF_INET6 )
					{
						ipv6_mreq mreq6 = { 0 };
						IN6_ADDR mcin6 = ((sockaddr_in6*)&mcastAddr)->sin6_addr;
						memcpy(&(mreq6.ipv6mr_multiaddr), &mcin6, sizeof(IN6_ADDR));
						if ( SOCKET_ERROR != setsockopt(m_hSocket, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, (const char*)&mreq6, sizeof(mreq6)))
						{
							return true;
						}
					}
					else
					{
						// invalid socket option
						WSASetLastError(WSAENOPROTOOPT);
					}
				}
			}
			else
			{
				// invalid socket option
				WSASetLastError(WSAENOPROTOOPT);
			}
		}
		SetLastError( WSAGetLastError() );
	}
	return false;
}

/************************************************************************/
/*  ������CreateSocket[2/29/2016 IT];
/*  ����������������׽���;
/*  ������;
/*  	[IN] pszHostName����������������������ַ;
/*  	[IN] pszServiceName���������������IP�˿ں�;
/*  	[IN] nFamily��Ҫ�õĵ�ַЭ������ͣ�IPV4��IPV6��;
/*  	[IN] nType��Ҫ�������׽������ͣ�SOCK_STREAM �� SOCK_DGRAM��;
/*  	[IN] uOptions������ѡ��(SO_BROADCAST,SO_REUSEADDR) ;
/*  ���أ��ɹ�����TRUE;
/*  ע�⣺ʹ��WSAGetLastError()������ȡ���Ĵ���,��������InitLibrary, ConnectTo, IsOpen;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
bool CSocketHandle::CreateSocket(IN LPCTSTR pszHostName, IN LPCTSTR pszServiceName, IN int nFamily, IN int nType, IN UINT uOptions /* = 0 */)
{
	// Socket is already opened
	if ( IsOpen() ) {
		SetLastError(ERROR_ACCESS_DENIED);
		return false;
	}

	// Create a Socket that is bound to a specific service provider
	// nFamily: (AF_INET, AF_INET6)
	// nType: (SOCK_STREAM, SOCK_DGRAM)
#ifdef SOCKHANDLE_USE_OVERLAPPED
	SOCKET sock = WSASocket(nFamily, nType, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED);
#else
	SOCKET sock = socket(nFamily, nType, IPPROTO_IP);
#endif
	if (INVALID_SOCKET != sock)
	{
		if (uOptions & SO_REUSEADDR)
		{
			// Inform Windows Sockets provider that a bind on a socket should not be disallowed
			// because the desired address is already in use by another socket
			BOOL optval = TRUE;
			if ( SOCKET_ERROR == setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, (char *) &optval, sizeof( BOOL ) ) )
			{
				SetLastError( WSAGetLastError() );
				closesocket( sock );
				return false;
			}
		}

		if (nType == SOCK_DGRAM)
		{
			if ((uOptions & SO_BROADCAST) && (nFamily == AF_INET))
			{
				// Inform Windows Sockets provider that broadcast messages are allowed
				BOOL optval = TRUE;
				if ( SOCKET_ERROR == setsockopt( sock, SOL_SOCKET, SO_BROADCAST, (char *) &optval, sizeof( BOOL ) ) )
				{
					SetLastError( WSAGetLastError() );
					closesocket( sock );
					return false;
				}
			}
#ifdef SOCKHANDLE_CONFIGBUF
			// configure buffer size
			socklen_t rcvbuf = BUFFER_SIZE;
			if ( SOCKET_ERROR == setsockopt( sock, SOL_SOCKET, SO_RCVBUF, (char *) &rcvbuf, sizeof( int ) ) )
			{
				SetLastError( WSAGetLastError() );
				closesocket( sock );
				return false;
			}
#endif
		}

		// Associate a local address with the socket
		SockAddrIn sockAddr;
		sockAddr.CreateFrom(pszHostName, pszServiceName, nFamily);

		if ( SOCKET_ERROR == bind(sock, sockAddr, (int)sockAddr.Size()))
		{
			SetLastError( WSAGetLastError() );
			closesocket( sock );
			return false;
		}

		// Listen to the socket, only valid for connection socket (TCP)
		if (SOCK_STREAM == nType)
		{
			if ( SOCKET_ERROR == listen(sock, SOMAXCONN))
			{
				SetLastError( WSAGetLastError() );
				closesocket( sock );
				return false;
			}
		}

		// Success, now we may save this socket
		m_hSocket = sock;
	}

	return (INVALID_SOCKET != sock);
}

/************************************************************************/
/*  ������ConnectTo[2/29/2016 IT];
/*  �������ͻ������ӷ����;
/*  ������;
/*  	[IN] pszHostName��Hostname or NIC address;
/*  	[IN] pszRemote��Remote network address;
/*  	[IN] pszServiceName��Network service name or port number;
/*  	[IN] nFamily��address family to use (AF_INET, AF_INET6);
/*  	[IN] nType��type of socket to create (SOCK_STREAM, SOCK_DGRAM);
/*  ���أ�return true if successful, otherwise false (call WSAGetLastError() to retrieve latest error);
/*  ע�⣺��������InitLibrary, CreateSocket, IsOpen;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
bool CSocketHandle::ConnectTo(IN LPCTSTR pszHostName, IN LPCTSTR pszRemote, IN LPCTSTR pszServiceName, IN int nFamily, IN int nType)
{
	// Socket is already opened
	if ( IsOpen() ) {
		SetLastError(ERROR_ACCESS_DENIED);
		return false;
	}

	// Create a Socket that is bound to a specific service provider
	// nFamily: (AF_INET, AF_INET6)
	// nType: (SOCK_STREAM, SOCK_DGRAM)
#ifdef SOCKHANDLE_USE_OVERLAPPED
	SOCKET sock = WSASocket(nFamily, nType, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED);
#else
	SOCKET sock = socket(nFamily, nType, IPPROTO_IP);
#endif
	if (INVALID_SOCKET != sock)
	{
		// Associate a local address with the socket but let provider assign a port number
		SockAddrIn sockAddr;
		if (false == sockAddr.CreateFrom(pszHostName, TEXT("0"), nFamily))
		{
			SetLastError( WSAGetLastError() );
			closesocket( sock );
			return false;
		}

		if ( SOCKET_ERROR == bind(sock, sockAddr, (int)sockAddr.Size()))
		{
			SetLastError( WSAGetLastError() );
			closesocket( sock );
			return false;
		}

#ifdef SOCKHANDLE_CONFIGBUF
		if (nType == SOCK_DGRAM)
		{
			// configure buffer size
			socklen_t rcvbuf = BUFFER_SIZE;
			if ( SOCKET_ERROR == setsockopt( sock, SOL_SOCKET, SO_RCVBUF, (char *) &rcvbuf, sizeof( int ) ) )
			{
				SetLastError( WSAGetLastError() );
				closesocket( sock );
				return false;
			}
		}
#endif
		// Now get destination address & port
		sockAddr.CreateFrom( pszRemote, pszServiceName, nFamily );

		// try to connect - if fail, server not ready
		if (SOCKET_ERROR == connect( sock, sockAddr, (int)sockAddr.Size()))
		{
			SetLastError( WSAGetLastError() );
			closesocket( sock );
			return false;
		}

		// Success, now we may save this socket
		m_hSocket = sock;
	}
	return (INVALID_SOCKET != sock);
}

/************************************************************************/
/*  ������Read[2/29/2016 IT];
/*  ���������׽����ж�ȡ����;
/*  ������;
/*  	[OUT] lpBuffer��Buffer to receive data;
/*  	[IN] dwSize��Size of buffer in bytes;
/*  	[IN] lpAddrIn��Peer address for UDP - this must be NULL for TCP;
/*  	[IN] dwTimeout��Read timeout in milliseconds;
/*  ���أ�return number of bytes read or (-1L) if fail;
/*  ע�⣺��������InitLibrary, CreateSocket, ConnectTo, IsOpen, ReadEx, Write, WriteEx;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
DWORD CSocketHandle::Read(OUT LPBYTE lpBuffer, IN DWORD dwSize, IN LPSOCKADDR lpAddrIn /* = NULL */, IN DWORD dwTimeout /* = INFINITE */)
{
	_ASSERTE( IsOpen() );
	_ASSERTE( lpBuffer != NULL );

	if (!IsOpen() || lpBuffer == NULL || dwSize < 1L)
		return (DWORD)-1L;

	fd_set  fdRead  = { 0 };
	TIMEVAL stTime;
	TIMEVAL *pstTime = NULL;

	if ( INFINITE != dwTimeout ) {
		stTime.tv_sec = dwTimeout/1000;
		stTime.tv_usec = (dwTimeout%1000)*1000;
		pstTime = &stTime;
	}

	SOCKET s = GetSocket();

	// Set Descriptor
	FD_SET( s, &fdRead );

	// Select function set read timeout
	DWORD dwBytesRead = 0L;
	int res = 1;
	if ( pstTime != NULL )
		res = select((int)s, &fdRead, NULL, NULL, pstTime );
	if ( res > 0)
	{
		if (lpAddrIn)
		{
			// UDP
			socklen_t fromlen = sizeof(SOCKADDR_STORAGE);
			res = recvfrom(s, reinterpret_cast<LPSTR>(lpBuffer), dwSize, 0, lpAddrIn, &fromlen);
		}
		else
		{
			// TCP
			res = recv(s, reinterpret_cast<LPSTR>(lpBuffer), dwSize, 0);
		}
		if ( res == 0 ) {
			WSASetLastError(WSAECONNRESET);
			res = SOCKET_ERROR;
		}
	}
	if ( res == SOCKET_ERROR )
	{
		SetLastError( WSAGetLastError() );
	}
	dwBytesRead = (DWORD)((res >= 0)?(res) : (-1));

	return dwBytesRead;
}

#ifdef WIN32
/************************************************************************/
/*  ������ReadEx[2/29/2016 IT];
/*  ���������׽��ֶ�ȡ����,�첽ģʽ��asynchronous mode��;
/*  ������;
/*  	[OUT] lpBuffer��Buffer to receive data;
/*  	[IN] dwSize��Size of buffer in bytes;
/*  	[IN] lpAddrIn��SockAddrIn for UDP - this must be NULL for TCP;
/*  	[IN] lpOverlapped��Windows Overlapped structure (required);
/*  	[IN] lpCompletionRoutine��Winsock Completion routine (required);
/*  ���أ�return number of bytes read, overlapped operation is pending or (-1L) if fail;
/*  ע�⣺�������� InitLibrary, CreateSocket, ConnectTo, IsOpen, Read, Write, WriteEx, IOControl, GetTransferOverlappedResult;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
DWORD CSocketHandle::ReadEx(OUT LPBYTE lpBuffer, IN DWORD dwSize, IN LPSOCKADDR lpAddrIn, IN LPWSAOVERLAPPED lpOverlapped, IN LPWSACOMPLETIONROUTINE lpCompletionRoutine)
{
	_ASSERTE( IsOpen() );
	_ASSERTE( lpBuffer != NULL );

	if (!IsOpen() || lpBuffer == NULL || dwSize < 1L)
		return (DWORD)-1L;

	SOCKET s = GetSocket();
	// Send message to peer
	WSABUF wsabuf;
	wsabuf.buf = (char FAR*)lpBuffer;
	wsabuf.len = dwSize;

	// Select function set read timeout
	DWORD dwBytesRead = 0L;
	DWORD dwFlags = 0L;
	int res = 0;
	if (lpAddrIn)
	{
		// UDP
		socklen_t fromlen = sizeof(SOCKADDR_STORAGE);
		res = WSARecvFrom( s, &wsabuf, 1, &dwBytesRead, &dwFlags, lpAddrIn, &fromlen, lpOverlapped, lpCompletionRoutine);
	}
	else
	{
		// TCP
		res = WSARecv( s, &wsabuf, 1, &dwBytesRead, &dwFlags, lpOverlapped, lpCompletionRoutine);
	}
	if ( res == SOCKET_ERROR )
	{
		res = WSAGetLastError();
		if ( res != WSA_IO_PENDING )
		{
			dwBytesRead = (DWORD)-1L;
			SetLastError( res );
		}
	}

	return dwBytesRead;
}
#endif

/************************************************************************/
/*  ������Write[2/29/2016 IT];
/*  ��������Ŀ���׽��ַ�������;
/*  ������;
/*  	[IN] lpBuffer��Buffer to send;
/*  	[IN] dwCount��Number of bytes to send;
/*  	[IN] lpAddrIn��Peer address for UDP - this must be NULL for TCP;
/*  	[IN] dwTimeout��Write timeout in milliseconds;
/*  ���أ�return number of bytes sent or (-1L) if fail;
/*  ע�⣺��������InitLibrary, CreateSocket, ConnectTo, IsOpen, Read, ReadEx, WriteEx;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
DWORD CSocketHandle::Write(IN const LPBYTE lpBuffer, IN DWORD dwCount, IN const LPSOCKADDR lpAddrIn /* = NULL */, IN DWORD dwTimeout /* = INFINITE */)
{
	_ASSERTE( IsOpen() );
	_ASSERTE( NULL != lpBuffer );

	// validate params
	if (!IsOpen() || NULL == lpBuffer)
		return (DWORD)-1L;

	fd_set  fdWrite  = { 0 };
	TIMEVAL stTime;
	TIMEVAL *pstTime = NULL;

	if ( INFINITE != dwTimeout ) {
		stTime.tv_sec = dwTimeout/1000;
		stTime.tv_usec = (dwTimeout%1000)*1000;
		pstTime = &stTime;
	}

	SOCKET s = GetSocket();

	// Set Descriptor
	FD_SET( s, &fdWrite );

	// Select function set write timeout
	DWORD dwBytesWritten = 0L;
	int res = 1;
	if ( pstTime != NULL )
	{
		res = select((int)s, NULL, &fdWrite, NULL, pstTime );
	}
	if ( res > 0)
	{
		// Send message to peer
		if (lpAddrIn)
		{
			// UDP
			res = sendto( s, reinterpret_cast<LPCSTR>(lpBuffer), dwCount, 0, lpAddrIn, sizeof(SOCKADDR_STORAGE));
		}
		else
		{
			// TCP
			res = send( s, reinterpret_cast<LPCSTR>(lpBuffer), dwCount, 0);
		}
	}
	if ( res == SOCKET_ERROR )
	{
		SetLastError( WSAGetLastError() );
	}
	dwBytesWritten = (DWORD)((res >= 0)?(res) : (-1));

	return dwBytesWritten;
}

#ifdef WIN32
/************************************************************************/
/*  ������WriteEx[2/29/2016 IT];
/*  ��������Ŀ���׽��ַ�������,�첽ģʽ(asynchronous mode);
/*  ������;
/*  	[IN] lpBuffer��Buffer to send;
/*  	[IN] dwCount��Number of bytes to send;
/*  	[IN] lpAddrIn��SockAddrIn for UDP - this must be NULL for TCP;
/*  	[IN] lpOverlapped��Windows Overlapped structure (required);
/*  	[IN] lpCompletionRoutine��Winsock Completion routine (required);
/*  ���أ�return number of bytes read, overlapped operation is pending or (-1L) if fail;
/*  ע�⣺��������InitLibrary, CreateSocket, ConnectTo, IsOpen, Read, ReadEx, Write, IOControl, GetTransferOverlappedResult;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
DWORD CSocketHandle::WriteEx(IN const LPBYTE lpBuffer, IN DWORD dwCount, IN const LPSOCKADDR lpAddrIn, IN LPWSAOVERLAPPED lpOverlapped, IN LPWSACOMPLETIONROUTINE lpCompletionRoutine)
{
	_ASSERTE( IsOpen() );
	_ASSERTE( NULL != lpBuffer );

	// validate params
	if (!IsOpen() || NULL == lpBuffer)
		return (DWORD)-1L;

	SOCKET s = GetSocket();

	// Select function set write timeout
	DWORD dwBytesWritten = 0L;
	int res = 0;
	// Send message to peer
	WSABUF wsabuf;
	wsabuf.buf = (char FAR*) lpBuffer;
	wsabuf.len = dwCount;
	if (lpAddrIn)
	{
		// UDP
		res = WSASendTo( s, &wsabuf, 1, &dwBytesWritten, 0, lpAddrIn, sizeof(SOCKADDR_STORAGE),
			lpOverlapped, lpCompletionRoutine);
	}
	else // TCP
		res = WSASend( s, &wsabuf, 1, &dwBytesWritten, 0, lpOverlapped, lpCompletionRoutine);

	if ( res == SOCKET_ERROR )
	{
		res = WSAGetLastError();
		if ( res != WSA_IO_PENDING )
		{
			dwBytesWritten = (DWORD)-1L;
			SetLastError( res );
		}
	}

	return dwBytesWritten;
}
#endif

#ifdef WIN32
/************************************************************************/
/*  ������IOControl[2/29/2016 IT];
/*  ������Control the mode of a socket (asynchronous mode);
/*  ������;
/*  	[IN] dwIoCode��Control code of operation to perform;
/*  	[IN] lpInBuffer��Pointer to the input buffer;
/*  	[IN] cbInBuffer��Size of the input buffer, in bytes;
/*  	[IN] lpOutBuffer��Pointer to the output buffer;
/*  	[IN] cbOutBuffer��Size of the output buffer, in bytes;
/*  	[IN] lpcbBytesReturned��Pointer to actual number of bytes of output;
/*  	[IN] lpOverlapped��Winsock Overlapped structure;
/*  	[IN] lpCompletionRoutine��Winsock Completion routine;
/*  ���أ�return true if successful, otherwise false (call WSAGetLastError() to retrieve latest error);
/*  ע�⣺��������InitLibrary, CreateSocket, ConnectTo, IsOpen, ReadEx, WriteEx, GetTransferOverlappedResult;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
bool CSocketHandle::IOControl( 
							  IN DWORD dwIoCode, 
							  IN LPBYTE lpInBuffer, 
							  IN DWORD cbInBuffer, 
							  IN LPBYTE lpOutBuffer, 
							  IN DWORD cbOutBuffer, 
							  IN LPDWORD lpcbBytesReturned, 
							  IN LPWSAOVERLAPPED lpOverlapped, 
							  IN LPWSACOMPLETIONROUTINE lpCompletionRoutine )
{
	_ASSERTE( IsOpen() );
	// validate params
	if ( !IsOpen() ) {
		SetLastError(ERROR_INVALID_HANDLE);
		return false;
	}
	int res;
	SOCKET s = GetSocket();
	res = WSAIoctl(s, dwIoCode, lpInBuffer, cbInBuffer, lpOutBuffer, cbOutBuffer,
		lpcbBytesReturned, lpOverlapped, lpCompletionRoutine);
	if ( res == SOCKET_ERROR )
	{
		SetLastError( WSAGetLastError() );
	}
	return ( res != SOCKET_ERROR );
}

/************************************************************************/
/*  ������GetTransferOverlappedResult[2/29/2016 IT];
/*  ������Get Overlapped result (asynchronous mode);
/*  ������;
/*  	[IN] lpOverlapped��Windows Overlapped structure (required);
/*  	[IN] lpcbTransfer��Pointer to get number of bytes transferred;
/*  	[IN] bWait��Force wait for overlapped operation to complete;
/*  	[IN] lpdwFlags��Optional flags (see MSDN on WSARecv API);
/*  	[OUT] ��;
/*  	[IN/OUT] ��;
/*  ���أ��ɹ�����TRUE;
/*  ע�⣺��������InitLibrary, CreateSocket, ConnectTo, IsOpen, ReadEx, WriteEx, IOControl;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
bool CSocketHandle::GetTransferOverlappedResult(IN LPWSAOVERLAPPED lpOverlapped, IN LPDWORD lpcbTransfer, IN bool bWait /* = true */, IN LPDWORD lpdwFlags /* = 0 */)
{
	_ASSERTE( IsOpen() );
	_ASSERTE( NULL != lpOverlapped );

	// validate params
	if (!IsOpen() || NULL == lpOverlapped) {
		SetLastError(ERROR_INVALID_HANDLE);
		return false;
	}

	SOCKET s = GetSocket();
	DWORD dwFlags = 0;
	if ( lpdwFlags == NULL )
		lpdwFlags = &dwFlags;
	BOOL bRet = WSAGetOverlappedResult( s, lpOverlapped, lpcbTransfer, bWait, lpdwFlags );
	if ( !bRet )
	{
		SetLastError( WSAGetLastError() );
	}
	return (bRet != FALSE);
}
#endif


///////////////////////////////////////////////////////////////////////////////
// Utility functions

/************************************************************************/
/*  ������InitLibrary[2/29/2016 IT];
/*  ������Initialize Winsock library. This function calls WSAStartup;
/*  ������;
/*  	[IN] wVersion��Winsock version use MAKEWORD macro if possible (e.g.: MAKEWORD(2,2));
/*  ���أ�return true if successful;
/*  ע�⣺����ReleaseLibrary;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
bool CSocketHandle::InitLibrary(IN WORD wVersion)
{
#ifdef WIN32
	WSADATA WSAData = { 0 };
	return ( 0 == WSAStartup( wVersion, &WSAData ) );
#else
	return true;
#endif
}

/************************************************************************/
/*  ������ReleaseLibrary[2/29/2016 IT];
/*  ������Release Winsock library;
/*  ������;
/*  ���أ�return true if successful;
/*  ע�⣺����InitLibrary;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
bool CSocketHandle::ReleaseLibrary()
{
#ifdef WIN32
	return ( 0 == WSACleanup() );
#else
	return true;
#endif
}

/************************************************************************/
/*  ������WaitForConnection[2/29/2016 IT];
/*  ������Wait for a new connection;
/*  ������;
/*  	[IN] sock��A TCP socket handle. A new socket is return returned;
/*  ���أ�return A new socket when a new client connects;
/*  ע�⣺����GetSocket, CreateSocket;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
SOCKET CSocketHandle::WaitForConnection(IN SOCKET sock)
{ 
#if 0
	return accept(sock, 0, 0);
#else
	SOCKET ncs = accept(sock, 0, 0);
	SetKeepLive(ncs);
	return ncs;
#endif
}

/************************************************************************/
/*  ������ShutdownConnection[2/29/2016 IT];
/*  ������Shutdown a connection;
/*  ������;
/*  	[IN] sock��Socket to shutdown communication;
/*  ���أ�return true if successful;
/*  ע�⣺;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
bool CSocketHandle::ShutdownConnection(IN SOCKET sock)
{
	shutdown(sock, SD_BOTH);
	return ( 0 == closesocket( sock ));
}

static unsigned char chMinClassA_IP [] = { 1,   0,   0,   0   } ;
static unsigned char chMinClassD_IP [] = { 224, 0,   0,   0   } ;
static unsigned char chMaxClassD_IP [] = { 239, 255, 255, 255 } ;

/************************************************************************/
/*  ������IsUnicastIP[2/29/2016 IT];
/*  ������Check if IP address is unicast (network order);
/*  ������;
/*  	[IN] ulAddr��IP address (expected valid unicast address);
/*  ���أ�return true if successful;
/*  ע�⣺;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
bool CSocketHandle::IsUnicastIP( ULONG ulAddr )
{
	return (((unsigned char *) & ulAddr) [0] >= chMinClassA_IP [0] &&
		((unsigned char *) & ulAddr) [0] < chMinClassD_IP [0]) ;
}

/************************************************************************/
/*  ������IsMulticastIP[2/29/2016 IT];
/*  ������Check if IP address is multicast (network order);
/*  ������;
/*  	[IN] ulAddr��IP address (expected valid multicast address);
/*  ���أ�return true if successful;
/*  ע�⣺;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
bool CSocketHandle::IsMulticastIP( ULONG ulAddr )
{
	return (((unsigned char *) & ulAddr) [0] >= chMinClassD_IP [0] &&
		((unsigned char *) & ulAddr) [0] <= chMaxClassD_IP [0]) ;
}

/************************************************************************/
/*  ������FormatIP[2/29/2016 IT];
/*  ������Format IP address to string;
/*  ������;
/*  	[IN] pszIPAddr��Buffer to hold string;
/*  	[IN] nSize��Size of buffer in characters;
/*  	[IN] ulAddr��IP Address to format;
/*  	[IN] bFmtHost��Specify if address (ulAddr) is in host (true) or network format (false);
/*  ���أ�return true if successful. Possible error could be INSUFFICIENT_BUFFER;
/*  ע�⣺;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
bool CSocketHandle::FormatIP(LPTSTR pszIPAddr, UINT nSize, ULONG ulAddr, bool bFmtHost)
{
	if ( pszIPAddr && nSize > 8)
	{
		if ( bFmtHost )
			ulAddr = htonl( ulAddr );
		// Create Address string
		return (SUCCEEDED(StringCchPrintf(pszIPAddr, nSize, TEXT("%u.%u.%u.%u"),
			(UINT)(((PBYTE) &ulAddr)[0]),
			(UINT)(((PBYTE) &ulAddr)[1]),
			(UINT)(((PBYTE) &ulAddr)[2]),
			(UINT)(((PBYTE) &ulAddr)[3]))));
	}
	SetLastError(ERROR_INSUFFICIENT_BUFFER);
	return false;
}

/************************************************************************/
/*  ������FormatIP[2/29/2016 IT];
/*  ������Format IP address to string;
/*  ������;
/*  	[IN] pszIPAddr��Buffer to hold string;
/*  	[IN] nSize��Size of buffer in characters;
/*  	[IN] addrIn��IP Address to format;
/*  ���أ�return true if successful. Possible error could be INSUFFICIENT_BUFFER;
/*  ע�⣺;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
bool CSocketHandle::FormatIP(LPTSTR pszIPAddr, UINT nSize, const SockAddrIn& addrIn)
{
	if ( pszIPAddr && nSize > 8)
	{
		const void* addr;
		char szIPAddr[MAX_PATH] = { 0 };
		if (addrIn.ss_family == AF_INET) {
			addr = &((const sockaddr_in*)&addrIn)->sin_addr;
		} else {
			addr = &((const sockaddr_in6*)&addrIn)->sin6_addr;
		}
		if (_inet_ntop(addrIn.ss_family, const_cast<void*>(addr), szIPAddr, MAX_PATH) != NULL)
		{
#ifdef _UNICODE
			return (0 != MultiByteToWideChar(CP_UTF8, 0, szIPAddr, -1, pszIPAddr, nSize ));
#else
			::StringCbCopyA(pszIPAddr, nSize, szIPAddr);
			return true;
#endif
		}
	}
	SetLastError(ERROR_INSUFFICIENT_BUFFER);
	return false;
}

/************************************************************************/
/*  ������GetPortNumber[2/29/2016 IT];
/*  ������Get service port number;
/*  ������;
/*  	[IN] pszServiceName��Network service name (e.g.: "ftp", "telnet") or port number;
/*  ���أ�return port number;
/*  ע�⣺;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
USHORT CSocketHandle::GetPortNumber( LPCTSTR pszServiceName )
{
	LPSERVENT   lpservent;
	USHORT      nPort = 0;

	if ( _istdigit( pszServiceName[0] ) ) {
		nPort = (USHORT) _ttoi( pszServiceName );
	}
	else {
#ifdef _UNICODE
		char pstrService[HOSTNAME_SIZE] = { 0 };
		WideCharToMultiByte(CP_UTF8, 0, pszServiceName, -1, pstrService, sizeof(pstrService), NULL, NULL );
#else
		LPCTSTR pstrService = pszServiceName;
#endif
		// Convert network byte order to host byte order
		if ( (lpservent = getservbyname( pstrService, NULL )) != NULL )
			nPort = ntohs( lpservent->s_port );
	}

	return nPort;
}

/************************************************************************/
/*  ������GetIPAddress[2/29/2016 IT];
/*  ������Get IP address of a host;
/*  ������;
/*  	[IN] pszHostName��host name or IP address;
/*  ���أ�return Host IP address in host format;
/*  ע�⣺����GetAddressInfo;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
ULONG CSocketHandle::GetIPAddress( LPCTSTR pszHostName )
{
	LPHOSTENT   lphostent;
	ULONG       uAddr = INADDR_NONE;
	TCHAR       szLocal[HOSTNAME_SIZE] = { 0 };

	// if no name specified, get local
	if ( NULL == pszHostName || !pszHostName[0])
	{
		GetLocalName(szLocal, HOSTNAME_SIZE);
		pszHostName = szLocal;
	}

#ifdef _UNICODE
	char pstrHost[HOSTNAME_SIZE] = { 0 };
	WideCharToMultiByte(CP_UTF8, 0, pszHostName, -1, pstrHost, sizeof(pstrHost), NULL, NULL );
#else
	LPCTSTR pstrHost = pszHostName;
#endif

	// Check for an Internet Protocol dotted address string
	uAddr = inet_addr( pstrHost );

	if ( (INADDR_NONE == uAddr) && (strcmp( pstrHost, "255.255.255.255" )) )
	{
		// It's not an address, then try to resolve it as a hostname
		if ( (lphostent = gethostbyname( pstrHost )) != NULL )
			uAddr = *((ULONG *) lphostent->h_addr_list[0]);
	}

	return ntohl( uAddr );
}

/************************************************************************/
/*  ������GetLocalName[2/29/2016 IT];
/*  ������Get current localname for this machine;
/*  ������;
/*  	[IN] pszName��Buffer to receive host name;
/*  	[IN] nSize��Size of this buffer in character;
/*  ���أ�return true if successful;
/*  ע�⣺;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
bool CSocketHandle::GetLocalName(LPTSTR pszName, UINT nSize)
{
	if (pszName != NULL && nSize > 0)
	{
		char szHost[HOSTNAME_SIZE] = { 0 };

		// get host name, if fail, SetLastError is set
		if (SOCKET_ERROR != gethostname(szHost, sizeof(szHost)))
		{
			struct hostent* hp;
			hp = gethostbyname(szHost);
			if (hp != NULL) {
				::StringCbCopyA(szHost, HOSTNAME_SIZE, hp->h_name);
			}

			// check if user provide enough buffer
			size_t cbLength = 0;
			::StringCbLengthA(szHost, HOSTNAME_SIZE, &cbLength);
			if ( cbLength > nSize )
			{
				SetLastError(ERROR_INSUFFICIENT_BUFFER);
				return false;
			}

			// Unicode conversion
#ifdef _UNICODE
			return (0 != MultiByteToWideChar(CP_UTF8, 0, szHost, -1, pszName, nSize ));
#else
			::StringCbCopyA(pszName, nSize, szHost);
			return true;
#endif
		}
		else
			SetLastError( WSAGetLastError() );
	}
	else
		SetLastError(ERROR_INVALID_PARAMETER);
	return false;
}

/************************************************************************/
/*  ������GetLocalAddress[2/29/2016 IT];
/*  ������Get current (default) IP address for this machine;
/*  ������;
/*  	[IN] pszAddress��Buffer to receive IP address (IPv4, IPv6 format);
/*  	[IN] nSize��Size of this buffer in character;
/*  	[IN] nFamily��address family to use (AF_INET, AF_INET6);
/*  ���أ�return true if successful;
/*  ע�⣺;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
bool CSocketHandle::GetLocalAddress(LPTSTR pszAddress, UINT nSize, int nFamily /*= AF_INET*/)
{
	if (pszAddress != NULL && nSize > 0)
	{
		TCHAR szHost[HOSTNAME_SIZE] = { 0 };

		// Get computer local address
		// get host name, if fail, SetLastError is set
		if (GetLocalName(szHost, HOSTNAME_SIZE))
		{
			char szAddress[MAX_PATH] = { 0 };

#ifdef _UNICODE
			char pstrHost[HOSTNAME_SIZE] = { 0 };
			WideCharToMultiByte(CP_UTF8, 0, szHost, -1, pstrHost, sizeof(pstrHost), NULL, NULL );
#else
			LPCTSTR pstrHost = szHost;
#endif
			// get address info
			sockaddr_storage addr_store = { 0 };
			addr_store.ss_family = static_cast<short>(nFamily);
			_inet_pton(nFamily, pstrHost, &addr_store);
			const void* addr;
			if (addr_store.ss_family == AF_INET) {
				addr = &((const sockaddr_in*)&addr_store)->sin_addr;
			} else {
				addr = &((const sockaddr_in6*)&addr_store)->sin6_addr;
			}
			if (_inet_ntop(addr_store.ss_family, const_cast<void*>(addr), szAddress, MAX_PATH) != NULL)
			{
				// Unicode conversion
#ifdef _UNICODE
				return (0 != MultiByteToWideChar(CP_UTF8, 0, szAddress, -1, pszAddress, nSize ));
#else
				::StringCbCopyA(pszAddress, nSize, szAddress);
				return true;
#endif
			}
			else
				SetLastError( WSAGetLastError() );
		}
	}
	else
		SetLastError(ERROR_INVALID_PARAMETER);
	return false;
}

/************************************************************************/
/*  ������GetAddressInfo[2/29/2016 IT];
/*  ������Get IP address info of a host (Supports: IPv4 and IPv6);
/*  ������;
/*  	[IN] pszHostName��host name or IP address;
/*  	[IN] pszServiceName��pszServiceName Network service name (e.g.: "ftp", "telnet") or port number;
/*  	[IN] nFamily��address family to use (AF_INET, AF_INET6);
/*  	[IN] sockAddr��Socket address to fill in;
/*  ���أ�return true if successful;
/*  ע�⣺;
/*  ʾ����;
/*
/*  �޸ģ�;
/*  ���ڣ�;
/*  ���ݣ�;
/************************************************************************/
bool CSocketHandle::GetAddressInfo(LPCTSTR pszHostName, LPCTSTR pszServiceName,int nFamily, SockAddrIn& sockAddr)
{
	const TCHAR szZERO[] = TEXT("0");
	ADDRINFO aiHints;
	ADDRINFO *aiList = NULL;
	memset(&aiHints, 0, sizeof(aiHints));
	aiHints.ai_flags = AI_ADDRCONFIG; // Jeff.��ʱ����;
	aiHints.ai_family = static_cast<short>(nFamily);

	TCHAR szLocal[HOSTNAME_SIZE] = { 0 };
	// if no name specified, get local
	if ( NULL == pszHostName || !pszHostName[0])
	{
		GetLocalName(szLocal, HOSTNAME_SIZE);
		pszHostName = szLocal;
	}
	if ( NULL == pszServiceName || !pszServiceName[0])
	{
		pszServiceName = szZERO;
	}

#ifdef _UNICODE
	char pstrHost[HOSTNAME_SIZE] = { 0 };
	WideCharToMultiByte(CP_UTF8, 0, pszHostName, -1, pstrHost, sizeof(pstrHost), NULL, NULL );
	char pstrService[HOSTNAME_SIZE] = { 0 };
	WideCharToMultiByte(CP_UTF8, 0, pszServiceName, -1, pstrService, sizeof(pstrService), NULL, NULL );
#else
	LPCTSTR pstrHost = pszHostName;
	LPCTSTR pstrService = pszServiceName;
#endif
	if ( SOCKET_ERROR != getaddrinfo(pstrHost, pstrService, &aiHints, &aiList) && ( aiList != 0 ))
	{
		ADDRINFO ai = { 0 };
		ai.ai_addr = sockAddr;
		memcpy(ai.ai_addr, aiList->ai_addr, aiList->ai_addrlen);
		freeaddrinfo( aiList );
		return true;
	}
	SetLastError( WSAGetLastError() );
	return false;
}

///////////////////////////////////////////////////////////////////////////////
// Globals
///////////////////////////////////////////////////////////////////////////////
#if !defined(PLATFORM_HAS_INETFUNC)
///////////////////////////////////////////////////////////////////////////////
// inet_ntop
#if 0
const char *_inet_ntop(int af, const void *src, char *dst, size_t cnt)
{
	if ( dst != NULL)
	{
		dst[0] = 0;
		if (af == AF_INET)
		{
			sockaddr_in in;
			memset(&in, 0, sizeof(in));
			in.sin_family = AF_INET;
			memcpy(&in.sin_addr, src, sizeof(in_addr));
			getnameinfo((sockaddr *)&in, sizeof(sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST);
			return dst;
		}
		else if (af == AF_INET6)
		{
			sockaddr_in6 in;
			memset(&in, 0, sizeof(in));
			in.sin6_family = AF_INET6;
			memcpy(&in.sin6_addr, src, sizeof(in6_addr));
			getnameinfo((sockaddr *)&in, sizeof(sockaddr_in6), dst, cnt, NULL, 0, NI_NUMERICHOST);
			return dst;
		}
	}
	WSASetLastError(WSA_INVALID_PARAMETER);
	return dst;
}

///////////////////////////////////////////////////////////////////////////////
// inet_pton
int _inet_pton(int af, const char *src, void *dst)
{
	int result = SOCKET_ERROR;
	addrinfo aiHints, *aiList = NULL;
	memset(&aiHints, 0, sizeof(aiHints));
	aiHints.ai_family = af;

	if ( SOCKET_ERROR != getaddrinfo(src, NULL, &aiHints, &aiList) && (aiList != NULL))
	{
		memcpy(dst, aiList->ai_addr, aiList->ai_addrlen);
		freeaddrinfo(aiList);
		result = 0;
	}
	return result;
}
#else
//////////////////////////////////////////////////////////////////////////
static const char * inet_ntop_v4 (const void *src, char *dst, size_t size)
{
	const char digits[] = "0123456789";
	int i;
	struct in_addr *addr = (struct in_addr *)src;
	u_long a = ntohl(addr->s_addr);
	const char *orig_dst = dst;

	if (size < INET_ADDRSTRLEN) {
		errno = ENOSPC;
		return NULL;
	}
	for (i = 0; i < 4; ++i) {
		int n = (a >> (24 - i * 8)) & 0xFF;
		int non_zerop = 0;

		if (non_zerop || n / 100 > 0) {
			*dst++ = digits[n / 100];
			n %= 100;
			non_zerop = 1;
		}
		if (non_zerop || n / 10 > 0) {
			*dst++ = digits[n / 10];
			n %= 10;
			non_zerop = 1;
		}
		*dst++ = digits[n];
		if (i != 3)
			*dst++ = '.';
	}
	*dst++ = '\0';
	return orig_dst;
}

#ifdef HAVE_IPV6
static const char * inet_ntop_v6 (const void *src, char *dst, size_t size)
{
	const char xdigits[] = "0123456789abcdef";
	int i;
	const struct in6_addr *addr = (struct in6_addr *)src;
	const u_char *ptr = addr->s6_addr;
	const char *orig_dst = dst;
	int compressed = 0;

	if (size < INET6_ADDRSTRLEN) {
		errno = ENOSPC;
		return NULL;
	}
	for (i = 0; i < 8; ++i) {
		int non_zerop = 0;

		if (compressed == 0 &&
			ptr[0] == 0 && ptr[1] == 0 &&
			i <= 5 &&
			ptr[2] == 0 && ptr[3] == 0 &&
			ptr[4] == 0 && ptr[5] == 0) {

				compressed = 1;

				if (i == 0)
					*dst++ = ':';
				*dst++ = ':';

				for (ptr += 6, i += 3;
					i < 8 && ptr[0] == 0 && ptr[1] == 0;
					++i, ptr += 2);

				if (i >= 8)
					break;
		}

		if (non_zerop || (ptr[0] >> 4)) {
			*dst++ = xdigits[ptr[0] >> 4];
			non_zerop = 1;
		}
		if (non_zerop || (ptr[0] & 0x0F)) {
			*dst++ = xdigits[ptr[0] & 0x0F];
			non_zerop = 1;
		}
		if (non_zerop || (ptr[1] >> 4)) {
			*dst++ = xdigits[ptr[1] >> 4];
			non_zerop = 1;
		}
		*dst++ = xdigits[ptr[1] & 0x0F];
		if (i != 7)
			*dst++ = ':';
		ptr += 2;
	}
	*dst++ = '\0';
	return orig_dst;
}
#endif /* HAVE_IPV6 */

const char * _inet_ntop(int af, const void *src, char *dst, size_t size)
{
	switch (af) {
	case AF_INET :
		return inet_ntop_v4 (src, dst, size);
#ifdef HAVE_IPV6
	case AF_INET6 :
		return inet_ntop_v6 (src, dst, size);
#endif
	default :
		//errno = EAFNOSUPPORT;
		return NULL;
	}
}

int _inet_pton(int af, const char *csrc, void *dst)
{
	char * src;
	if (csrc == NULL || (src = strdup(csrc)) == NULL) {
		_set_errno( ENOMEM );
		return 0;
	}

	switch (af) {
	case AF_INET:
		{
			struct sockaddr_in  si4;
			INT r;
			INT s = sizeof(si4);

			si4.sin_family = AF_INET;
			r = WSAStringToAddress(src, AF_INET, NULL, (LPSOCKADDR) &si4, &s);
			free(src);
			src = NULL;

			if (r == 0) {
				memcpy(dst, &si4.sin_addr, sizeof(si4.sin_addr));
				return 1;
			}
		}
		break;

	case AF_INET6:
		{
			struct sockaddr_in6 si6;
			INT r;
			INT s = sizeof(si6);

			si6.sin6_family = AF_INET6;
			r = WSAStringToAddress(src, AF_INET6, NULL, (LPSOCKADDR) &si6, &s);
			free(src);
			src = NULL;

			if (r == 0) {
				memcpy(dst, &si6.sin6_addr, sizeof(si6.sin6_addr));
				return 1;
			}
		}
		break;

	default:
		_set_errno( ENOSYS/*EAFNOSUPPORT*/ );
		return -1;
	}

	/* the call failed */
	{
		int le = WSAGetLastError();

		if (le == WSAEINVAL)
			return 0;

		_set_errno(le);
		return -1;
	}
}
#endif
#endif