e7e1b89e74cdde87a83b854e4c7432f2f6272fa2
[matches/honours.git] / research / transmission_spectroscopy / TOF / Win32++ / include / socket.h
1 // Win32++   Version 7.3\r
2 // Released: 30th November 2011\r
3 //\r
4 //      David Nash\r
5 //      email: [email protected]\r
6 //      url: https://sourceforge.net/projects/win32-framework\r
7 //\r
8 //\r
9 // Copyright (c) 2005-2011  David Nash\r
10 //\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
20 //\r
21 // The above copyright notice and this permission notice\r
22 // shall be included in all copies or substantial portions\r
23 // of the Software.\r
24 //\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
34 //\r
35 ////////////////////////////////////////////////////////\r
36 \r
37 \r
38 ////////////////////////////////////////////////////////\r
39 // socket.h\r
40 //  Declaration of the CSocket class\r
41 //\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
49 \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
57 \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
60 \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
65 \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
78 \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
85 \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
95 \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
105 //\r
106 \r
107 #ifndef _WIN32XX_SOCKET_H_\r
108 #define _WIN32XX_SOCKET_H_\r
109 \r
110 \r
111 #include "wincore.h"\r
112 #include <winsock2.h>\r
113 #include <ws2tcpip.h>\r
114 #include <process.h>\r
115 \r
116 \r
117 #define THREAD_TIMEOUT 100\r
118 \r
119 \r
120 namespace Win32xx\r
121 {\r
122 \r
123         typedef int  WINAPI GETADDRINFO(LPCSTR, LPCSTR, const struct addrinfo*, struct addrinfo**);\r
124         typedef void WINAPI FREEADDRINFO(struct addrinfo*);\r
125 \r
126         class CSocket\r
127         {\r
128         public:\r
129                 CSocket();\r
130                 virtual ~CSocket();\r
131 \r
132                 // Operations\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
151 \r
152                 virtual void StartEvents();\r
153                 virtual void StopEvents();\r
154 \r
155                 // Attributes\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
161 \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
172 \r
173 \r
174 \r
175                 // Allow CSocket to be used as a SOCKET\r
176                 operator SOCKET() const {return m_Socket;}\r
177 \r
178         private:\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
182 \r
183                 CString m_ErrorMessage;\r
184                 SOCKET m_Socket;\r
185                 HMODULE m_hWS2_32;\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
189 \r
190                 GETADDRINFO* m_pfnGetAddrInfo;          // pointer for the GetAddrInfo function\r
191                 FREEADDRINFO* m_pfnFreeAddrInfo;        // pointer for the FreeAddrInfo function\r
192         };\r
193 }\r
194 \r
195 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
196 \r
197 namespace Win32xx\r
198 {\r
199 \r
200         inline CSocket::CSocket() : m_Socket(INVALID_SOCKET), m_hEventThread(0)\r
201         {\r
202                 // Initialise the Windows Socket services\r
203                 WSADATA wsaData;\r
204 \r
205                 if (0 != ::WSAStartup(MAKEWORD(2,2), &wsaData))\r
206                         throw CWinException(_T("WSAStartup failed"));\r
207 \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
211 \r
212                 m_pfnGetAddrInfo = (GETADDRINFO*) GetProcAddress(m_hWS2_32, "getaddrinfo");\r
213                 m_pfnFreeAddrInfo = (FREEADDRINFO*) GetProcAddress(m_hWS2_32, "freeaddrinfo");\r
214 \r
215                 m_StopRequest = ::CreateEvent(0, TRUE, FALSE, 0);\r
216                 m_Stopped = ::CreateEvent(0, TRUE, FALSE, 0);\r
217         }\r
218 \r
219         inline CSocket::~CSocket()\r
220         {\r
221                 Disconnect();\r
222 \r
223                 // Close handles\r
224                 ::CloseHandle(m_StopRequest);\r
225                 ::CloseHandle(m_Stopped);\r
226 \r
227                 // Terminate the  Windows Socket services\r
228                 ::WSACleanup();\r
229 \r
230                 ::FreeLibrary(m_hWS2_32);\r
231         }\r
232 \r
233         inline void CSocket::Accept(CSocket& rClientSock, struct sockaddr* addr, int* addrlen)\r
234         {\r
235                 // The accept function permits an incoming connection attempt on the socket.\r
236 \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
240         }\r
241 \r
242         inline int CSocket::Bind(LPCTSTR addr, LPCTSTR port)\r
243         // The bind function associates a local address with the socket.\r
244         {\r
245                 int RetVal = 0;\r
246 \r
247                 if (IsIPV6Supported())\r
248                 {\r
249 \r
250 #ifdef GetAddrInfo      // Skip the following code block for older development environments\r
251 \r
252                         ADDRINFO Hints= {0};\r
253                         Hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;\r
254                         ADDRINFO *AddrInfo;\r
255 \r
256                         RetVal = GetAddrInfo(addr, port, &Hints, &AddrInfo);\r
257                         if (RetVal != 0)\r
258                         {\r
259                                 TRACE( _T("GetAddrInfo failed\n"));\r
260                                 return RetVal;\r
261                         }\r
262 \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
266                         {\r
267                                 TRACE(_T("Bind failed\n"));\r
268                                 return RetVal;\r
269                         }\r
270 \r
271                         // Free the address information allocated by GetAddrInfo\r
272                         FreeAddrInfo(AddrInfo);\r
273 \r
274 #endif\r
275 \r
276                 }\r
277                 else\r
278                 {\r
279                         sockaddr_in clientService;\r
280                         clientService.sin_family = AF_INET;\r
281                         clientService.sin_addr.s_addr = inet_addr( T2A(addr) );\r
282                         int nPort = -1;\r
283             nPort = atoi( T2A(port) );\r
284                         if (-1 == nPort)\r
285                         {\r
286                                 TRACE(_T("Invalid port number\n"));\r
287                                 return SOCKET_ERROR;\r
288                         }\r
289                         clientService.sin_port = htons( (u_short)nPort );\r
290 \r
291                         RetVal = ::bind( m_Socket, (SOCKADDR*) &clientService, sizeof(clientService) );\r
292                         if ( 0 != RetVal )\r
293                                 TRACE(_T("Bind failed\n"));\r
294                 }\r
295 \r
296                 return RetVal;\r
297         }\r
298 \r
299         inline int CSocket::Bind(const struct sockaddr* name, int namelen)\r
300         {\r
301                 // The bind function associates a local address with the socket.\r
302 \r
303                 int Result = ::bind (m_Socket, name, namelen);\r
304                 if ( 0 != Result )\r
305                         TRACE(_T("Bind failed\n"));\r
306                 return Result;\r
307         }\r
308 \r
309         inline int CSocket::Connect(LPCTSTR addr, LPCTSTR port)\r
310         // The Connect function establishes a connection to the socket.\r
311         {\r
312                 int RetVal = 0;\r
313 \r
314                 if (IsIPV6Supported())\r
315                 {\r
316 \r
317 #ifdef GetAddrInfo      // Skip the following code block for older development environments\r
318 \r
319                         ADDRINFO Hints= {0};\r
320                         Hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;\r
321                         ADDRINFO *AddrInfo;\r
322 \r
323                         RetVal = GetAddrInfo(addr, port, &Hints, &AddrInfo);\r
324                         if (RetVal != 0)\r
325                         {\r
326                                 TRACE( _T("getaddrinfo failed\n"));\r
327                                 return SOCKET_ERROR;\r
328                         }\r
329 \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
333                         {\r
334                                 TRACE(_T("Connect failed\n"));\r
335                                 return RetVal;\r
336                         }\r
337 \r
338                         // Free the address information allocatied by GetAddrInfo\r
339                         FreeAddrInfo(AddrInfo);\r
340 \r
341 #endif\r
342 \r
343                 }\r
344                 else\r
345                 {\r
346                         sockaddr_in clientService;\r
347                         clientService.sin_family = AF_INET;\r
348                         clientService.sin_addr.s_addr = inet_addr( T2A(addr) );\r
349                         int nPort = -1;\r
350                         nPort = atoi( T2A(port) );\r
351                         if (-1 == nPort)\r
352                         {\r
353                                 TRACE(_T("Invalid port number\n"));\r
354                                 return SOCKET_ERROR;\r
355                         }\r
356                         clientService.sin_port = htons( (u_short)nPort );\r
357 \r
358                         RetVal = ::connect( m_Socket, (SOCKADDR*) &clientService, sizeof(clientService) );\r
359                         if ( 0 != RetVal )\r
360                                 TRACE(_T("Connect failed\n"));\r
361                 }\r
362 \r
363                 return RetVal;\r
364         }\r
365 \r
366         inline int CSocket::Connect(const struct sockaddr* name, int namelen)\r
367         {\r
368                 // The Connect function establishes a connection to the socket.\r
369 \r
370                 int Result = ::connect( m_Socket, name, namelen );\r
371                 if ( 0 != Result )\r
372                         TRACE(_T("Connect failed\n"));\r
373 \r
374                 return Result;\r
375         }\r
376 \r
377         inline bool CSocket::Create( int family, int type, int protocol /*= IPPROTO_IP*/)\r
378         {\r
379                 // Creates the socket\r
380 \r
381                 // Valid values:\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
385 \r
386                 m_Socket = socket(family, type, protocol);\r
387                 if(m_Socket == INVALID_SOCKET)\r
388                 {\r
389                         TRACE(_T("Failed to create socket\n"));\r
390                         return FALSE;\r
391                 }\r
392 \r
393                 return TRUE;\r
394         }\r
395 \r
396         inline void CSocket::Disconnect()\r
397         {\r
398                 ::shutdown(m_Socket, SD_BOTH);\r
399                 StopEvents();\r
400                 ::closesocket(m_Socket);\r
401                 m_Socket = INVALID_SOCKET;\r
402         }\r
403 \r
404         inline UINT WINAPI CSocket::EventThread(LPVOID thread_data)\r
405         {\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
416 \r
417                 WSANETWORKEVENTS NetworkEvents;\r
418                 CSocket* pSocket = (CSocket*)thread_data;\r
419                 SOCKET sClient = pSocket->m_Socket;\r
420 \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
426 \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
430                 {\r
431                         TRACE(_T("Error in Event Select\n"));\r
432                         ::SetEvent(pSocket->m_Stopped);\r
433                         ::WSACloseEvent(AllEvents[0]);\r
434                         return 0;\r
435                 }\r
436 \r
437                 // loop until the stop event is set\r
438                 for (;;) // infinite loop\r
439                 {\r
440                         // Wait 100 ms for a network event\r
441                         DWORD dwResult = ::WSAWaitForMultipleEvents(2, AllEvents, FALSE, THREAD_TIMEOUT, FALSE);\r
442 \r
443                         // Check event for stop thread\r
444                         if(::WaitForSingleObject(pSocket->m_StopRequest, 0) == WAIT_OBJECT_0)\r
445                         {\r
446                                 ::WSACloseEvent(AllEvents[0]);\r
447                                 ::SetEvent(pSocket->m_Stopped);\r
448                                 return 0;\r
449                         }\r
450 \r
451                         if (WSA_WAIT_FAILED == dwResult)\r
452                         {\r
453                                 TRACE(_T("WSAWaitForMultipleEvents failed\n"));\r
454                                 ::WSACloseEvent(AllEvents[0]);\r
455                                 ::SetEvent(pSocket->m_Stopped);\r
456                                 return 0;\r
457                         }\r
458 \r
459                         // Proceed if a network event occurred\r
460                         if (WSA_WAIT_TIMEOUT != dwResult)\r
461                         {\r
462 \r
463                                 if ( SOCKET_ERROR == ::WSAEnumNetworkEvents(sClient, AllEvents[0], &NetworkEvents) )\r
464                                 {\r
465                                         TRACE(_T("WSAEnumNetworkEvents failed\n"));\r
466                                         ::WSACloseEvent(AllEvents[0]);\r
467                                         ::SetEvent(pSocket->m_Stopped);\r
468                                         return 0;\r
469                                 }\r
470 \r
471                                 if (NetworkEvents.lNetworkEvents & FD_ACCEPT)\r
472                                         pSocket->OnAccept();\r
473 \r
474                                 if (NetworkEvents.lNetworkEvents & FD_READ)\r
475                                         pSocket->OnReceive();\r
476 \r
477                                 if (NetworkEvents.lNetworkEvents & FD_WRITE)\r
478                                         pSocket->OnSend();\r
479 \r
480                                 if (NetworkEvents.lNetworkEvents & FD_OOB)\r
481                                         pSocket->OnOutOfBand();\r
482 \r
483                                 if (NetworkEvents.lNetworkEvents & FD_QOS)\r
484                                         pSocket->OnQualityOfService();\r
485 \r
486                                 if (NetworkEvents.lNetworkEvents & FD_CONNECT)\r
487                                         pSocket->OnConnect();\r
488 \r
489                                 if (NetworkEvents.lNetworkEvents & FD_ROUTING_INTERFACE_CHANGE)\r
490                                         pSocket->OnRoutingChange();\r
491 \r
492                                 if (NetworkEvents.lNetworkEvents & FD_ADDRESS_LIST_CHANGE)\r
493                                         pSocket->OnAddresListChange();\r
494 \r
495                                 if (NetworkEvents.lNetworkEvents & FD_CLOSE)\r
496                                 {\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
502                                         return 0;\r
503                                 }\r
504                         }\r
505                 }\r
506         }\r
507 \r
508         inline int CSocket::GetAddrInfo( LPCTSTR nodename, LPCTSTR servname, const struct addrinfo* hints, struct addrinfo** res)\r
509         {\r
510 \r
511 #ifdef GetAddrInfo\r
512 \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
516 \r
517 #else\r
518 \r
519                 UNREFERENCED_PARAMETER(nodename);\r
520                 UNREFERENCED_PARAMETER(servname);\r
521                 UNREFERENCED_PARAMETER(hints);\r
522                 UNREFERENCED_PARAMETER(res);\r
523 \r
524                 throw CWinException(_T("getaddrinfo is not supported"));\r
525 \r
526 #endif\r
527 \r
528         }\r
529 \r
530         inline LPCTSTR CSocket::GetLastError()\r
531         {\r
532                 // Retrieves the most recent network error.\r
533 \r
534                 int ErrorCode = WSAGetLastError();\r
535                 LPTSTR Message = NULL;\r
536                 m_ErrorMessage = _T("");\r
537 \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
542 \r
543                 if (Message)\r
544                 {\r
545                         m_ErrorMessage = Message;\r
546                         ::LocalFree(Message);\r
547                 }\r
548 \r
549                 return m_ErrorMessage;\r
550         }\r
551 \r
552         inline int  CSocket::GetPeerName(struct sockaddr* name, int* namelen)\r
553         {\r
554                 int Result = ::getpeername(m_Socket, name, namelen);\r
555                 if (0 != Result)\r
556                         TRACE(_T("GetPeerName failed\n"));\r
557 \r
558                 return Result;\r
559         }\r
560 \r
561         inline int  CSocket::GetSockName(struct sockaddr* name, int* namelen)\r
562         {\r
563                 int Result = ::getsockname(m_Socket, name, namelen);\r
564                 if (0 != Result)\r
565                         TRACE(_T("GetSockName Failed\n"));\r
566 \r
567                 return Result;\r
568         }\r
569 \r
570         inline int  CSocket::GetSockOpt(int level, int optname, char* optval, int* optlen)\r
571         {\r
572                 int Result = ::getsockopt(m_Socket, level, optname, optval, optlen);\r
573                 if (0 != Result)\r
574                         TRACE(_T("GetSockOpt Failed\n"));\r
575 \r
576                 return Result;\r
577         }\r
578 \r
579         inline void CSocket::FreeAddrInfo( struct addrinfo* ai )\r
580         {\r
581 \r
582 #ifdef GetAddrInfo\r
583 \r
584                 (*m_pfnFreeAddrInfo)(ai);\r
585 \r
586 #else\r
587 \r
588                 UNREFERENCED_PARAMETER(ai);\r
589 \r
590                 throw CWinException(_T("getaddrinfo is not supported"));\r
591 \r
592 #endif\r
593 \r
594         }\r
595 \r
596         inline int CSocket::ioCtlSocket(long cmd, u_long* argp)\r
597         {\r
598                 int Result = ::ioctlsocket(m_Socket, cmd, argp);\r
599                 if (0 != Result)\r
600                         TRACE(_T("ioCtlSocket Failed\n"));\r
601 \r
602                 return Result;\r
603         }\r
604 \r
605         inline bool CSocket::IsIPV6Supported()\r
606         {\r
607                 bool IsIPV6Supported = FALSE;\r
608 \r
609 #ifdef GetAddrInfo\r
610 \r
611                 if (m_pfnGetAddrInfo != 0 && m_pfnFreeAddrInfo != 0)\r
612                         IsIPV6Supported = TRUE;\r
613 \r
614 #endif\r
615 \r
616                 return IsIPV6Supported;\r
617         }\r
618 \r
619         inline int CSocket::Listen(int backlog /*= SOMAXCONN*/)\r
620         {\r
621                 int Result = ::listen(m_Socket, backlog);\r
622                 if (0 != Result)\r
623                         TRACE(_T("Listen Failed\n"));\r
624 \r
625                 return Result;\r
626         }\r
627 \r
628         inline int CSocket::Receive(TCHAR* buf, int len, int flags)\r
629         {\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
635 \r
636                 lstrcpyn(buf, A2T(pCharArray), len);\r
637 \r
638                 return Result;\r
639         }\r
640 \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
643         {\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
649 \r
650                 lstrcpyn(buf, A2T(pCharArray), len);\r
651 \r
652                 return Result;\r
653         }\r
654 \r
655         inline int CSocket::Send(LPCTSTR buf, int len, int flags)\r
656         {\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
660 \r
661                 return Result;\r
662         }\r
663 \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
666         {\r
667                 int RetVal = 0;\r
668 \r
669                 if (IsIPV6Supported())\r
670                 {\r
671 \r
672 #ifdef GetAddrInfo      // Skip the following code block for older development environments\r
673 \r
674                         ADDRINFO Hints= {0};\r
675                         Hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;\r
676                         ADDRINFO *AddrInfo;\r
677 \r
678                         RetVal = GetAddrInfo(addr, port, &Hints, &AddrInfo);\r
679                         if (RetVal != 0)\r
680                         {\r
681                                 TRACE( _T("GetAddrInfo failed\n"));\r
682                                 return SOCKET_ERROR;\r
683                         }\r
684 \r
685                         RetVal = ::sendto(m_Socket, T2A(send), len, flags, AddrInfo->ai_addr, (int)AddrInfo->ai_addrlen );\r
686                         if ( RetVal == SOCKET_ERROR )\r
687                         {\r
688                                 TRACE(_T("SendTo failed\n"));\r
689                                 return RetVal;\r
690                         }\r
691 \r
692                         // Free the address information allocatied by GetAddrInfo\r
693                         FreeAddrInfo(AddrInfo);\r
694 \r
695 #endif\r
696 \r
697                 }\r
698                 else\r
699                 {\r
700                         sockaddr_in clientService;\r
701                         clientService.sin_family = AF_INET;\r
702                         clientService.sin_addr.s_addr = inet_addr( T2A(addr) );\r
703                         int nPort = -1;\r
704             nPort = atoi( T2A(port));\r
705                         if (-1 == nPort)\r
706                         {\r
707                                 TRACE(_T("Invalid port number\n"));\r
708                                 return SOCKET_ERROR;\r
709                         }\r
710                         clientService.sin_port = htons( (u_short)nPort );\r
711 \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
715                 }\r
716 \r
717                 return RetVal;\r
718         }\r
719 \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
722         {\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
726 \r
727                 return Result;\r
728         }\r
729 \r
730         inline int CSocket::SetSockOpt(int level, int optname, const char* optval, int optlen)\r
731         {\r
732                 int Result = ::setsockopt(m_Socket, level, optname, optval, optlen);\r
733                 if (0 != Result)\r
734                         TRACE(_T("SetSockOpt failed\n"));\r
735 \r
736                 return Result;\r
737         }\r
738 \r
739         inline void CSocket::StartEvents()\r
740         {\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
745         }\r
746 \r
747         inline void CSocket::StopEvents()\r
748         {\r
749                 // Terminates the event thread gracefully (if possible)\r
750                 if (m_hEventThread)\r
751                 {\r
752                         ::SetThreadPriority(m_hEventThread, THREAD_PRIORITY_HIGHEST);\r
753                         ::SetEvent(m_StopRequest);\r
754 \r
755                         for (;;)        // infinite loop\r
756                         {\r
757                                 // wait for the Thread stopping event to be set\r
758                                 if ( WAIT_TIMEOUT == ::WaitForSingleObject(m_Stopped, THREAD_TIMEOUT * 10) )\r
759                                 {\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
763                                 }\r
764                                 else break;\r
765                         }\r
766 \r
767                         ::CloseHandle(m_hEventThread);\r
768                         m_hEventThread = 0;\r
769                 }\r
770 \r
771                 ::ResetEvent(m_StopRequest);\r
772                 ::ResetEvent(m_Stopped);\r
773         }\r
774 }\r
775 \r
776 \r
777 #endif // #ifndef _WIN32XX_SOCKET_H_\r
778 \r

UCC git Repository :: git.ucc.asn.au