1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/gsockmsw.cpp
3 // Purpose: MSW-specific socket support
4 // Authors: Guilhem Lavaux, Guillermo Rodriguez Garcia
6 // Copyright: (C) 1999-1997, Guilhem Lavaux
7 // (C) 1999-2000, Guillermo Rodriguez Garcia
8 // (C) 2008 Vadim Zeitlin
10 // License: wxWindows licence
11 /////////////////////////////////////////////////////////////////////////////
14 // For compilers that support precompilation, includes "wx.h".
15 #include "wx/wxprec.h"
24 * DONE: for WinCE we need to replace WSAAsyncSelect
25 * (Windows message-based notification of network events for a socket)
26 * with another mechanism.
27 * As WSAAsyncSelect is not present on WinCE, it now uses
28 * WSACreateEvent, WSAEventSelect, WSAWaitForMultipleEvents and WSAEnumNetworkEvents.
29 * When enabling eventhandling for a socket a new thread it created that keeps track of the events
30 * and posts a messageto the hidden window to use the standard message loop.
33 /* including rasasync.h (included from windows.h itself included from
34 * wx/setup.h and/or winsock.h results in this warning for
35 * RPCNOTIFICATION_ROUTINE
38 # pragma warning(disable:4115) /* named type definition in parentheses */
41 #include "wx/private/socket.h"
42 #include "wx/apptrait.h"
45 wxFORCE_LINK_THIS_MODULE(gsockmsw
)
47 extern "C" WXDLLIMPEXP_BASE HINSTANCE
wxGetInstance();
48 #define INSTANCE wxGetInstance()
52 #include "wx/msw/wince/net.h"
53 #include "wx/hashmap.h"
54 WX_DECLARE_HASH_MAP(int,bool,wxIntegerHash
,wxIntegerEqual
,SocketHash
);
66 # pragma warning(default:4115) /* named type definition in parentheses */
69 #define CLASSNAME TEXT("_wxSocket_Internal_Window_Class")
71 /* implemented in utils.cpp */
72 extern "C" WXDLLIMPEXP_BASE HWND
73 wxCreateHiddenWindow(LPCTSTR
*pclassname
, LPCTSTR classname
, WNDPROC wndproc
);
75 /* Maximum number of different wxSocket objects at a given time.
76 * This value can be modified at will, but it CANNOT be greater
77 * than (0x7FFF - WM_USER + 1)
79 #define MAXSOCKETS 1024
81 #if (MAXSOCKETS > (0x7FFF - WM_USER + 1))
82 #error "MAXSOCKETS is too big!"
86 typedef int (PASCAL
*WSAAsyncSelectFunc
)(SOCKET
,HWND
,u_int
,long);
88 /* Typedef the needed function prototypes and the WSANETWORKEVENTS structure
90 typedef struct _WSANETWORKEVENTS
{
93 } WSANETWORKEVENTS
, FAR
* LPWSANETWORKEVENTS
;
94 typedef HANDLE (PASCAL
*WSACreateEventFunc
)();
95 typedef int (PASCAL
*WSAEventSelectFunc
)(SOCKET
,HANDLE
,long);
96 typedef int (PASCAL
*WSAWaitForMultipleEventsFunc
)(long,HANDLE
,BOOL
,long,BOOL
);
97 typedef int (PASCAL
*WSAEnumNetworkEventsFunc
)(SOCKET
,HANDLE
,LPWSANETWORKEVENTS
);
100 LRESULT CALLBACK
wxSocket_Internal_WinProc(HWND
, UINT
, WPARAM
, LPARAM
);
102 /* Global variables */
105 static CRITICAL_SECTION critical
;
106 static wxSocketImplMSW
*socketList
[MAXSOCKETS
];
107 static int firstAvailable
;
110 static WSAAsyncSelectFunc gs_WSAAsyncSelect
= NULL
;
112 static SocketHash socketHash
;
113 static unsigned int currSocket
;
114 HANDLE hThread
[MAXSOCKETS
];
115 static WSACreateEventFunc gs_WSACreateEvent
= NULL
;
116 static WSAEventSelectFunc gs_WSAEventSelect
= NULL
;
117 static WSAWaitForMultipleEventsFunc gs_WSAWaitForMultipleEvents
= NULL
;
118 static WSAEnumNetworkEventsFunc gs_WSAEnumNetworkEvents
= NULL
;
119 /* This structure will be used to pass data on to the thread that handles socket events.
121 typedef struct thread_data
{
123 unsigned long msgnumber
;
125 unsigned long lEvent
;
129 static HMODULE gs_wsock32dll
= 0;
133 /* This thread handles socket events on WinCE using WSAEventSelect() as WSAAsyncSelect is not supported.
134 * When an event occures for the socket, it is checked what kind of event happend and the correct message gets posted
135 * so that the hidden window can handle it as it would in other MSW builds.
137 DWORD WINAPI
SocketThread(LPVOID data
)
139 WSANETWORKEVENTS NetworkEvents
;
140 thread_data
* d
= (thread_data
*)data
;
142 HANDLE NetworkEvent
= gs_WSACreateEvent();
143 gs_WSAEventSelect(d
->fd
, NetworkEvent
, d
->lEvent
);
145 while(socketHash
[d
->fd
] == true)
147 if ((gs_WSAWaitForMultipleEvents(1, &NetworkEvent
, FALSE
,INFINITE
, FALSE
)) == WAIT_FAILED
)
149 printf("WSAWaitForMultipleEvents failed with error %d\n", WSAGetLastError());
152 if (gs_WSAEnumNetworkEvents(d
->fd
,NetworkEvent
, &NetworkEvents
) == SOCKET_ERROR
)
154 printf("WSAEnumNetworkEvents failed with error %d\n", WSAGetLastError());
158 long flags
= NetworkEvents
.lNetworkEvents
;
160 ::PostMessage(d
->hEvtWin
, d
->msgnumber
,d
->fd
, FD_READ
);
161 if (flags
& FD_WRITE
)
162 ::PostMessage(d
->hEvtWin
, d
->msgnumber
,d
->fd
, FD_WRITE
);
164 ::PostMessage(d
->hEvtWin
, d
->msgnumber
,d
->fd
, FD_OOB
);
165 if (flags
& FD_ACCEPT
)
166 ::PostMessage(d
->hEvtWin
, d
->msgnumber
,d
->fd
, FD_ACCEPT
);
167 if (flags
& FD_CONNECT
)
168 ::PostMessage(d
->hEvtWin
, d
->msgnumber
,d
->fd
, FD_CONNECT
);
169 if (flags
& FD_CLOSE
)
170 ::PostMessage(d
->hEvtWin
, d
->msgnumber
,d
->fd
, FD_CLOSE
);
173 gs_WSAEventSelect(d
->fd
, NetworkEvent
, 0);
179 // ----------------------------------------------------------------------------
180 // MSW implementation of wxSocketManager
181 // ----------------------------------------------------------------------------
183 class wxSocketMSWManager
: public wxSocketManager
186 virtual bool OnInit();
187 virtual void OnExit();
189 virtual wxSocketImpl
*CreateSocket(wxSocketBase
& wxsocket
)
191 return new wxSocketImplMSW(wxsocket
);
193 virtual void Install_Callback(wxSocketImpl
*socket
, wxSocketNotify event
);
194 virtual void Uninstall_Callback(wxSocketImpl
*socket
, wxSocketNotify event
);
197 /* Global initializers */
199 bool wxSocketMSWManager::OnInit()
201 static LPCTSTR pclassname
= NULL
;
204 /* Create internal window for event notifications */
205 hWin
= wxCreateHiddenWindow(&pclassname
, CLASSNAME
, wxSocket_Internal_WinProc
);
209 /* Initialize socket list */
210 InitializeCriticalSection(&critical
);
212 for (i
= 0; i
< MAXSOCKETS
; i
++)
214 socketList
[i
] = NULL
;
218 /* Load WSAAsyncSelect from wsock32.dll (we don't link against it
219 statically to avoid dependency on wsock32.dll for apps that don't use
222 gs_wsock32dll
= LoadLibrary(wxT("wsock32.dll"));
225 gs_WSAAsyncSelect
=(WSAAsyncSelectFunc
)GetProcAddress(gs_wsock32dll
,
227 if (!gs_WSAAsyncSelect
)
230 /* On WinCE we load ws2.dll which will provide the needed functions.
232 gs_wsock32dll
= LoadLibrary(wxT("ws2.dll"));
235 gs_WSAEventSelect
=(WSAEventSelectFunc
)GetProcAddress(gs_wsock32dll
,
236 wxT("WSAEventSelect"));
237 if (!gs_WSAEventSelect
)
240 gs_WSACreateEvent
=(WSACreateEventFunc
)GetProcAddress(gs_wsock32dll
,
241 wxT("WSACreateEvent"));
242 if (!gs_WSACreateEvent
)
245 gs_WSAWaitForMultipleEvents
=(WSAWaitForMultipleEventsFunc
)GetProcAddress(gs_wsock32dll
,
246 wxT("WSAWaitForMultipleEvents"));
247 if (!gs_WSAWaitForMultipleEvents
)
250 gs_WSAEnumNetworkEvents
=(WSAEnumNetworkEventsFunc
)GetProcAddress(gs_wsock32dll
,
251 wxT("WSAEnumNetworkEvents"));
252 if (!gs_WSAEnumNetworkEvents
)
258 // finally initialize WinSock
260 return WSAStartup((1 << 8) | 1, &wsaData
) == 0;
263 void wxSocketMSWManager::OnExit()
266 /* Delete the threads here */
267 for(unsigned int i
=0; i
< currSocket
; i
++)
268 CloseHandle(hThread
[i
]);
270 /* Destroy internal window */
272 UnregisterClass(CLASSNAME
, INSTANCE
);
274 /* Unlock wsock32.dll */
277 FreeLibrary(gs_wsock32dll
);
281 /* Delete critical section */
282 DeleteCriticalSection(&critical
);
287 /* Per-socket GUI initialization / cleanup */
289 wxSocketImplMSW::wxSocketImplMSW(wxSocketBase
& wxsocket
)
290 : wxSocketImpl(wxsocket
)
292 /* Allocate a new message number for this socket */
293 EnterCriticalSection(&critical
);
295 int i
= firstAvailable
;
296 while (socketList
[i
] != NULL
)
298 i
= (i
+ 1) % MAXSOCKETS
;
300 if (i
== firstAvailable
) /* abort! */
302 LeaveCriticalSection(&critical
);
303 m_msgnumber
= 0; // invalid
307 socketList
[i
] = this;
308 firstAvailable
= (i
+ 1) % MAXSOCKETS
;
309 m_msgnumber
= (i
+ WM_USER
);
311 LeaveCriticalSection(&critical
);
314 wxSocketImplMSW::~wxSocketImplMSW()
316 /* Remove the socket from the list */
317 EnterCriticalSection(&critical
);
321 // we need to remove any pending messages for this socket to avoid having
322 // them sent to a new socket which could reuse the same message number as
323 // soon as we destroy this one
325 while ( ::PeekMessage(&msg
, hWin
, m_msgnumber
, m_msgnumber
, PM_REMOVE
) )
328 socketList
[m_msgnumber
- WM_USER
] = NULL
;
330 //else: the socket has never been created successfully
332 LeaveCriticalSection(&critical
);
335 /* Windows proc for asynchronous event handling */
337 LRESULT CALLBACK
wxSocket_Internal_WinProc(HWND hWnd
,
342 wxSocketImplMSW
*socket
;
343 wxSocketNotify event
;
345 if (uMsg
>= WM_USER
&& uMsg
<= (WM_USER
+ MAXSOCKETS
- 1))
347 EnterCriticalSection(&critical
);
348 socket
= socketList
[(uMsg
- WM_USER
)];
349 event
= (wxSocketNotify
) -1;
351 /* Check that the socket still exists (it has not been
352 * destroyed) and for safety, check that the m_fd field
353 * is what we expect it to be.
355 if ((socket
!= NULL
) && ((WPARAM
)socket
->m_fd
== wParam
))
357 switch WSAGETSELECTEVENT(lParam
)
359 case FD_READ
: event
= wxSOCKET_INPUT
; break;
360 case FD_WRITE
: event
= wxSOCKET_OUTPUT
; break;
361 case FD_ACCEPT
: event
= wxSOCKET_CONNECTION
; break;
364 if (WSAGETSELECTERROR(lParam
) != 0)
365 event
= wxSOCKET_LOST
;
367 event
= wxSOCKET_CONNECTION
;
370 case FD_CLOSE
: event
= wxSOCKET_LOST
; break;
375 if (event
== wxSOCKET_LOST
)
376 socket
->m_detected
= wxSOCKET_LOST_FLAG
;
378 socket
->m_detected
|= (1 << event
);
382 LeaveCriticalSection(&critical
);
385 socket
->NotifyOnStateChange(event
);
390 return DefWindowProc(hWnd
, uMsg
, wParam
, lParam
);
394 * Enable all event notifications; we need to be notified of all
395 * events for internal processing, but we will only notify users
396 * when an appropriate callback function has been installed.
398 void wxSocketMSWManager::Install_Callback(wxSocketImpl
*socket_
,
399 wxSocketNotify
WXUNUSED(event
))
401 wxSocketImplMSW
* const socket
= static_cast<wxSocketImplMSW
*>(socket_
);
403 if (socket
->m_fd
!= INVALID_SOCKET
)
405 /* We could probably just subscribe to all events regardless
406 * of the socket type, but MS recommends to do it this way.
408 long lEvent
= socket
->m_server
?
409 FD_ACCEPT
: (FD_READ
| FD_WRITE
| FD_CONNECT
| FD_CLOSE
);
411 gs_WSAAsyncSelect(socket
->m_fd
, hWin
, socket
->m_msgnumber
, lEvent
);
414 * WinCE creates a thread for socket event handling.
415 * All needed parameters get passed through the thread_data structure.
418 thread_data
* d
= new thread_data
;
421 d
->msgnumber
= socket
->m_msgnumber
;
422 d
->fd
= socket
->m_fd
;
423 socketHash
[socket
->m_fd
] = true;
424 hThread
[currSocket
++] = CreateThread(NULL
, 0, &SocketThread
,(LPVOID
)d
, 0, NULL
);
430 * Disable event notifications (used when shutting down the socket)
432 void wxSocketMSWManager::Uninstall_Callback(wxSocketImpl
*socket_
,
433 wxSocketNotify
WXUNUSED(event
))
435 wxSocketImplMSW
* const socket
= static_cast<wxSocketImplMSW
*>(socket_
);
437 if (socket
->m_fd
!= INVALID_SOCKET
)
440 gs_WSAAsyncSelect(socket
->m_fd
, hWin
, socket
->m_msgnumber
, 0);
443 socketHash
[socket
->m_fd
] = false;
448 // set the wxBase variable to point to our wxSocketManager implementation
450 // see comments in wx/apptrait.h for the explanation of why do we do it
452 static struct ManagerSetter
456 static wxSocketMSWManager s_manager
;
457 wxAppTraits::SetDefaultSocketManager(&s_manager
);
461 #endif // wxUSE_SOCKETS