--- /dev/null
+// Win32++ Version 7.3\r
+// Released: 30th November 2011\r
+//\r
+// David Nash\r
+// url: https://sourceforge.net/projects/win32-framework\r
+//\r
+//\r
+// Copyright (c) 2005-2011 David Nash\r
+//\r
+// Permission is hereby granted, free of charge, to\r
+// any person obtaining a copy of this software and\r
+// associated documentation files (the "Software"),\r
+// to deal in the Software without restriction, including\r
+// without limitation the rights to use, copy, modify,\r
+// merge, publish, distribute, sublicense, and/or sell\r
+// copies of the Software, and to permit persons to whom\r
+// the Software is furnished to do so, subject to the\r
+// following conditions:\r
+//\r
+// The above copyright notice and this permission notice\r
+// shall be included in all copies or substantial portions\r
+// of the Software.\r
+//\r
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF\r
+// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED\r
+// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\r
+// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT\r
+// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
+// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE\r
+// OR OTHER DEALINGS IN THE SOFTWARE.\r
+//\r
+////////////////////////////////////////////////////////\r
+\r
+\r
+////////////////////////////////////////////////////////\r
+// socket.h\r
+// Declaration of the CSocket class\r
+//\r
+// The CSocket class represents a network socket. It encapsualtes many of\r
+// the Windows Socket SPI fuctions, providing an object-oriented approach\r
+// to network programming. After StartEvents is called, CSocket monitors\r
+// the socket and responds automatically to network events. This event\r
+// monitoring, for example, automatically calls OnReceive when there is\r
+// data on the socket to be read, and OnAccept when a server should accept\r
+// a connection from a client.\r
+\r
+// Users of this class should be aware that functions like OnReceive,\r
+// OnAccept, etc. are called on a different thread from the one CSocket is\r
+// instanciated on. The thread for these functions needs to respond quickly\r
+// to other network events, so it shouldn't be delayed. It also doesn't run\r
+// a message loop, so it can't be used to create windows. For these reasons\r
+// it might be best to use PostMessage in response to these functions in a\r
+// windows environment.\r
+\r
+// Refer to the network samples for an example of how to use this class to\r
+// create a TCP client & server, and a UDP client and server.\r
+\r
+// To compile programs with CSocket, link with ws3_32.lib for Win32,\r
+// and ws2.lib for Windows CE. Windows 95 systems will need to install the\r
+// "Windows Sockets 2.0 for Windows 95". It's available from:\r
+// http://support.microsoft.com/kb/182108/EN-US/\r
+\r
+// For a TCP server, inherit a class from CSocket and override OnAccept, OnDisconnect\r
+// and OnRecieve. Create one instance of this class and use it as a listening socket.\r
+// The purpose of the listening socket is to detect connections from clients and accept them.\r
+// For the listening socket, we do the following:\r
+// 1) Create the socket.\r
+// 2) Bind an IP address to the socket.\r
+// 3) Listen on the socket for incoming connection requests.\r
+// 4) Use StartNotifyRevents to receive notification of network events.\r
+// 5) Override OnAccept to accept requests on a newly created data CSocket object.\r
+// 6) Create a new data socket for each client connection accepted.\r
+// 7) The server socket uses the 'accept' function to accept an incoming connection\r
+// from this new data socket.\r
+\r
+// The purpose of the data socket is to send data to, and recieve data from the client.\r
+// There will be one data socket for each client accepted by the server.\r
+// To use it we do the following:\r
+// * To recieve data from the client, override OnReceive and use Receive.\r
+// * To send data to use Send.\r
+// * OnDisconnect can be used to detect when the client is disconnected.\r
+\r
+// For a TCP client, inherit from CSocket and override OnReceive and OnDisconnect.\r
+// Create an instance of this inherited class, and perform the following steps:\r
+// 1) Create the socket.\r
+// 2) Connect to the server.\r
+// 3) Use StartNotifyRevents to receive notification of network events.\r
+// We are now ready to send and recieve data from the server.\r
+// * Use Send to send data to the server.\r
+// * Override OnReceive and use Recieve to receive data from the server\r
+// * OnDisconnect can be used to detect when the client is disconnected from the server.\r
+\r
+// Notes regarding IPv6 support\r
+// * IPv6 is supported on Windows Vista and above. Windows XP with SP2 provides\r
+// "experimental" support, which can be enabled by entering "ipv6 install"\r
+// at a command prompt.\r
+// * IPv6 is not supported by all compilters and devlopment environments. In\r
+// particular, it is not supported by Dev-C++ or Borland 5.5. A modern\r
+// Platform SDK needs to be added to Visual Studio 6 for it to support IPv6.\r
+// * IsIPV6Supported returns false if either the operating system or the\r
+// development environment fails to support IPv6.\r
+//\r
+\r
+#ifndef _WIN32XX_SOCKET_H_\r
+#define _WIN32XX_SOCKET_H_\r
+\r
+\r
+#include "wincore.h"\r
+#include <winsock2.h>\r
+#include <ws2tcpip.h>\r
+#include <process.h>\r
+\r
+\r
+#define THREAD_TIMEOUT 100\r
+\r
+\r
+namespace Win32xx\r
+{\r
+\r
+ typedef int WINAPI GETADDRINFO(LPCSTR, LPCSTR, const struct addrinfo*, struct addrinfo**);\r
+ typedef void WINAPI FREEADDRINFO(struct addrinfo*);\r
+\r
+ class CSocket\r
+ {\r
+ public:\r
+ CSocket();\r
+ virtual ~CSocket();\r
+\r
+ // Operations\r
+ virtual void Accept(CSocket& rClientSock, struct sockaddr* addr, int* addrlen);\r
+ virtual int Bind(LPCTSTR addr, LPCTSTR port);\r
+ virtual int Bind(const struct sockaddr* name, int namelen);\r
+ virtual int Connect(LPCTSTR addr, LPCTSTR port);\r
+ virtual int Connect(const struct sockaddr* name, int namelen);\r
+ virtual bool Create( int family, int type, int protocol = IPPROTO_IP);\r
+ virtual void Disconnect();\r
+ virtual void FreeAddrInfo( struct addrinfo* ai );\r
+ virtual int GetAddrInfo( LPCTSTR nodename, LPCTSTR servname, const struct addrinfo* hints, struct addrinfo** res);\r
+ virtual LPCTSTR GetLastError();\r
+ virtual int ioCtlSocket(long cmd, u_long* argp);\r
+ virtual bool IsIPV6Supported();\r
+ virtual int Listen(int backlog = SOMAXCONN);\r
+ virtual int Receive(TCHAR* buf, int len, int flags);\r
+ virtual int ReceiveFrom(TCHAR* buf, int len, int flags, struct sockaddr* from, int* fromlen);\r
+ virtual int Send(LPCTSTR buf, int len, int flags);\r
+ virtual int SendTo(LPCTSTR send, int len, int flags, LPCTSTR addr, LPCTSTR port);\r
+ virtual int SendTo(LPCTSTR buf, int len, int flags, const struct sockaddr* to, int tolen);\r
+\r
+ virtual void StartEvents();\r
+ virtual void StopEvents();\r
+\r
+ // Attributes\r
+ virtual int GetPeerName(struct sockaddr* name, int* namelen);\r
+ virtual int GetSockName(struct sockaddr* name, int* namelen);\r
+ SOCKET& GetSocket() { return m_Socket; }\r
+ virtual int GetSockOpt(int level, int optname, char* optval, int* optlen);\r
+ virtual int SetSockOpt(int level, int optname, const char* optval, int optlen);\r
+\r
+ // Override these functions to monitor events\r
+ virtual void OnAccept() {}\r
+ virtual void OnAddresListChange() {}\r
+ virtual void OnDisconnect() {}\r
+ virtual void OnConnect() {}\r
+ virtual void OnOutOfBand() {}\r
+ virtual void OnQualityOfService() {}\r
+ virtual void OnReceive() {}\r
+ virtual void OnRoutingChange() {}\r
+ virtual void OnSend() {}\r
+\r
+\r
+\r
+ // Allow CSocket to be used as a SOCKET\r
+ operator SOCKET() const {return m_Socket;}\r
+\r
+ private:\r
+ CSocket(const CSocket&); // Disable copy construction\r
+ CSocket& operator = (const CSocket&); // Disable assignment operator\r
+ static UINT WINAPI EventThread(LPVOID thread_data);\r
+\r
+ CString m_ErrorMessage;\r
+ SOCKET m_Socket;\r
+ HMODULE m_hWS2_32;\r
+ HANDLE m_hEventThread; // Handle to the thread\r
+ HANDLE m_StopRequest; // An event to signal the event thread should stop\r
+ HANDLE m_Stopped; // An event to signal the event thread is stopped\r
+\r
+ GETADDRINFO* m_pfnGetAddrInfo; // pointer for the GetAddrInfo function\r
+ FREEADDRINFO* m_pfnFreeAddrInfo; // pointer for the FreeAddrInfo function\r
+ };\r
+}\r
+\r
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
+\r
+namespace Win32xx\r
+{\r
+\r
+ inline CSocket::CSocket() : m_Socket(INVALID_SOCKET), m_hEventThread(0)\r
+ {\r
+ // Initialise the Windows Socket services\r
+ WSADATA wsaData;\r
+\r
+ if (0 != ::WSAStartup(MAKEWORD(2,2), &wsaData))\r
+ throw CWinException(_T("WSAStartup failed"));\r
+\r
+ m_hWS2_32 = ::LoadLibrary(_T("WS2_32.dll"));\r
+ if (0 == m_hWS2_32)\r
+ throw CWinException(_T("Failed to load WS2_2.dll"));\r
+\r
+ m_pfnGetAddrInfo = (GETADDRINFO*) GetProcAddress(m_hWS2_32, "getaddrinfo");\r
+ m_pfnFreeAddrInfo = (FREEADDRINFO*) GetProcAddress(m_hWS2_32, "freeaddrinfo");\r
+\r
+ m_StopRequest = ::CreateEvent(0, TRUE, FALSE, 0);\r
+ m_Stopped = ::CreateEvent(0, TRUE, FALSE, 0);\r
+ }\r
+\r
+ inline CSocket::~CSocket()\r
+ {\r
+ Disconnect();\r
+\r
+ // Close handles\r
+ ::CloseHandle(m_StopRequest);\r
+ ::CloseHandle(m_Stopped);\r
+\r
+ // Terminate the Windows Socket services\r
+ ::WSACleanup();\r
+\r
+ ::FreeLibrary(m_hWS2_32);\r
+ }\r
+\r
+ inline void CSocket::Accept(CSocket& rClientSock, struct sockaddr* addr, int* addrlen)\r
+ {\r
+ // The accept function permits an incoming connection attempt on the socket.\r
+\r
+ rClientSock.m_Socket = ::accept(m_Socket, addr, addrlen);\r
+ if (INVALID_SOCKET == rClientSock.GetSocket())\r
+ TRACE(_T("Accept failed\n"));\r
+ }\r
+\r
+ inline int CSocket::Bind(LPCTSTR addr, LPCTSTR port)\r
+ // The bind function associates a local address with the socket.\r
+ {\r
+ int RetVal = 0;\r
+\r
+ if (IsIPV6Supported())\r
+ {\r
+\r
+#ifdef GetAddrInfo // Skip the following code block for older development environments\r
+\r
+ ADDRINFO Hints= {0};\r
+ Hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;\r
+ ADDRINFO *AddrInfo;\r
+\r
+ RetVal = GetAddrInfo(addr, port, &Hints, &AddrInfo);\r
+ if (RetVal != 0)\r
+ {\r
+ TRACE( _T("GetAddrInfo failed\n"));\r
+ return RetVal;\r
+ }\r
+\r
+ // Bind the IP address to the listening socket\r
+ RetVal = ::bind( m_Socket, AddrInfo->ai_addr, (int)AddrInfo->ai_addrlen );\r
+ if ( RetVal == SOCKET_ERROR )\r
+ {\r
+ TRACE(_T("Bind failed\n"));\r
+ return RetVal;\r
+ }\r
+\r
+ // Free the address information allocated by GetAddrInfo\r
+ FreeAddrInfo(AddrInfo);\r
+\r
+#endif\r
+\r
+ }\r
+ else\r
+ {\r
+ sockaddr_in clientService;\r
+ clientService.sin_family = AF_INET;\r
+ clientService.sin_addr.s_addr = inet_addr( T2A(addr) );\r
+ int nPort = -1;\r
+ nPort = atoi( T2A(port) );\r
+ if (-1 == nPort)\r
+ {\r
+ TRACE(_T("Invalid port number\n"));\r
+ return SOCKET_ERROR;\r
+ }\r
+ clientService.sin_port = htons( (u_short)nPort );\r
+\r
+ RetVal = ::bind( m_Socket, (SOCKADDR*) &clientService, sizeof(clientService) );\r
+ if ( 0 != RetVal )\r
+ TRACE(_T("Bind failed\n"));\r
+ }\r
+\r
+ return RetVal;\r
+ }\r
+\r
+ inline int CSocket::Bind(const struct sockaddr* name, int namelen)\r
+ {\r
+ // The bind function associates a local address with the socket.\r
+\r
+ int Result = ::bind (m_Socket, name, namelen);\r
+ if ( 0 != Result )\r
+ TRACE(_T("Bind failed\n"));\r
+ return Result;\r
+ }\r
+\r
+ inline int CSocket::Connect(LPCTSTR addr, LPCTSTR port)\r
+ // The Connect function establishes a connection to the socket.\r
+ {\r
+ int RetVal = 0;\r
+\r
+ if (IsIPV6Supported())\r
+ {\r
+\r
+#ifdef GetAddrInfo // Skip the following code block for older development environments\r
+\r
+ ADDRINFO Hints= {0};\r
+ Hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;\r
+ ADDRINFO *AddrInfo;\r
+\r
+ RetVal = GetAddrInfo(addr, port, &Hints, &AddrInfo);\r
+ if (RetVal != 0)\r
+ {\r
+ TRACE( _T("getaddrinfo failed\n"));\r
+ return SOCKET_ERROR;\r
+ }\r
+\r
+ // Bind the IP address to the listening socket\r
+ RetVal = Connect( AddrInfo->ai_addr, (int)AddrInfo->ai_addrlen );\r
+ if ( RetVal == SOCKET_ERROR )\r
+ {\r
+ TRACE(_T("Connect failed\n"));\r
+ return RetVal;\r
+ }\r
+\r
+ // Free the address information allocatied by GetAddrInfo\r
+ FreeAddrInfo(AddrInfo);\r
+\r
+#endif\r
+\r
+ }\r
+ else\r
+ {\r
+ sockaddr_in clientService;\r
+ clientService.sin_family = AF_INET;\r
+ clientService.sin_addr.s_addr = inet_addr( T2A(addr) );\r
+ int nPort = -1;\r
+ nPort = atoi( T2A(port) );\r
+ if (-1 == nPort)\r
+ {\r
+ TRACE(_T("Invalid port number\n"));\r
+ return SOCKET_ERROR;\r
+ }\r
+ clientService.sin_port = htons( (u_short)nPort );\r
+\r
+ RetVal = ::connect( m_Socket, (SOCKADDR*) &clientService, sizeof(clientService) );\r
+ if ( 0 != RetVal )\r
+ TRACE(_T("Connect failed\n"));\r
+ }\r
+\r
+ return RetVal;\r
+ }\r
+\r
+ inline int CSocket::Connect(const struct sockaddr* name, int namelen)\r
+ {\r
+ // The Connect function establishes a connection to the socket.\r
+\r
+ int Result = ::connect( m_Socket, name, namelen );\r
+ if ( 0 != Result )\r
+ TRACE(_T("Connect failed\n"));\r
+\r
+ return Result;\r
+ }\r
+\r
+ inline bool CSocket::Create( int family, int type, int protocol /*= IPPROTO_IP*/)\r
+ {\r
+ // Creates the socket\r
+\r
+ // Valid values:\r
+ // family: AF_INET or AF_INET6\r
+ // type: SOCK_DGRAM, SOCK_SEQPACKET, SOCK_STREAM, SOCK_RAW\r
+ // protocol: IPPROTO_IP, IPPROTO_TCP, IPPROTO_UDP, IPPROTO_RAW, IPPROTO_ICMP, IPPROTO_ICMPV6\r
+\r
+ m_Socket = socket(family, type, protocol);\r
+ if(m_Socket == INVALID_SOCKET)\r
+ {\r
+ TRACE(_T("Failed to create socket\n"));\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+ }\r
+\r
+ inline void CSocket::Disconnect()\r
+ {\r
+ ::shutdown(m_Socket, SD_BOTH);\r
+ StopEvents();\r
+ ::closesocket(m_Socket);\r
+ m_Socket = INVALID_SOCKET;\r
+ }\r
+\r
+ inline UINT WINAPI CSocket::EventThread(LPVOID thread_data)\r
+ {\r
+ // These are the possible network event notifications:\r
+ // FD_READ Notification of readiness for reading.\r
+ // FD_WRITE Motification of readiness for writing.\r
+ // FD_OOB Notification of the arrival of Out Of Band data.\r
+ // FD_ACCEPT Notification of incoming connections.\r
+ // FD_CONNECT Notification of completed connection or multipoint join operation.\r
+ // FD_CLOSE Notification of socket closure.\r
+ // FD_QOS Notification of socket Quality Of Service changes\r
+ // FD_ROUTING_INTERFACE_CHANGE Notification of routing interface changes for the specified destination.\r
+ // FD_ADDRESS_LIST_CHANGE Notification of local address list changes for the address family of the socket.\r
+\r
+ WSANETWORKEVENTS NetworkEvents;\r
+ CSocket* pSocket = (CSocket*)thread_data;\r
+ SOCKET sClient = pSocket->m_Socket;\r
+\r
+ WSAEVENT AllEvents[2];\r
+ AllEvents[0] = ::WSACreateEvent();\r
+ AllEvents[1] = (WSAEVENT)pSocket->m_StopRequest;\r
+ long Events = FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE |\r
+ FD_QOS | FD_ROUTING_INTERFACE_CHANGE | FD_ADDRESS_LIST_CHANGE;\r
+\r
+ // Associate the network event object (hNetworkEvents) with the\r
+ // specified network events (Events) on socket sClient.\r
+ if( SOCKET_ERROR == WSAEventSelect(sClient, AllEvents[0], Events))\r
+ {\r
+ TRACE(_T("Error in Event Select\n"));\r
+ ::SetEvent(pSocket->m_Stopped);\r
+ ::WSACloseEvent(AllEvents[0]);\r
+ return 0;\r
+ }\r
+\r
+ // loop until the stop event is set\r
+ for (;;) // infinite loop\r
+ {\r
+ // Wait 100 ms for a network event\r
+ DWORD dwResult = ::WSAWaitForMultipleEvents(2, AllEvents, FALSE, THREAD_TIMEOUT, FALSE);\r
+\r
+ // Check event for stop thread\r
+ if(::WaitForSingleObject(pSocket->m_StopRequest, 0) == WAIT_OBJECT_0)\r
+ {\r
+ ::WSACloseEvent(AllEvents[0]);\r
+ ::SetEvent(pSocket->m_Stopped);\r
+ return 0;\r
+ }\r
+\r
+ if (WSA_WAIT_FAILED == dwResult)\r
+ {\r
+ TRACE(_T("WSAWaitForMultipleEvents failed\n"));\r
+ ::WSACloseEvent(AllEvents[0]);\r
+ ::SetEvent(pSocket->m_Stopped);\r
+ return 0;\r
+ }\r
+\r
+ // Proceed if a network event occurred\r
+ if (WSA_WAIT_TIMEOUT != dwResult)\r
+ {\r
+\r
+ if ( SOCKET_ERROR == ::WSAEnumNetworkEvents(sClient, AllEvents[0], &NetworkEvents) )\r
+ {\r
+ TRACE(_T("WSAEnumNetworkEvents failed\n"));\r
+ ::WSACloseEvent(AllEvents[0]);\r
+ ::SetEvent(pSocket->m_Stopped);\r
+ return 0;\r
+ }\r
+\r
+ if (NetworkEvents.lNetworkEvents & FD_ACCEPT)\r
+ pSocket->OnAccept();\r
+\r
+ if (NetworkEvents.lNetworkEvents & FD_READ)\r
+ pSocket->OnReceive();\r
+\r
+ if (NetworkEvents.lNetworkEvents & FD_WRITE)\r
+ pSocket->OnSend();\r
+\r
+ if (NetworkEvents.lNetworkEvents & FD_OOB)\r
+ pSocket->OnOutOfBand();\r
+\r
+ if (NetworkEvents.lNetworkEvents & FD_QOS)\r
+ pSocket->OnQualityOfService();\r
+\r
+ if (NetworkEvents.lNetworkEvents & FD_CONNECT)\r
+ pSocket->OnConnect();\r
+\r
+ if (NetworkEvents.lNetworkEvents & FD_ROUTING_INTERFACE_CHANGE)\r
+ pSocket->OnRoutingChange();\r
+\r
+ if (NetworkEvents.lNetworkEvents & FD_ADDRESS_LIST_CHANGE)\r
+ pSocket->OnAddresListChange();\r
+\r
+ if (NetworkEvents.lNetworkEvents & FD_CLOSE)\r
+ {\r
+ ::shutdown(sClient, SD_BOTH);\r
+ ::closesocket(sClient);\r
+ pSocket->OnDisconnect();\r
+ ::WSACloseEvent(AllEvents[0]);\r
+ ::SetEvent(pSocket->m_Stopped);\r
+ return 0;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ inline int CSocket::GetAddrInfo( LPCTSTR nodename, LPCTSTR servname, const struct addrinfo* hints, struct addrinfo** res)\r
+ {\r
+\r
+#ifdef GetAddrInfo\r
+\r
+ std::string sNodeName = T2A(nodename);\r
+ std::string sServName = T2A(servname);\r
+ return (*m_pfnGetAddrInfo)(sNodeName.c_str(), sServName.c_str(), hints, res);\r
+\r
+#else\r
+\r
+ UNREFERENCED_PARAMETER(nodename);\r
+ UNREFERENCED_PARAMETER(servname);\r
+ UNREFERENCED_PARAMETER(hints);\r
+ UNREFERENCED_PARAMETER(res);\r
+\r
+ throw CWinException(_T("getaddrinfo is not supported"));\r
+\r
+#endif\r
+\r
+ }\r
+\r
+ inline LPCTSTR CSocket::GetLastError()\r
+ {\r
+ // Retrieves the most recent network error.\r
+\r
+ int ErrorCode = WSAGetLastError();\r
+ LPTSTR Message = NULL;\r
+ m_ErrorMessage = _T("");\r
+\r
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |\r
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_MAX_WIDTH_MASK,\r
+ NULL, ErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),\r
+ (LPTSTR)&Message, 1024, NULL);\r
+\r
+ if (Message)\r
+ {\r
+ m_ErrorMessage = Message;\r
+ ::LocalFree(Message);\r
+ }\r
+\r
+ return m_ErrorMessage;\r
+ }\r
+\r
+ inline int CSocket::GetPeerName(struct sockaddr* name, int* namelen)\r
+ {\r
+ int Result = ::getpeername(m_Socket, name, namelen);\r
+ if (0 != Result)\r
+ TRACE(_T("GetPeerName failed\n"));\r
+\r
+ return Result;\r
+ }\r
+\r
+ inline int CSocket::GetSockName(struct sockaddr* name, int* namelen)\r
+ {\r
+ int Result = ::getsockname(m_Socket, name, namelen);\r
+ if (0 != Result)\r
+ TRACE(_T("GetSockName Failed\n"));\r
+\r
+ return Result;\r
+ }\r
+\r
+ inline int CSocket::GetSockOpt(int level, int optname, char* optval, int* optlen)\r
+ {\r
+ int Result = ::getsockopt(m_Socket, level, optname, optval, optlen);\r
+ if (0 != Result)\r
+ TRACE(_T("GetSockOpt Failed\n"));\r
+\r
+ return Result;\r
+ }\r
+\r
+ inline void CSocket::FreeAddrInfo( struct addrinfo* ai )\r
+ {\r
+\r
+#ifdef GetAddrInfo\r
+\r
+ (*m_pfnFreeAddrInfo)(ai);\r
+\r
+#else\r
+\r
+ UNREFERENCED_PARAMETER(ai);\r
+\r
+ throw CWinException(_T("getaddrinfo is not supported"));\r
+\r
+#endif\r
+\r
+ }\r
+\r
+ inline int CSocket::ioCtlSocket(long cmd, u_long* argp)\r
+ {\r
+ int Result = ::ioctlsocket(m_Socket, cmd, argp);\r
+ if (0 != Result)\r
+ TRACE(_T("ioCtlSocket Failed\n"));\r
+\r
+ return Result;\r
+ }\r
+\r
+ inline bool CSocket::IsIPV6Supported()\r
+ {\r
+ bool IsIPV6Supported = FALSE;\r
+\r
+#ifdef GetAddrInfo\r
+\r
+ if (m_pfnGetAddrInfo != 0 && m_pfnFreeAddrInfo != 0)\r
+ IsIPV6Supported = TRUE;\r
+\r
+#endif\r
+\r
+ return IsIPV6Supported;\r
+ }\r
+\r
+ inline int CSocket::Listen(int backlog /*= SOMAXCONN*/)\r
+ {\r
+ int Result = ::listen(m_Socket, backlog);\r
+ if (0 != Result)\r
+ TRACE(_T("Listen Failed\n"));\r
+\r
+ return Result;\r
+ }\r
+\r
+ inline int CSocket::Receive(TCHAR* buf, int len, int flags)\r
+ {\r
+ std::vector<char> vChar(len+1, '\0');\r
+ char* pCharArray = &vChar.front();\r
+ int Result = ::recv(m_Socket, pCharArray, len, flags);\r
+ if (SOCKET_ERROR == Result)\r
+ TRACE(_T("Receive failed\n"));\r
+\r
+ lstrcpyn(buf, A2T(pCharArray), len);\r
+\r
+ return Result;\r
+ }\r
+\r
+ inline int CSocket::ReceiveFrom(TCHAR* buf, int len, int flags, struct sockaddr* from, int* fromlen)\r
+ //The ReceiveFrom function receives a datagram and stores the source address.\r
+ {\r
+ std::vector<char> vChar(len+1, '\0');\r
+ char* pCharArray = &vChar.front();\r
+ int Result = ::recvfrom(m_Socket, pCharArray, len, flags, from, fromlen);\r
+ if (SOCKET_ERROR == Result)\r
+ TRACE(_T("ReceiveFrom failed\n"));\r
+\r
+ lstrcpyn(buf, A2T(pCharArray), len);\r
+\r
+ return Result;\r
+ }\r
+\r
+ inline int CSocket::Send(LPCTSTR buf, int len, int flags)\r
+ {\r
+ int Result = ::send(m_Socket, T2A(buf), len, flags);\r
+ if (SOCKET_ERROR == Result)\r
+ TRACE(_T("Send failed\n"));\r
+\r
+ return Result;\r
+ }\r
+\r
+ inline int CSocket::SendTo(LPCTSTR send, int len, int flags, LPCTSTR addr, LPCTSTR port)\r
+ // The sendto function sends data to a specific destination.\r
+ {\r
+ int RetVal = 0;\r
+\r
+ if (IsIPV6Supported())\r
+ {\r
+\r
+#ifdef GetAddrInfo // Skip the following code block for older development environments\r
+\r
+ ADDRINFO Hints= {0};\r
+ Hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;\r
+ ADDRINFO *AddrInfo;\r
+\r
+ RetVal = GetAddrInfo(addr, port, &Hints, &AddrInfo);\r
+ if (RetVal != 0)\r
+ {\r
+ TRACE( _T("GetAddrInfo failed\n"));\r
+ return SOCKET_ERROR;\r
+ }\r
+\r
+ RetVal = ::sendto(m_Socket, T2A(send), len, flags, AddrInfo->ai_addr, (int)AddrInfo->ai_addrlen );\r
+ if ( RetVal == SOCKET_ERROR )\r
+ {\r
+ TRACE(_T("SendTo failed\n"));\r
+ return RetVal;\r
+ }\r
+\r
+ // Free the address information allocatied by GetAddrInfo\r
+ FreeAddrInfo(AddrInfo);\r
+\r
+#endif\r
+\r
+ }\r
+ else\r
+ {\r
+ sockaddr_in clientService;\r
+ clientService.sin_family = AF_INET;\r
+ clientService.sin_addr.s_addr = inet_addr( T2A(addr) );\r
+ int nPort = -1;\r
+ nPort = atoi( T2A(port));\r
+ if (-1 == nPort)\r
+ {\r
+ TRACE(_T("Invalid port number\n"));\r
+ return SOCKET_ERROR;\r
+ }\r
+ clientService.sin_port = htons( (u_short)nPort );\r
+\r
+ RetVal = ::sendto( m_Socket, T2A(send), len, flags, (SOCKADDR*) &clientService, sizeof(clientService) );\r
+ if ( SOCKET_ERROR != RetVal )\r
+ TRACE(_T("SendTo failed\n"));\r
+ }\r
+\r
+ return RetVal;\r
+ }\r
+\r
+ inline int CSocket::SendTo(LPCTSTR buf, int len, int flags, const struct sockaddr* to, int tolen)\r
+ // The sendto function sends data to a specific destination.\r
+ {\r
+ int Result = ::sendto(m_Socket, T2A(buf), len, flags, to, tolen);\r
+ if (SOCKET_ERROR == Result)\r
+ TRACE(_T("SendTo failed\n"));\r
+\r
+ return Result;\r
+ }\r
+\r
+ inline int CSocket::SetSockOpt(int level, int optname, const char* optval, int optlen)\r
+ {\r
+ int Result = ::setsockopt(m_Socket, level, optname, optval, optlen);\r
+ if (0 != Result)\r
+ TRACE(_T("SetSockOpt failed\n"));\r
+\r
+ return Result;\r
+ }\r
+\r
+ inline void CSocket::StartEvents()\r
+ {\r
+ // This function starts the thread which monitors the socket for events.\r
+ StopEvents(); // Ensure the thread isn't already running\r
+ UINT ThreadID; // a return variable required for Win95, Win98, WinME\r
+ m_hEventThread = (HANDLE)::_beginthreadex(NULL, 0, CSocket::EventThread, (LPVOID) this, 0, &ThreadID);\r
+ }\r
+\r
+ inline void CSocket::StopEvents()\r
+ {\r
+ // Terminates the event thread gracefully (if possible)\r
+ if (m_hEventThread)\r
+ {\r
+ ::SetThreadPriority(m_hEventThread, THREAD_PRIORITY_HIGHEST);\r
+ ::SetEvent(m_StopRequest);\r
+\r
+ for (;;) // infinite loop\r
+ {\r
+ // wait for the Thread stopping event to be set\r
+ if ( WAIT_TIMEOUT == ::WaitForSingleObject(m_Stopped, THREAD_TIMEOUT * 10) )\r
+ {\r
+ // Note: An excessive delay in processing any of the notification functions\r
+ // can cause us to get here. (Yes one second is an excessive delay. Its a bug!)\r
+ TRACE(_T("*** Error: Event Thread won't die ***\n") );\r
+ }\r
+ else break;\r
+ }\r
+\r
+ ::CloseHandle(m_hEventThread);\r
+ m_hEventThread = 0;\r
+ }\r
+\r
+ ::ResetEvent(m_StopRequest);\r
+ ::ResetEvent(m_Stopped);\r
+ }\r
+}\r
+\r
+\r
+#endif // #ifndef _WIN32XX_SOCKET_H_\r
+\r