1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/sockmsw.cpp
3 // Purpose: MSW-specific socket code
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"
23 /* including rasasync.h (included from windows.h itself included from
24 * wx/setup.h and/or winsock.h results in this warning for
25 * RPCNOTIFICATION_ROUTINE
28 # pragma warning(disable:4115) /* named type definition in parentheses */
31 #include "wx/private/socket.h"
32 #include "wx/msw/private.h" // for wxGetInstance()
33 #include "wx/private/fd.h"
34 #include "wx/apptrait.h"
35 #include "wx/thread.h"
36 #include "wx/dynlib.h"
41 * As WSAAsyncSelect is not present on WinCE, it now uses WSACreateEvent,
42 * WSAEventSelect, WSAWaitForMultipleEvents and WSAEnumNetworkEvents. When
43 * enabling eventhandling for a socket a new thread it created that keeps track
44 * of the events and posts a messageto the hidden window to use the standard
47 #include "wx/msw/wince/net.h"
48 #include "wx/hashmap.h"
49 WX_DECLARE_HASH_MAP(int,bool,wxIntegerHash
,wxIntegerEqual
,SocketHash
);
52 #define isdigit(x) (x > 47 && x < 58)
54 #include "wx/msw/wince/net.h"
59 # pragma warning(default:4115) /* named type definition in parentheses */
62 #define CLASSNAME TEXT("_wxSocket_Internal_Window_Class")
64 /* implemented in utils.cpp */
65 extern "C" WXDLLIMPEXP_BASE HWND
66 wxCreateHiddenWindow(LPCTSTR
*pclassname
, LPCTSTR classname
, WNDPROC wndproc
);
68 /* Maximum number of different wxSocket objects at a given time.
69 * This value can be modified at will, but it CANNOT be greater
70 * than (0x7FFF - WM_USER + 1)
72 #define MAXSOCKETS 1024
74 #if (MAXSOCKETS > (0x7FFF - WM_USER + 1))
75 #error "MAXSOCKETS is too big!"
79 typedef int (PASCAL
*WSAAsyncSelect_t
)(SOCKET
,HWND
,u_int
,long);
81 /* Typedef the needed function prototypes and the WSANETWORKEVENTS structure
83 typedef struct _WSANETWORKEVENTS
{
86 } WSANETWORKEVENTS
, FAR
* LPWSANETWORKEVENTS
;
87 typedef HANDLE (PASCAL
*WSACreateEvent_t
)();
88 typedef int (PASCAL
*WSAEventSelect_t
)(SOCKET
,HANDLE
,long);
89 typedef int (PASCAL
*WSAWaitForMultipleEvents_t
)(long,HANDLE
,BOOL
,long,BOOL
);
90 typedef int (PASCAL
*WSAEnumNetworkEvents_t
)(SOCKET
,HANDLE
,LPWSANETWORKEVENTS
);
93 LRESULT CALLBACK
wxSocket_Internal_WinProc(HWND
, UINT
, WPARAM
, LPARAM
);
95 /* Global variables */
98 wxCRIT_SECT_DECLARE_MEMBER(gs_critical
);
99 static wxSocketImplMSW
*socketList
[MAXSOCKETS
];
100 static int firstAvailable
;
103 static WSAAsyncSelect_t gs_WSAAsyncSelect
= NULL
;
105 static SocketHash socketHash
;
106 static unsigned int currSocket
;
107 HANDLE hThread
[MAXSOCKETS
];
108 static WSACreateEvent_t gs_WSACreateEvent
= NULL
;
109 static WSAEventSelect_t gs_WSAEventSelect
= NULL
;
110 static WSAWaitForMultipleEvents_t gs_WSAWaitForMultipleEvents
= NULL
;
111 static WSAEnumNetworkEvents_t gs_WSAEnumNetworkEvents
= NULL
;
112 /* This structure will be used to pass data on to the thread that handles socket events.
114 typedef struct thread_data
{
116 unsigned long msgnumber
;
118 unsigned long lEvent
;
123 /* This thread handles socket events on WinCE using WSAEventSelect() as
124 * WSAAsyncSelect is not supported. When an event occurs for the socket, it is
125 * checked what kind of event happend and the correct message gets posted so
126 * that the hidden window can handle it as it would in other MSW builds.
128 DWORD WINAPI
SocketThread(LPVOID data
)
130 WSANETWORKEVENTS NetworkEvents
;
131 thread_data
* d
= (thread_data
*)data
;
133 HANDLE NetworkEvent
= gs_WSACreateEvent();
134 gs_WSAEventSelect(d
->fd
, NetworkEvent
, d
->lEvent
);
136 while(socketHash
[d
->fd
] == true)
138 if ((gs_WSAWaitForMultipleEvents(1, &NetworkEvent
, FALSE
,INFINITE
, FALSE
)) == WAIT_FAILED
)
140 printf("WSAWaitForMultipleEvents failed with error %d\n", WSAGetLastError());
143 if (gs_WSAEnumNetworkEvents(d
->fd
,NetworkEvent
, &NetworkEvents
) == SOCKET_ERROR
)
145 printf("WSAEnumNetworkEvents failed with error %d\n", WSAGetLastError());
149 long flags
= NetworkEvents
.lNetworkEvents
;
151 ::PostMessage(d
->hEvtWin
, d
->msgnumber
,d
->fd
, FD_READ
);
152 if (flags
& FD_WRITE
)
153 ::PostMessage(d
->hEvtWin
, d
->msgnumber
,d
->fd
, FD_WRITE
);
155 ::PostMessage(d
->hEvtWin
, d
->msgnumber
,d
->fd
, FD_OOB
);
156 if (flags
& FD_ACCEPT
)
157 ::PostMessage(d
->hEvtWin
, d
->msgnumber
,d
->fd
, FD_ACCEPT
);
158 if (flags
& FD_CONNECT
)
159 ::PostMessage(d
->hEvtWin
, d
->msgnumber
,d
->fd
, FD_CONNECT
);
160 if (flags
& FD_CLOSE
)
161 ::PostMessage(d
->hEvtWin
, d
->msgnumber
,d
->fd
, FD_CLOSE
);
164 gs_WSAEventSelect(d
->fd
, NetworkEvent
, 0);
170 // ----------------------------------------------------------------------------
171 // MSW implementation of wxSocketManager
172 // ----------------------------------------------------------------------------
174 class wxSocketMSWManager
: public wxSocketManager
177 virtual bool OnInit();
178 virtual void OnExit();
180 virtual wxSocketImpl
*CreateSocket(wxSocketBase
& wxsocket
)
182 return new wxSocketImplMSW(wxsocket
);
184 virtual void Install_Callback(wxSocketImpl
*socket
,
185 wxSocketNotify event
= wxSOCKET_LOST
);
186 virtual void Uninstall_Callback(wxSocketImpl
*socket
,
187 wxSocketNotify event
= wxSOCKET_LOST
);
190 static wxDynamicLibrary gs_wsock32dll
;
193 wxDynamicLibrary
wxSocketMSWManager::gs_wsock32dll
;
195 bool wxSocketMSWManager::OnInit()
197 static LPCTSTR pclassname
= NULL
;
200 /* Create internal window for event notifications */
201 hWin
= wxCreateHiddenWindow(&pclassname
, CLASSNAME
, wxSocket_Internal_WinProc
);
205 /* Initialize socket list */
206 for (i
= 0; i
< MAXSOCKETS
; i
++)
208 socketList
[i
] = NULL
;
212 // we don't link with wsock32.dll (or ws2 in CE case) statically to avoid
213 // dependencies on it for all the application using wx even if they don't use
216 #define WINSOCK_DLL_NAME wxT("ws2.dll")
218 #define WINSOCK_DLL_NAME wxT("wsock32.dll")
221 gs_wsock32dll
.Load(WINSOCK_DLL_NAME
, wxDL_VERBATIM
| wxDL_QUIET
);
222 if ( !gs_wsock32dll
.IsLoaded() )
226 wxDL_INIT_FUNC(gs_
, WSAAsyncSelect
, gs_wsock32dll
);
227 if ( !gs_WSAAsyncSelect
)
230 wxDL_INIT_FUNC(gs_
, WSAEventSelect
, gs_wsock32dll
);
231 if ( !gs_WSAEventSelect
)
234 wxDL_INIT_FUNC(gs_
, WSACreateEvent
, gs_wsock32dll
);
235 if ( !gs_WSACreateEvent
)
238 wxDL_INIT_FUNC(gs_
, WSAWaitForMultipleEvents
, gs_wsock32dll
);
239 if ( !gs_WSAWaitForMultipleEvents
)
242 wxDL_INIT_FUNC(gs_
, WSAEnumNetworkEvents
, gs_wsock32dll
);
243 if ( !gs_WSAEnumNetworkEvents
)
247 #endif // !__WXWINCE__/__WXWINCE__
249 // finally initialize WinSock
251 return WSAStartup((1 << 8) | 1, &wsaData
) == 0;
254 void wxSocketMSWManager::OnExit()
257 /* Delete the threads here */
258 for(unsigned int i
=0; i
< currSocket
; i
++)
259 CloseHandle(hThread
[i
]);
261 /* Destroy internal window */
263 UnregisterClass(CLASSNAME
, wxGetInstance());
267 gs_wsock32dll
.Unload();
270 /* Per-socket GUI initialization / cleanup */
272 wxSocketImplMSW::wxSocketImplMSW(wxSocketBase
& wxsocket
)
273 : wxSocketImpl(wxsocket
)
275 /* Allocate a new message number for this socket */
276 wxCRIT_SECT_LOCKER(lock
, gs_critical
);
278 int i
= firstAvailable
;
279 while (socketList
[i
] != NULL
)
281 i
= (i
+ 1) % MAXSOCKETS
;
283 if (i
== firstAvailable
) /* abort! */
285 m_msgnumber
= 0; // invalid
289 socketList
[i
] = this;
290 firstAvailable
= (i
+ 1) % MAXSOCKETS
;
291 m_msgnumber
= (i
+ WM_USER
);
294 wxSocketImplMSW::~wxSocketImplMSW()
296 /* Remove the socket from the list */
297 wxCRIT_SECT_LOCKER(lock
, gs_critical
);
301 // we need to remove any pending messages for this socket to avoid having
302 // them sent to a new socket which could reuse the same message number as
303 // soon as we destroy this one
305 while ( ::PeekMessage(&msg
, hWin
, m_msgnumber
, m_msgnumber
, PM_REMOVE
) )
308 socketList
[m_msgnumber
- WM_USER
] = NULL
;
310 //else: the socket has never been created successfully
313 /* Windows proc for asynchronous event handling */
315 LRESULT CALLBACK
wxSocket_Internal_WinProc(HWND hWnd
,
320 if ( uMsg
< WM_USER
|| uMsg
> (WM_USER
+ MAXSOCKETS
- 1))
321 return DefWindowProc(hWnd
, uMsg
, wParam
, lParam
);
323 wxSocketImplMSW
*socket
;
324 wxSocketNotify event
= (wxSocketNotify
)-1;
326 wxCRIT_SECT_LOCKER(lock
, gs_critical
);
328 socket
= socketList
[(uMsg
- WM_USER
)];
332 // the socket may be already closed but we could still receive
333 // notifications for it sent (asynchronously) before it got closed
334 if ( socket
->m_fd
== INVALID_SOCKET
)
337 wxASSERT_MSG( socket
->m_fd
== (SOCKET
)wParam
,
338 "mismatch between message and socket?" );
340 switch ( WSAGETSELECTEVENT(lParam
) )
343 // We may get a FD_READ notification even when there is no data
344 // to read on the socket, in particular this happens on socket
345 // creation when we seem to always get FD_CONNECT, FD_WRITE and
346 // FD_READ notifications all at once (but it doesn't happen
347 // only then). Ignore such dummy notifications.
353 wxFD_SET(socket
->m_fd
, &fds
);
355 if ( select(socket
->m_fd
+ 1, &fds
, NULL
, NULL
, &tv
) != 1 )
359 event
= wxSOCKET_INPUT
;
363 event
= wxSOCKET_OUTPUT
;
367 event
= wxSOCKET_CONNECTION
;
371 event
= WSAGETSELECTERROR(lParam
) ? wxSOCKET_LOST
372 : wxSOCKET_CONNECTION
;
376 event
= wxSOCKET_LOST
;
380 wxFAIL_MSG( "unexpected socket notification" );
383 } // unlock gs_critical
385 socket
->NotifyOnStateChange(event
);
391 * Enable all event notifications; we need to be notified of all
392 * events for internal processing, but we will only notify users
393 * when an appropriate callback function has been installed.
395 void wxSocketMSWManager::Install_Callback(wxSocketImpl
*socket_
,
396 wxSocketNotify
WXUNUSED(event
))
398 wxSocketImplMSW
* const socket
= static_cast<wxSocketImplMSW
*>(socket_
);
400 if (socket
->m_fd
!= INVALID_SOCKET
)
402 /* We could probably just subscribe to all events regardless
403 * of the socket type, but MS recommends to do it this way.
405 long lEvent
= socket
->m_server
?
406 FD_ACCEPT
: (FD_READ
| FD_WRITE
| FD_CONNECT
| FD_CLOSE
);
408 gs_WSAAsyncSelect(socket
->m_fd
, hWin
, socket
->m_msgnumber
, lEvent
);
411 * WinCE creates a thread for socket event handling.
412 * All needed parameters get passed through the thread_data structure.
415 thread_data
* d
= new thread_data
;
418 d
->msgnumber
= socket
->m_msgnumber
;
419 d
->fd
= socket
->m_fd
;
420 socketHash
[socket
->m_fd
] = true;
421 hThread
[currSocket
++] = CreateThread(NULL
, 0, &SocketThread
,(LPVOID
)d
, 0, NULL
);
427 * Disable event notifications (used when shutting down the socket)
429 void wxSocketMSWManager::Uninstall_Callback(wxSocketImpl
*socket_
,
430 wxSocketNotify
WXUNUSED(event
))
432 wxSocketImplMSW
* const socket
= static_cast<wxSocketImplMSW
*>(socket_
);
434 if (socket
->m_fd
!= INVALID_SOCKET
)
437 gs_WSAAsyncSelect(socket
->m_fd
, hWin
, socket
->m_msgnumber
, 0);
440 socketHash
[socket
->m_fd
] = false;
445 // set the wxBase variable to point to our wxSocketManager implementation
447 // see comments in wx/apptrait.h for the explanation of why do we do it
449 static struct ManagerSetter
453 static wxSocketMSWManager s_manager
;
454 wxAppTraits::SetDefaultSocketManager(&s_manager
);
458 // see the relative linker macro in socket.cpp
459 wxFORCE_LINK_THIS_MODULE( mswsocket
);
461 // ============================================================================
462 // wxSocketImpl implementation
463 // ============================================================================
465 void wxSocketImplMSW::DoClose()
467 wxSocketManager::Get()->Uninstall_Callback(this);
472 wxSocketError
wxSocketImplMSW::GetLastError() const
474 switch ( WSAGetLastError() )
477 return wxSOCKET_NOERROR
;
480 return wxSOCKET_INVSOCK
;
483 return wxSOCKET_WOULDBLOCK
;
486 return wxSOCKET_IOERR
;
490 #endif // wxUSE_SOCKETS