1 /////////////////////////////////////////////////////////////////////////////
2 // Name:       src/msw/sockmsw.cpp
3 // Purpose:    MSW-specific socket code
4 // Authors:    Guilhem Lavaux, Guillermo Rodriguez Garcia
5 // Created:    April 1997
6 // Copyright:  (C) 1999-1997, Guilhem Lavaux
7 //             (C) 1999-2000, Guillermo Rodriguez Garcia
8 //             (C) 2008 Vadim Zeitlin
9 // Licence:    wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11 
12 
13 // For compilers that support precompilation, includes "wx.h".
14 #include "wx/wxprec.h"
15 
16 #ifdef __BORLANDC__
17     #pragma hdrstop
18 #endif
19 
20 #if wxUSE_SOCKETS
21 
22 /* including rasasync.h (included from windows.h itself included from
23  * wx/setup.h and/or winsock.h results in this warning for
24  * RPCNOTIFICATION_ROUTINE
25  */
26 #ifdef _MSC_VER
27 #   pragma warning(disable:4115) /* named type definition in parentheses */
28 #endif
29 
30 #include "wx/private/socket.h"
31 #include "wx/msw/private.h"     // for wxGetInstance()
32 #include "wx/private/fd.h"
33 #include "wx/apptrait.h"
34 #include "wx/thread.h"
35 #include "wx/dynlib.h"
36 #include "wx/link.h"
37 
38 #ifdef __WXWINCE__
39 /*
40  * As WSAAsyncSelect is not present on WinCE, it now uses WSACreateEvent,
41  * WSAEventSelect, WSAWaitForMultipleEvents and WSAEnumNetworkEvents. When
42  * enabling eventhandling for a socket a new thread it created that keeps track
43  * of the events and posts a messageto the hidden window to use the standard
44  * message loop.
45  */
46 #include "wx/msw/wince/net.h"
47 #include "wx/hashmap.h"
48 WX_DECLARE_HASH_MAP(int,bool,wxIntegerHash,wxIntegerEqual,SocketHash);
49 
50 #ifndef isdigit
51 #define isdigit(x) (x > 47 && x < 58)
52 #endif
53 #include "wx/msw/wince/net.h"
54 
55 #endif // __WXWINCE__
56 
57 #ifdef _MSC_VER
58 #  pragma warning(default:4115) /* named type definition in parentheses */
59 #endif
60 
61 #include "wx/msw/private/hiddenwin.h"
62 
63 #define CLASSNAME  TEXT("_wxSocket_Internal_Window_Class")
64 
65 /* Maximum number of different wxSocket objects at a given time.
66  * This value can be modified at will, but it CANNOT be greater
67  * than (0x7FFF - WM_USER + 1)
68  */
69 #define MAXSOCKETS 1024
70 
71 #if (MAXSOCKETS > (0x7FFF - WM_USER + 1))
72 #error "MAXSOCKETS is too big!"
73 #endif
74 
75 #ifndef __WXWINCE__
76 typedef int (PASCAL *WSAAsyncSelect_t)(SOCKET,HWND,u_int,long);
77 #else
78 /* Typedef the needed function prototypes and the WSANETWORKEVENTS structure
79 */
80 typedef struct _WSANETWORKEVENTS {
81        long lNetworkEvents;
82        int iErrorCode[10];
83 } WSANETWORKEVENTS, FAR * LPWSANETWORKEVENTS;
84 typedef HANDLE (PASCAL *WSACreateEvent_t)();
85 typedef int (PASCAL *WSAEventSelect_t)(SOCKET,HANDLE,long);
86 typedef int (PASCAL *WSAWaitForMultipleEvents_t)(long,HANDLE,BOOL,long,BOOL);
87 typedef int (PASCAL *WSAEnumNetworkEvents_t)(SOCKET,HANDLE,LPWSANETWORKEVENTS);
88 #endif //__WXWINCE__
89 
90 LRESULT CALLBACK wxSocket_Internal_WinProc(HWND, UINT, WPARAM, LPARAM);
91 
92 /* Global variables */
93 
94 static HWND hWin;
95 wxCRIT_SECT_DECLARE_MEMBER(gs_critical);
96 static wxSocketImplMSW *socketList[MAXSOCKETS];
97 static int firstAvailable;
98 
99 #ifndef __WXWINCE__
100 static WSAAsyncSelect_t gs_WSAAsyncSelect = NULL;
101 #else
102 static SocketHash socketHash;
103 static unsigned int currSocket;
104 HANDLE hThread[MAXSOCKETS];
105 static WSACreateEvent_t gs_WSACreateEvent = NULL;
106 static WSAEventSelect_t gs_WSAEventSelect = NULL;
107 static WSAWaitForMultipleEvents_t gs_WSAWaitForMultipleEvents = NULL;
108 static WSAEnumNetworkEvents_t gs_WSAEnumNetworkEvents = NULL;
109 /* This structure will be used to pass data on to the thread that handles socket events.
110 */
111 typedef struct thread_data{
112     HWND hEvtWin;
113     unsigned long msgnumber;
114     unsigned long fd;
115     unsigned long lEvent;
116 }thread_data;
117 #endif
118 
119 #ifdef __WXWINCE__
120 /* This thread handles socket events on WinCE using WSAEventSelect() as
121  * WSAAsyncSelect is not supported. When an event occurs for the socket, it is
122  * checked what kind of event happened and the correct message gets posted so
123  * that the hidden window can handle it as it would in other MSW builds.
124 */
SocketThread(LPVOID data)125 DWORD WINAPI SocketThread(LPVOID data)
126 {
127     WSANETWORKEVENTS NetworkEvents;
128     thread_data* d = (thread_data *)data;
129 
130     HANDLE NetworkEvent = gs_WSACreateEvent();
131     gs_WSAEventSelect(d->fd, NetworkEvent, d->lEvent);
132 
133     while(socketHash[d->fd] == true)
134     {
135         if ((gs_WSAWaitForMultipleEvents(1, &NetworkEvent, FALSE,INFINITE, FALSE)) == WAIT_FAILED)
136         {
137             printf("WSAWaitForMultipleEvents failed with error %d\n", WSAGetLastError());
138             return 0;
139         }
140         if (gs_WSAEnumNetworkEvents(d->fd ,NetworkEvent, &NetworkEvents) == SOCKET_ERROR)
141         {
142             printf("WSAEnumNetworkEvents failed with error %d\n", WSAGetLastError());
143             return 0;
144         }
145 
146         long flags = NetworkEvents.lNetworkEvents;
147         if (flags & FD_READ)
148             ::PostMessage(d->hEvtWin, d->msgnumber,d->fd, FD_READ);
149         if (flags & FD_WRITE)
150             ::PostMessage(d->hEvtWin, d->msgnumber,d->fd, FD_WRITE);
151         if (flags & FD_OOB)
152             ::PostMessage(d->hEvtWin, d->msgnumber,d->fd, FD_OOB);
153         if (flags & FD_ACCEPT)
154             ::PostMessage(d->hEvtWin, d->msgnumber,d->fd, FD_ACCEPT);
155         if (flags & FD_CONNECT)
156             ::PostMessage(d->hEvtWin, d->msgnumber,d->fd, FD_CONNECT);
157         if (flags & FD_CLOSE)
158             ::PostMessage(d->hEvtWin, d->msgnumber,d->fd, FD_CLOSE);
159 
160     }
161     gs_WSAEventSelect(d->fd, NetworkEvent, 0);
162     ExitThread(0);
163     return 0;
164 }
165 #endif
166 
167 // ----------------------------------------------------------------------------
168 // MSW implementation of wxSocketManager
169 // ----------------------------------------------------------------------------
170 
171 class wxSocketMSWManager : public wxSocketManager
172 {
173 public:
174     virtual bool OnInit();
175     virtual void OnExit();
176 
CreateSocket(wxSocketBase & wxsocket)177     virtual wxSocketImpl *CreateSocket(wxSocketBase& wxsocket)
178     {
179         return new wxSocketImplMSW(wxsocket);
180     }
181     virtual void Install_Callback(wxSocketImpl *socket,
182                                   wxSocketNotify event = wxSOCKET_LOST);
183     virtual void Uninstall_Callback(wxSocketImpl *socket,
184                                     wxSocketNotify event = wxSOCKET_LOST);
185 
186 private:
187     static wxDynamicLibrary gs_wsock32dll;
188 };
189 
190 wxDynamicLibrary wxSocketMSWManager::gs_wsock32dll;
191 
OnInit()192 bool wxSocketMSWManager::OnInit()
193 {
194   LPCTSTR pclassname = NULL;
195   int i;
196 
197   /* Create internal window for event notifications */
198   hWin = wxCreateHiddenWindow(&pclassname, CLASSNAME, wxSocket_Internal_WinProc);
199   if (!hWin)
200       return false;
201 
202   /* Initialize socket list */
203   for (i = 0; i < MAXSOCKETS; i++)
204   {
205     socketList[i] = NULL;
206   }
207   firstAvailable = 0;
208 
209   // we don't link with wsock32.dll (or ws2 in CE case) statically to avoid
210   // dependencies on it for all the application using wx even if they don't use
211   // sockets
212 #ifdef __WXWINCE__
213     #define WINSOCK_DLL_NAME wxT("ws2.dll")
214 #else
215     #define WINSOCK_DLL_NAME wxT("wsock32.dll")
216 #endif
217 
218     gs_wsock32dll.Load(WINSOCK_DLL_NAME, wxDL_VERBATIM | wxDL_QUIET);
219     if ( !gs_wsock32dll.IsLoaded() )
220         return false;
221 
222 #ifndef __WXWINCE__
223     wxDL_INIT_FUNC(gs_, WSAAsyncSelect, gs_wsock32dll);
224     if ( !gs_WSAAsyncSelect )
225         return false;
226 #else
227     wxDL_INIT_FUNC(gs_, WSAEventSelect, gs_wsock32dll);
228     if ( !gs_WSAEventSelect )
229         return false;
230 
231     wxDL_INIT_FUNC(gs_, WSACreateEvent, gs_wsock32dll);
232     if ( !gs_WSACreateEvent )
233         return false;
234 
235     wxDL_INIT_FUNC(gs_, WSAWaitForMultipleEvents, gs_wsock32dll);
236     if ( !gs_WSAWaitForMultipleEvents )
237         return false;
238 
239     wxDL_INIT_FUNC(gs_, WSAEnumNetworkEvents, gs_wsock32dll);
240     if ( !gs_WSAEnumNetworkEvents )
241         return false;
242 
243     currSocket = 0;
244 #endif // !__WXWINCE__/__WXWINCE__
245 
246   // finally initialize WinSock
247   WSADATA wsaData;
248   return WSAStartup((1 << 8) | 1, &wsaData) == 0;
249 }
250 
OnExit()251 void wxSocketMSWManager::OnExit()
252 {
253 #ifdef __WXWINCE__
254 /* Delete the threads here */
255     for(unsigned int i=0; i < currSocket; i++)
256         CloseHandle(hThread[i]);
257 #endif
258   /* Destroy internal window */
259   DestroyWindow(hWin);
260   UnregisterClass(CLASSNAME, wxGetInstance());
261 
262   WSACleanup();
263 
264   gs_wsock32dll.Unload();
265 }
266 
267 /* Per-socket GUI initialization / cleanup */
268 
wxSocketImplMSW(wxSocketBase & wxsocket)269 wxSocketImplMSW::wxSocketImplMSW(wxSocketBase& wxsocket)
270     : wxSocketImpl(wxsocket)
271 {
272   /* Allocate a new message number for this socket */
273   wxCRIT_SECT_LOCKER(lock, gs_critical);
274 
275   int i = firstAvailable;
276   while (socketList[i] != NULL)
277   {
278     i = (i + 1) % MAXSOCKETS;
279 
280     if (i == firstAvailable)    /* abort! */
281     {
282       m_msgnumber = 0; // invalid
283       return;
284     }
285   }
286   socketList[i] = this;
287   firstAvailable = (i + 1) % MAXSOCKETS;
288   m_msgnumber = (i + WM_USER);
289 }
290 
~wxSocketImplMSW()291 wxSocketImplMSW::~wxSocketImplMSW()
292 {
293   /* Remove the socket from the list */
294   wxCRIT_SECT_LOCKER(lock, gs_critical);
295 
296   if ( m_msgnumber )
297   {
298       // we need to remove any pending messages for this socket to avoid having
299       // them sent to a new socket which could reuse the same message number as
300       // soon as we destroy this one
301       MSG msg;
302       while ( ::PeekMessage(&msg, hWin, m_msgnumber, m_msgnumber, PM_REMOVE) )
303           ;
304 
305       socketList[m_msgnumber - WM_USER] = NULL;
306   }
307   //else: the socket has never been created successfully
308 }
309 
310 /* Windows proc for asynchronous event handling */
311 
wxSocket_Internal_WinProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)312 LRESULT CALLBACK wxSocket_Internal_WinProc(HWND hWnd,
313                                            UINT uMsg,
314                                            WPARAM wParam,
315                                            LPARAM lParam)
316 {
317     if ( uMsg < WM_USER || uMsg > (WM_USER + MAXSOCKETS - 1))
318         return DefWindowProc(hWnd, uMsg, wParam, lParam);
319 
320     wxSocketImplMSW *socket;
321     wxSocketNotify event = (wxSocketNotify)-1;
322     {
323         wxCRIT_SECT_LOCKER(lock, gs_critical);
324 
325         socket = socketList[(uMsg - WM_USER)];
326         if ( !socket )
327             return 0;
328 
329         // the socket may be already closed but we could still receive
330         // notifications for it sent (asynchronously) before it got closed
331         if ( socket->m_fd == INVALID_SOCKET )
332             return 0;
333 
334         wxASSERT_MSG( socket->m_fd == (SOCKET)wParam,
335                       "mismatch between message and socket?" );
336 
337         switch ( WSAGETSELECTEVENT(lParam) )
338         {
339             case FD_READ:
340                 // We may get a FD_READ notification even when there is no data
341                 // to read on the socket, in particular this happens on socket
342                 // creation when we seem to always get FD_CONNECT, FD_WRITE and
343                 // FD_READ notifications all at once (but it doesn't happen
344                 // only then). Ignore such dummy notifications.
345                 {
346                     fd_set fds;
347                     timeval tv = { 0, 0 };
348 
349                     wxFD_ZERO(&fds);
350                     wxFD_SET(socket->m_fd, &fds);
351 
352                     if ( select(socket->m_fd + 1, &fds, NULL, NULL, &tv) != 1 )
353                         return 0;
354                 }
355 
356                 event = wxSOCKET_INPUT;
357                 break;
358 
359             case FD_WRITE:
360                 event = wxSOCKET_OUTPUT;
361                 break;
362 
363             case FD_ACCEPT:
364                 event = wxSOCKET_CONNECTION;
365                 break;
366 
367             case FD_CONNECT:
368                 event = WSAGETSELECTERROR(lParam) ? wxSOCKET_LOST
369                                                   : wxSOCKET_CONNECTION;
370                 break;
371 
372             case FD_CLOSE:
373                 event = wxSOCKET_LOST;
374                 break;
375 
376             default:
377                 wxFAIL_MSG( "unexpected socket notification" );
378                 return 0;
379         }
380     } // unlock gs_critical
381 
382     socket->NotifyOnStateChange(event);
383 
384     return 0;
385 }
386 
387 /*
388  *  Enable all event notifications; we need to be notified of all
389  *  events for internal processing, but we will only notify users
390  *  when an appropriate callback function has been installed.
391  */
Install_Callback(wxSocketImpl * socket_,wxSocketNotify WXUNUSED (event))392 void wxSocketMSWManager::Install_Callback(wxSocketImpl *socket_,
393                                          wxSocketNotify WXUNUSED(event))
394 {
395     wxSocketImplMSW * const socket = static_cast<wxSocketImplMSW *>(socket_);
396 
397   if (socket->m_fd != INVALID_SOCKET)
398   {
399     /* We could probably just subscribe to all events regardless
400      * of the socket type, but MS recommends to do it this way.
401      */
402     long lEvent = socket->m_server?
403                   FD_ACCEPT : (FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE);
404 #ifndef __WXWINCE__
405     gs_WSAAsyncSelect(socket->m_fd, hWin, socket->m_msgnumber, lEvent);
406 #else
407 /*
408 *  WinCE creates a thread for socket event handling.
409 *  All needed parameters get passed through the thread_data structure.
410 */
411 
412     thread_data* d = new thread_data;
413     d->lEvent = lEvent;
414     d->hEvtWin = hWin;
415     d->msgnumber = socket->m_msgnumber;
416     d->fd = socket->m_fd;
417     socketHash[socket->m_fd] = true;
418     hThread[currSocket++] = CreateThread(NULL, 0, &SocketThread,(LPVOID)d, 0, NULL);
419 #endif
420   }
421 }
422 
423 /*
424  *  Disable event notifications (used when shutting down the socket)
425  */
Uninstall_Callback(wxSocketImpl * socket_,wxSocketNotify WXUNUSED (event))426 void wxSocketMSWManager::Uninstall_Callback(wxSocketImpl *socket_,
427                                             wxSocketNotify WXUNUSED(event))
428 {
429     wxSocketImplMSW * const socket = static_cast<wxSocketImplMSW *>(socket_);
430 
431   if (socket->m_fd != INVALID_SOCKET)
432   {
433 #ifndef __WXWINCE__
434     gs_WSAAsyncSelect(socket->m_fd, hWin, socket->m_msgnumber, 0);
435 #else
436     //Destroy the thread
437     socketHash[socket->m_fd] = false;
438 #endif
439   }
440 }
441 
442 // set the wxBase variable to point to our wxSocketManager implementation
443 //
444 // see comments in wx/apptrait.h for the explanation of why do we do it
445 // like this
446 static struct ManagerSetter
447 {
ManagerSetterManagerSetter448     ManagerSetter()
449     {
450         static wxSocketMSWManager s_manager;
451         wxAppTraits::SetDefaultSocketManager(&s_manager);
452     }
453 } gs_managerSetter;
454 
455 // see the relative linker macro in socket.cpp
456 wxFORCE_LINK_THIS_MODULE( mswsocket );
457 
458 // ============================================================================
459 // wxSocketImpl implementation
460 // ============================================================================
461 
DoClose()462 void wxSocketImplMSW::DoClose()
463 {
464     wxSocketManager::Get()->Uninstall_Callback(this);
465 
466     closesocket(m_fd);
467 }
468 
GetLastError() const469 wxSocketError wxSocketImplMSW::GetLastError() const
470 {
471     switch ( WSAGetLastError() )
472     {
473         case 0:
474             return wxSOCKET_NOERROR;
475 
476         case WSAENOTSOCK:
477             return wxSOCKET_INVSOCK;
478 
479         case WSAEWOULDBLOCK:
480             return wxSOCKET_WOULDBLOCK;
481 
482         default:
483             return wxSOCKET_IOERR;
484     }
485 }
486 
487 #endif  // wxUSE_SOCKETS
488