1 // Win32++ Version 7.3
\r
2 // Released: 30th November 2011
\r
6 // url: https://sourceforge.net/projects/win32-framework
\r
9 // Copyright (c) 2005-2011 David Nash
\r
11 // Permission is hereby granted, free of charge, to
\r
12 // any person obtaining a copy of this software and
\r
13 // associated documentation files (the "Software"),
\r
14 // to deal in the Software without restriction, including
\r
15 // without limitation the rights to use, copy, modify,
\r
16 // merge, publish, distribute, sublicense, and/or sell
\r
17 // copies of the Software, and to permit persons to whom
\r
18 // the Software is furnished to do so, subject to the
\r
19 // following conditions:
\r
21 // The above copyright notice and this permission notice
\r
22 // shall be included in all copies or substantial portions
\r
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
\r
26 // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
\r
27 // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
\r
28 // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
\r
29 // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
\r
30 // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
\r
31 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
\r
32 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
\r
33 // OR OTHER DEALINGS IN THE SOFTWARE.
\r
35 ////////////////////////////////////////////////////////
\r
38 ////////////////////////////////////////////////////////
\r
40 // Declaration of the CSocket class
\r
42 // The CSocket class represents a network socket. It encapsualtes many of
\r
43 // the Windows Socket SPI fuctions, providing an object-oriented approach
\r
44 // to network programming. After StartEvents is called, CSocket monitors
\r
45 // the socket and responds automatically to network events. This event
\r
46 // monitoring, for example, automatically calls OnReceive when there is
\r
47 // data on the socket to be read, and OnAccept when a server should accept
\r
48 // a connection from a client.
\r
50 // Users of this class should be aware that functions like OnReceive,
\r
51 // OnAccept, etc. are called on a different thread from the one CSocket is
\r
52 // instanciated on. The thread for these functions needs to respond quickly
\r
53 // to other network events, so it shouldn't be delayed. It also doesn't run
\r
54 // a message loop, so it can't be used to create windows. For these reasons
\r
55 // it might be best to use PostMessage in response to these functions in a
\r
56 // windows environment.
\r
58 // Refer to the network samples for an example of how to use this class to
\r
59 // create a TCP client & server, and a UDP client and server.
\r
61 // To compile programs with CSocket, link with ws3_32.lib for Win32,
\r
62 // and ws2.lib for Windows CE. Windows 95 systems will need to install the
\r
63 // "Windows Sockets 2.0 for Windows 95". It's available from:
\r
64 // http://support.microsoft.com/kb/182108/EN-US/
\r
66 // For a TCP server, inherit a class from CSocket and override OnAccept, OnDisconnect
\r
67 // and OnRecieve. Create one instance of this class and use it as a listening socket.
\r
68 // The purpose of the listening socket is to detect connections from clients and accept them.
\r
69 // For the listening socket, we do the following:
\r
70 // 1) Create the socket.
\r
71 // 2) Bind an IP address to the socket.
\r
72 // 3) Listen on the socket for incoming connection requests.
\r
73 // 4) Use StartNotifyRevents to receive notification of network events.
\r
74 // 5) Override OnAccept to accept requests on a newly created data CSocket object.
\r
75 // 6) Create a new data socket for each client connection accepted.
\r
76 // 7) The server socket uses the 'accept' function to accept an incoming connection
\r
77 // from this new data socket.
\r
79 // The purpose of the data socket is to send data to, and recieve data from the client.
\r
80 // There will be one data socket for each client accepted by the server.
\r
81 // To use it we do the following:
\r
82 // * To recieve data from the client, override OnReceive and use Receive.
\r
83 // * To send data to use Send.
\r
84 // * OnDisconnect can be used to detect when the client is disconnected.
\r
86 // For a TCP client, inherit from CSocket and override OnReceive and OnDisconnect.
\r
87 // Create an instance of this inherited class, and perform the following steps:
\r
88 // 1) Create the socket.
\r
89 // 2) Connect to the server.
\r
90 // 3) Use StartNotifyRevents to receive notification of network events.
\r
91 // We are now ready to send and recieve data from the server.
\r
92 // * Use Send to send data to the server.
\r
93 // * Override OnReceive and use Recieve to receive data from the server
\r
94 // * OnDisconnect can be used to detect when the client is disconnected from the server.
\r
96 // Notes regarding IPv6 support
\r
97 // * IPv6 is supported on Windows Vista and above. Windows XP with SP2 provides
\r
98 // "experimental" support, which can be enabled by entering "ipv6 install"
\r
99 // at a command prompt.
\r
100 // * IPv6 is not supported by all compilters and devlopment environments. In
\r
101 // particular, it is not supported by Dev-C++ or Borland 5.5. A modern
\r
102 // Platform SDK needs to be added to Visual Studio 6 for it to support IPv6.
\r
103 // * IsIPV6Supported returns false if either the operating system or the
\r
104 // development environment fails to support IPv6.
\r
107 #ifndef _WIN32XX_SOCKET_H_
\r
108 #define _WIN32XX_SOCKET_H_
\r
111 #include "wincore.h"
\r
112 #include <winsock2.h>
\r
113 #include <ws2tcpip.h>
\r
114 #include <process.h>
\r
117 #define THREAD_TIMEOUT 100
\r
123 typedef int WINAPI GETADDRINFO(LPCSTR, LPCSTR, const struct addrinfo*, struct addrinfo**);
\r
124 typedef void WINAPI FREEADDRINFO(struct addrinfo*);
\r
130 virtual ~CSocket();
\r
133 virtual void Accept(CSocket& rClientSock, struct sockaddr* addr, int* addrlen);
\r
134 virtual int Bind(LPCTSTR addr, LPCTSTR port);
\r
135 virtual int Bind(const struct sockaddr* name, int namelen);
\r
136 virtual int Connect(LPCTSTR addr, LPCTSTR port);
\r
137 virtual int Connect(const struct sockaddr* name, int namelen);
\r
138 virtual bool Create( int family, int type, int protocol = IPPROTO_IP);
\r
139 virtual void Disconnect();
\r
140 virtual void FreeAddrInfo( struct addrinfo* ai );
\r
141 virtual int GetAddrInfo( LPCTSTR nodename, LPCTSTR servname, const struct addrinfo* hints, struct addrinfo** res);
\r
142 virtual LPCTSTR GetLastError();
\r
143 virtual int ioCtlSocket(long cmd, u_long* argp);
\r
144 virtual bool IsIPV6Supported();
\r
145 virtual int Listen(int backlog = SOMAXCONN);
\r
146 virtual int Receive(TCHAR* buf, int len, int flags);
\r
147 virtual int ReceiveFrom(TCHAR* buf, int len, int flags, struct sockaddr* from, int* fromlen);
\r
148 virtual int Send(LPCTSTR buf, int len, int flags);
\r
149 virtual int SendTo(LPCTSTR send, int len, int flags, LPCTSTR addr, LPCTSTR port);
\r
150 virtual int SendTo(LPCTSTR buf, int len, int flags, const struct sockaddr* to, int tolen);
\r
152 virtual void StartEvents();
\r
153 virtual void StopEvents();
\r
156 virtual int GetPeerName(struct sockaddr* name, int* namelen);
\r
157 virtual int GetSockName(struct sockaddr* name, int* namelen);
\r
158 SOCKET& GetSocket() { return m_Socket; }
\r
159 virtual int GetSockOpt(int level, int optname, char* optval, int* optlen);
\r
160 virtual int SetSockOpt(int level, int optname, const char* optval, int optlen);
\r
162 // Override these functions to monitor events
\r
163 virtual void OnAccept() {}
\r
164 virtual void OnAddresListChange() {}
\r
165 virtual void OnDisconnect() {}
\r
166 virtual void OnConnect() {}
\r
167 virtual void OnOutOfBand() {}
\r
168 virtual void OnQualityOfService() {}
\r
169 virtual void OnReceive() {}
\r
170 virtual void OnRoutingChange() {}
\r
171 virtual void OnSend() {}
\r
175 // Allow CSocket to be used as a SOCKET
\r
176 operator SOCKET() const {return m_Socket;}
\r
179 CSocket(const CSocket&); // Disable copy construction
\r
180 CSocket& operator = (const CSocket&); // Disable assignment operator
\r
181 static UINT WINAPI EventThread(LPVOID thread_data);
\r
183 CString m_ErrorMessage;
\r
186 HANDLE m_hEventThread; // Handle to the thread
\r
187 HANDLE m_StopRequest; // An event to signal the event thread should stop
\r
188 HANDLE m_Stopped; // An event to signal the event thread is stopped
\r
190 GETADDRINFO* m_pfnGetAddrInfo; // pointer for the GetAddrInfo function
\r
191 FREEADDRINFO* m_pfnFreeAddrInfo; // pointer for the FreeAddrInfo function
\r
195 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\r
200 inline CSocket::CSocket() : m_Socket(INVALID_SOCKET), m_hEventThread(0)
\r
202 // Initialise the Windows Socket services
\r
205 if (0 != ::WSAStartup(MAKEWORD(2,2), &wsaData))
\r
206 throw CWinException(_T("WSAStartup failed"));
\r
208 m_hWS2_32 = ::LoadLibrary(_T("WS2_32.dll"));
\r
209 if (0 == m_hWS2_32)
\r
210 throw CWinException(_T("Failed to load WS2_2.dll"));
\r
212 m_pfnGetAddrInfo = (GETADDRINFO*) GetProcAddress(m_hWS2_32, "getaddrinfo");
\r
213 m_pfnFreeAddrInfo = (FREEADDRINFO*) GetProcAddress(m_hWS2_32, "freeaddrinfo");
\r
215 m_StopRequest = ::CreateEvent(0, TRUE, FALSE, 0);
\r
216 m_Stopped = ::CreateEvent(0, TRUE, FALSE, 0);
\r
219 inline CSocket::~CSocket()
\r
224 ::CloseHandle(m_StopRequest);
\r
225 ::CloseHandle(m_Stopped);
\r
227 // Terminate the Windows Socket services
\r
230 ::FreeLibrary(m_hWS2_32);
\r
233 inline void CSocket::Accept(CSocket& rClientSock, struct sockaddr* addr, int* addrlen)
\r
235 // The accept function permits an incoming connection attempt on the socket.
\r
237 rClientSock.m_Socket = ::accept(m_Socket, addr, addrlen);
\r
238 if (INVALID_SOCKET == rClientSock.GetSocket())
\r
239 TRACE(_T("Accept failed\n"));
\r
242 inline int CSocket::Bind(LPCTSTR addr, LPCTSTR port)
\r
243 // The bind function associates a local address with the socket.
\r
247 if (IsIPV6Supported())
\r
250 #ifdef GetAddrInfo // Skip the following code block for older development environments
\r
252 ADDRINFO Hints= {0};
\r
253 Hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
\r
254 ADDRINFO *AddrInfo;
\r
256 RetVal = GetAddrInfo(addr, port, &Hints, &AddrInfo);
\r
259 TRACE( _T("GetAddrInfo failed\n"));
\r
263 // Bind the IP address to the listening socket
\r
264 RetVal = ::bind( m_Socket, AddrInfo->ai_addr, (int)AddrInfo->ai_addrlen );
\r
265 if ( RetVal == SOCKET_ERROR )
\r
267 TRACE(_T("Bind failed\n"));
\r
271 // Free the address information allocated by GetAddrInfo
\r
272 FreeAddrInfo(AddrInfo);
\r
279 sockaddr_in clientService;
\r
280 clientService.sin_family = AF_INET;
\r
281 clientService.sin_addr.s_addr = inet_addr( T2A(addr) );
\r
283 nPort = atoi( T2A(port) );
\r
286 TRACE(_T("Invalid port number\n"));
\r
287 return SOCKET_ERROR;
\r
289 clientService.sin_port = htons( (u_short)nPort );
\r
291 RetVal = ::bind( m_Socket, (SOCKADDR*) &clientService, sizeof(clientService) );
\r
293 TRACE(_T("Bind failed\n"));
\r
299 inline int CSocket::Bind(const struct sockaddr* name, int namelen)
\r
301 // The bind function associates a local address with the socket.
\r
303 int Result = ::bind (m_Socket, name, namelen);
\r
305 TRACE(_T("Bind failed\n"));
\r
309 inline int CSocket::Connect(LPCTSTR addr, LPCTSTR port)
\r
310 // The Connect function establishes a connection to the socket.
\r
314 if (IsIPV6Supported())
\r
317 #ifdef GetAddrInfo // Skip the following code block for older development environments
\r
319 ADDRINFO Hints= {0};
\r
320 Hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
\r
321 ADDRINFO *AddrInfo;
\r
323 RetVal = GetAddrInfo(addr, port, &Hints, &AddrInfo);
\r
326 TRACE( _T("getaddrinfo failed\n"));
\r
327 return SOCKET_ERROR;
\r
330 // Bind the IP address to the listening socket
\r
331 RetVal = Connect( AddrInfo->ai_addr, (int)AddrInfo->ai_addrlen );
\r
332 if ( RetVal == SOCKET_ERROR )
\r
334 TRACE(_T("Connect failed\n"));
\r
338 // Free the address information allocatied by GetAddrInfo
\r
339 FreeAddrInfo(AddrInfo);
\r
346 sockaddr_in clientService;
\r
347 clientService.sin_family = AF_INET;
\r
348 clientService.sin_addr.s_addr = inet_addr( T2A(addr) );
\r
350 nPort = atoi( T2A(port) );
\r
353 TRACE(_T("Invalid port number\n"));
\r
354 return SOCKET_ERROR;
\r
356 clientService.sin_port = htons( (u_short)nPort );
\r
358 RetVal = ::connect( m_Socket, (SOCKADDR*) &clientService, sizeof(clientService) );
\r
360 TRACE(_T("Connect failed\n"));
\r
366 inline int CSocket::Connect(const struct sockaddr* name, int namelen)
\r
368 // The Connect function establishes a connection to the socket.
\r
370 int Result = ::connect( m_Socket, name, namelen );
\r
372 TRACE(_T("Connect failed\n"));
\r
377 inline bool CSocket::Create( int family, int type, int protocol /*= IPPROTO_IP*/)
\r
379 // Creates the socket
\r
382 // family: AF_INET or AF_INET6
\r
383 // type: SOCK_DGRAM, SOCK_SEQPACKET, SOCK_STREAM, SOCK_RAW
\r
384 // protocol: IPPROTO_IP, IPPROTO_TCP, IPPROTO_UDP, IPPROTO_RAW, IPPROTO_ICMP, IPPROTO_ICMPV6
\r
386 m_Socket = socket(family, type, protocol);
\r
387 if(m_Socket == INVALID_SOCKET)
\r
389 TRACE(_T("Failed to create socket\n"));
\r
396 inline void CSocket::Disconnect()
\r
398 ::shutdown(m_Socket, SD_BOTH);
\r
400 ::closesocket(m_Socket);
\r
401 m_Socket = INVALID_SOCKET;
\r
404 inline UINT WINAPI CSocket::EventThread(LPVOID thread_data)
\r
406 // These are the possible network event notifications:
\r
407 // FD_READ Notification of readiness for reading.
\r
408 // FD_WRITE Motification of readiness for writing.
\r
409 // FD_OOB Notification of the arrival of Out Of Band data.
\r
410 // FD_ACCEPT Notification of incoming connections.
\r
411 // FD_CONNECT Notification of completed connection or multipoint join operation.
\r
412 // FD_CLOSE Notification of socket closure.
\r
413 // FD_QOS Notification of socket Quality Of Service changes
\r
414 // FD_ROUTING_INTERFACE_CHANGE Notification of routing interface changes for the specified destination.
\r
415 // FD_ADDRESS_LIST_CHANGE Notification of local address list changes for the address family of the socket.
\r
417 WSANETWORKEVENTS NetworkEvents;
\r
418 CSocket* pSocket = (CSocket*)thread_data;
\r
419 SOCKET sClient = pSocket->m_Socket;
\r
421 WSAEVENT AllEvents[2];
\r
422 AllEvents[0] = ::WSACreateEvent();
\r
423 AllEvents[1] = (WSAEVENT)pSocket->m_StopRequest;
\r
424 long Events = FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE |
\r
425 FD_QOS | FD_ROUTING_INTERFACE_CHANGE | FD_ADDRESS_LIST_CHANGE;
\r
427 // Associate the network event object (hNetworkEvents) with the
\r
428 // specified network events (Events) on socket sClient.
\r
429 if( SOCKET_ERROR == WSAEventSelect(sClient, AllEvents[0], Events))
\r
431 TRACE(_T("Error in Event Select\n"));
\r
432 ::SetEvent(pSocket->m_Stopped);
\r
433 ::WSACloseEvent(AllEvents[0]);
\r
437 // loop until the stop event is set
\r
438 for (;;) // infinite loop
\r
440 // Wait 100 ms for a network event
\r
441 DWORD dwResult = ::WSAWaitForMultipleEvents(2, AllEvents, FALSE, THREAD_TIMEOUT, FALSE);
\r
443 // Check event for stop thread
\r
444 if(::WaitForSingleObject(pSocket->m_StopRequest, 0) == WAIT_OBJECT_0)
\r
446 ::WSACloseEvent(AllEvents[0]);
\r
447 ::SetEvent(pSocket->m_Stopped);
\r
451 if (WSA_WAIT_FAILED == dwResult)
\r
453 TRACE(_T("WSAWaitForMultipleEvents failed\n"));
\r
454 ::WSACloseEvent(AllEvents[0]);
\r
455 ::SetEvent(pSocket->m_Stopped);
\r
459 // Proceed if a network event occurred
\r
460 if (WSA_WAIT_TIMEOUT != dwResult)
\r
463 if ( SOCKET_ERROR == ::WSAEnumNetworkEvents(sClient, AllEvents[0], &NetworkEvents) )
\r
465 TRACE(_T("WSAEnumNetworkEvents failed\n"));
\r
466 ::WSACloseEvent(AllEvents[0]);
\r
467 ::SetEvent(pSocket->m_Stopped);
\r
471 if (NetworkEvents.lNetworkEvents & FD_ACCEPT)
\r
472 pSocket->OnAccept();
\r
474 if (NetworkEvents.lNetworkEvents & FD_READ)
\r
475 pSocket->OnReceive();
\r
477 if (NetworkEvents.lNetworkEvents & FD_WRITE)
\r
480 if (NetworkEvents.lNetworkEvents & FD_OOB)
\r
481 pSocket->OnOutOfBand();
\r
483 if (NetworkEvents.lNetworkEvents & FD_QOS)
\r
484 pSocket->OnQualityOfService();
\r
486 if (NetworkEvents.lNetworkEvents & FD_CONNECT)
\r
487 pSocket->OnConnect();
\r
489 if (NetworkEvents.lNetworkEvents & FD_ROUTING_INTERFACE_CHANGE)
\r
490 pSocket->OnRoutingChange();
\r
492 if (NetworkEvents.lNetworkEvents & FD_ADDRESS_LIST_CHANGE)
\r
493 pSocket->OnAddresListChange();
\r
495 if (NetworkEvents.lNetworkEvents & FD_CLOSE)
\r
497 ::shutdown(sClient, SD_BOTH);
\r
498 ::closesocket(sClient);
\r
499 pSocket->OnDisconnect();
\r
500 ::WSACloseEvent(AllEvents[0]);
\r
501 ::SetEvent(pSocket->m_Stopped);
\r
508 inline int CSocket::GetAddrInfo( LPCTSTR nodename, LPCTSTR servname, const struct addrinfo* hints, struct addrinfo** res)
\r
513 std::string sNodeName = T2A(nodename);
\r
514 std::string sServName = T2A(servname);
\r
515 return (*m_pfnGetAddrInfo)(sNodeName.c_str(), sServName.c_str(), hints, res);
\r
519 UNREFERENCED_PARAMETER(nodename);
\r
520 UNREFERENCED_PARAMETER(servname);
\r
521 UNREFERENCED_PARAMETER(hints);
\r
522 UNREFERENCED_PARAMETER(res);
\r
524 throw CWinException(_T("getaddrinfo is not supported"));
\r
530 inline LPCTSTR CSocket::GetLastError()
\r
532 // Retrieves the most recent network error.
\r
534 int ErrorCode = WSAGetLastError();
\r
535 LPTSTR Message = NULL;
\r
536 m_ErrorMessage = _T("");
\r
538 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
\r
539 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_MAX_WIDTH_MASK,
\r
540 NULL, ErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
\r
541 (LPTSTR)&Message, 1024, NULL);
\r
545 m_ErrorMessage = Message;
\r
546 ::LocalFree(Message);
\r
549 return m_ErrorMessage;
\r
552 inline int CSocket::GetPeerName(struct sockaddr* name, int* namelen)
\r
554 int Result = ::getpeername(m_Socket, name, namelen);
\r
556 TRACE(_T("GetPeerName failed\n"));
\r
561 inline int CSocket::GetSockName(struct sockaddr* name, int* namelen)
\r
563 int Result = ::getsockname(m_Socket, name, namelen);
\r
565 TRACE(_T("GetSockName Failed\n"));
\r
570 inline int CSocket::GetSockOpt(int level, int optname, char* optval, int* optlen)
\r
572 int Result = ::getsockopt(m_Socket, level, optname, optval, optlen);
\r
574 TRACE(_T("GetSockOpt Failed\n"));
\r
579 inline void CSocket::FreeAddrInfo( struct addrinfo* ai )
\r
584 (*m_pfnFreeAddrInfo)(ai);
\r
588 UNREFERENCED_PARAMETER(ai);
\r
590 throw CWinException(_T("getaddrinfo is not supported"));
\r
596 inline int CSocket::ioCtlSocket(long cmd, u_long* argp)
\r
598 int Result = ::ioctlsocket(m_Socket, cmd, argp);
\r
600 TRACE(_T("ioCtlSocket Failed\n"));
\r
605 inline bool CSocket::IsIPV6Supported()
\r
607 bool IsIPV6Supported = FALSE;
\r
611 if (m_pfnGetAddrInfo != 0 && m_pfnFreeAddrInfo != 0)
\r
612 IsIPV6Supported = TRUE;
\r
616 return IsIPV6Supported;
\r
619 inline int CSocket::Listen(int backlog /*= SOMAXCONN*/)
\r
621 int Result = ::listen(m_Socket, backlog);
\r
623 TRACE(_T("Listen Failed\n"));
\r
628 inline int CSocket::Receive(TCHAR* buf, int len, int flags)
\r
630 std::vector<char> vChar(len+1, '\0');
\r
631 char* pCharArray = &vChar.front();
\r
632 int Result = ::recv(m_Socket, pCharArray, len, flags);
\r
633 if (SOCKET_ERROR == Result)
\r
634 TRACE(_T("Receive failed\n"));
\r
636 lstrcpyn(buf, A2T(pCharArray), len);
\r
641 inline int CSocket::ReceiveFrom(TCHAR* buf, int len, int flags, struct sockaddr* from, int* fromlen)
\r
642 //The ReceiveFrom function receives a datagram and stores the source address.
\r
644 std::vector<char> vChar(len+1, '\0');
\r
645 char* pCharArray = &vChar.front();
\r
646 int Result = ::recvfrom(m_Socket, pCharArray, len, flags, from, fromlen);
\r
647 if (SOCKET_ERROR == Result)
\r
648 TRACE(_T("ReceiveFrom failed\n"));
\r
650 lstrcpyn(buf, A2T(pCharArray), len);
\r
655 inline int CSocket::Send(LPCTSTR buf, int len, int flags)
\r
657 int Result = ::send(m_Socket, T2A(buf), len, flags);
\r
658 if (SOCKET_ERROR == Result)
\r
659 TRACE(_T("Send failed\n"));
\r
664 inline int CSocket::SendTo(LPCTSTR send, int len, int flags, LPCTSTR addr, LPCTSTR port)
\r
665 // The sendto function sends data to a specific destination.
\r
669 if (IsIPV6Supported())
\r
672 #ifdef GetAddrInfo // Skip the following code block for older development environments
\r
674 ADDRINFO Hints= {0};
\r
675 Hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
\r
676 ADDRINFO *AddrInfo;
\r
678 RetVal = GetAddrInfo(addr, port, &Hints, &AddrInfo);
\r
681 TRACE( _T("GetAddrInfo failed\n"));
\r
682 return SOCKET_ERROR;
\r
685 RetVal = ::sendto(m_Socket, T2A(send), len, flags, AddrInfo->ai_addr, (int)AddrInfo->ai_addrlen );
\r
686 if ( RetVal == SOCKET_ERROR )
\r
688 TRACE(_T("SendTo failed\n"));
\r
692 // Free the address information allocatied by GetAddrInfo
\r
693 FreeAddrInfo(AddrInfo);
\r
700 sockaddr_in clientService;
\r
701 clientService.sin_family = AF_INET;
\r
702 clientService.sin_addr.s_addr = inet_addr( T2A(addr) );
\r
704 nPort = atoi( T2A(port));
\r
707 TRACE(_T("Invalid port number\n"));
\r
708 return SOCKET_ERROR;
\r
710 clientService.sin_port = htons( (u_short)nPort );
\r
712 RetVal = ::sendto( m_Socket, T2A(send), len, flags, (SOCKADDR*) &clientService, sizeof(clientService) );
\r
713 if ( SOCKET_ERROR != RetVal )
\r
714 TRACE(_T("SendTo failed\n"));
\r
720 inline int CSocket::SendTo(LPCTSTR buf, int len, int flags, const struct sockaddr* to, int tolen)
\r
721 // The sendto function sends data to a specific destination.
\r
723 int Result = ::sendto(m_Socket, T2A(buf), len, flags, to, tolen);
\r
724 if (SOCKET_ERROR == Result)
\r
725 TRACE(_T("SendTo failed\n"));
\r
730 inline int CSocket::SetSockOpt(int level, int optname, const char* optval, int optlen)
\r
732 int Result = ::setsockopt(m_Socket, level, optname, optval, optlen);
\r
734 TRACE(_T("SetSockOpt failed\n"));
\r
739 inline void CSocket::StartEvents()
\r
741 // This function starts the thread which monitors the socket for events.
\r
742 StopEvents(); // Ensure the thread isn't already running
\r
743 UINT ThreadID; // a return variable required for Win95, Win98, WinME
\r
744 m_hEventThread = (HANDLE)::_beginthreadex(NULL, 0, CSocket::EventThread, (LPVOID) this, 0, &ThreadID);
\r
747 inline void CSocket::StopEvents()
\r
749 // Terminates the event thread gracefully (if possible)
\r
750 if (m_hEventThread)
\r
752 ::SetThreadPriority(m_hEventThread, THREAD_PRIORITY_HIGHEST);
\r
753 ::SetEvent(m_StopRequest);
\r
755 for (;;) // infinite loop
\r
757 // wait for the Thread stopping event to be set
\r
758 if ( WAIT_TIMEOUT == ::WaitForSingleObject(m_Stopped, THREAD_TIMEOUT * 10) )
\r
760 // Note: An excessive delay in processing any of the notification functions
\r
761 // can cause us to get here. (Yes one second is an excessive delay. Its a bug!)
\r
762 TRACE(_T("*** Error: Event Thread won't die ***\n") );
\r
767 ::CloseHandle(m_hEventThread);
\r
768 m_hEventThread = 0;
\r
771 ::ResetEvent(m_StopRequest);
\r
772 ::ResetEvent(m_Stopped);
\r
777 #endif // #ifndef _WIN32XX_SOCKET_H_
\r