X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/bb20575e6e0f498e2766b01d77c7cf85b4bcd241..07aaf32633ecf18ec3edfbb41793a112914792d0:/src/msw/sockmsw.cpp?ds=sidebyside diff --git a/src/msw/sockmsw.cpp b/src/msw/sockmsw.cpp index 4215428a26..57f6b91199 100644 --- a/src/msw/sockmsw.cpp +++ b/src/msw/sockmsw.cpp @@ -1,13 +1,13 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: src/msw/gsockmsw.cpp -// Purpose: MSW-specific socket support +// Name: src/msw/sockmsw.cpp +// Purpose: MSW-specific socket code // Authors: Guilhem Lavaux, Guillermo Rodriguez Garcia // Created: April 1997 // Copyright: (C) 1999-1997, Guilhem Lavaux // (C) 1999-2000, Guillermo Rodriguez Garcia // (C) 2008 Vadim Zeitlin // RCS_ID: $Id$ -// License: wxWindows licence +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -20,16 +20,6 @@ #if wxUSE_SOCKETS -/* - * DONE: for WinCE we need to replace WSAAsyncSelect - * (Windows message-based notification of network events for a socket) - * with another mechanism. - * As WSAAsyncSelect is not present on WinCE, it now uses - * WSACreateEvent, WSAEventSelect, WSAWaitForMultipleEvents and WSAEnumNetworkEvents. - * When enabling eventhandling for a socket a new thread it created that keeps track of the events - * and posts a messageto the hidden window to use the standard message loop. - */ - /* including rasasync.h (included from windows.h itself included from * wx/setup.h and/or winsock.h results in this warning for * RPCNOTIFICATION_ROUTINE @@ -39,38 +29,39 @@ #endif #include "wx/private/socket.h" +#include "wx/msw/private.h" // for wxGetInstance() +#include "wx/private/fd.h" #include "wx/apptrait.h" +#include "wx/thread.h" +#include "wx/dynlib.h" #include "wx/link.h" -wxFORCE_LINK_THIS_MODULE(gsockmsw) - -extern "C" WXDLLIMPEXP_BASE HINSTANCE wxGetInstance(); -#define INSTANCE wxGetInstance() - #ifdef __WXWINCE__ -#include +/* + * As WSAAsyncSelect is not present on WinCE, it now uses WSACreateEvent, + * WSAEventSelect, WSAWaitForMultipleEvents and WSAEnumNetworkEvents. When + * enabling eventhandling for a socket a new thread it created that keeps track + * of the events and posts a messageto the hidden window to use the standard + * message loop. + */ #include "wx/msw/wince/net.h" #include "wx/hashmap.h" WX_DECLARE_HASH_MAP(int,bool,wxIntegerHash,wxIntegerEqual,SocketHash); -#endif -#include -#include -#include -#include -#include +#ifndef isdigit +#define isdigit(x) (x > 47 && x < 58) +#endif +#include "wx/msw/wince/net.h" -#include +#endif // __WXWINCE__ #ifdef _MSC_VER # pragma warning(default:4115) /* named type definition in parentheses */ #endif -#define CLASSNAME TEXT("_wxSocket_Internal_Window_Class") +#include "wx/msw/private/hiddenwin.h" -/* implemented in utils.cpp */ -extern "C" WXDLLIMPEXP_BASE HWND -wxCreateHiddenWindow(LPCTSTR *pclassname, LPCTSTR classname, WNDPROC wndproc); +#define CLASSNAME TEXT("_wxSocket_Internal_Window_Class") /* Maximum number of different wxSocket objects at a given time. * This value can be modified at will, but it CANNOT be greater @@ -83,7 +74,7 @@ wxCreateHiddenWindow(LPCTSTR *pclassname, LPCTSTR classname, WNDPROC wndproc); #endif #ifndef __WXWINCE__ -typedef int (PASCAL *WSAAsyncSelectFunc)(SOCKET,HWND,u_int,long); +typedef int (PASCAL *WSAAsyncSelect_t)(SOCKET,HWND,u_int,long); #else /* Typedef the needed function prototypes and the WSANETWORKEVENTS structure */ @@ -91,10 +82,10 @@ typedef struct _WSANETWORKEVENTS { long lNetworkEvents; int iErrorCode[10]; } WSANETWORKEVENTS, FAR * LPWSANETWORKEVENTS; -typedef HANDLE (PASCAL *WSACreateEventFunc)(); -typedef int (PASCAL *WSAEventSelectFunc)(SOCKET,HANDLE,long); -typedef int (PASCAL *WSAWaitForMultipleEventsFunc)(long,HANDLE,BOOL,long,BOOL); -typedef int (PASCAL *WSAEnumNetworkEventsFunc)(SOCKET,HANDLE,LPWSANETWORKEVENTS); +typedef HANDLE (PASCAL *WSACreateEvent_t)(); +typedef int (PASCAL *WSAEventSelect_t)(SOCKET,HANDLE,long); +typedef int (PASCAL *WSAWaitForMultipleEvents_t)(long,HANDLE,BOOL,long,BOOL); +typedef int (PASCAL *WSAEnumNetworkEvents_t)(SOCKET,HANDLE,LPWSANETWORKEVENTS); #endif //__WXWINCE__ LRESULT CALLBACK wxSocket_Internal_WinProc(HWND, UINT, WPARAM, LPARAM); @@ -102,20 +93,20 @@ LRESULT CALLBACK wxSocket_Internal_WinProc(HWND, UINT, WPARAM, LPARAM); /* Global variables */ static HWND hWin; -static CRITICAL_SECTION critical; +wxCRIT_SECT_DECLARE_MEMBER(gs_critical); static wxSocketImplMSW *socketList[MAXSOCKETS]; static int firstAvailable; #ifndef __WXWINCE__ -static WSAAsyncSelectFunc gs_WSAAsyncSelect = NULL; +static WSAAsyncSelect_t gs_WSAAsyncSelect = NULL; #else static SocketHash socketHash; static unsigned int currSocket; HANDLE hThread[MAXSOCKETS]; -static WSACreateEventFunc gs_WSACreateEvent = NULL; -static WSAEventSelectFunc gs_WSAEventSelect = NULL; -static WSAWaitForMultipleEventsFunc gs_WSAWaitForMultipleEvents = NULL; -static WSAEnumNetworkEventsFunc gs_WSAEnumNetworkEvents = NULL; +static WSACreateEvent_t gs_WSACreateEvent = NULL; +static WSAEventSelect_t gs_WSAEventSelect = NULL; +static WSAWaitForMultipleEvents_t gs_WSAWaitForMultipleEvents = NULL; +static WSAEnumNetworkEvents_t gs_WSAEnumNetworkEvents = NULL; /* This structure will be used to pass data on to the thread that handles socket events. */ typedef struct thread_data{ @@ -126,13 +117,11 @@ typedef struct thread_data{ }thread_data; #endif -static HMODULE gs_wsock32dll = 0; - - #ifdef __WXWINCE__ -/* This thread handles socket events on WinCE using WSAEventSelect() as WSAAsyncSelect is not supported. -* When an event occures for the socket, it is checked what kind of event happend and the correct message gets posted -* so that the hidden window can handle it as it would in other MSW builds. +/* This thread handles socket events on WinCE using WSAEventSelect() as + * WSAAsyncSelect is not supported. When an event occurs for the socket, it is + * checked what kind of event happened and the correct message gets posted so + * that the hidden window can handle it as it would in other MSW builds. */ DWORD WINAPI SocketThread(LPVOID data) { @@ -190,11 +179,16 @@ public: { return new wxSocketImplMSW(wxsocket); } - virtual void Install_Callback(wxSocketImpl *socket, wxSocketNotify event); - virtual void Uninstall_Callback(wxSocketImpl *socket, wxSocketNotify event); + virtual void Install_Callback(wxSocketImpl *socket, + wxSocketNotify event = wxSOCKET_LOST); + virtual void Uninstall_Callback(wxSocketImpl *socket, + wxSocketNotify event = wxSOCKET_LOST); + +private: + static wxDynamicLibrary gs_wsock32dll; }; -/* Global initializers */ +wxDynamicLibrary wxSocketMSWManager::gs_wsock32dll; bool wxSocketMSWManager::OnInit() { @@ -207,53 +201,48 @@ bool wxSocketMSWManager::OnInit() return false; /* Initialize socket list */ - InitializeCriticalSection(&critical); - for (i = 0; i < MAXSOCKETS; i++) { socketList[i] = NULL; } firstAvailable = 0; - /* Load WSAAsyncSelect from wsock32.dll (we don't link against it - statically to avoid dependency on wsock32.dll for apps that don't use - sockets): */ + // we don't link with wsock32.dll (or ws2 in CE case) statically to avoid + // dependencies on it for all the application using wx even if they don't use + // sockets +#ifdef __WXWINCE__ + #define WINSOCK_DLL_NAME wxT("ws2.dll") +#else + #define WINSOCK_DLL_NAME wxT("wsock32.dll") +#endif + + gs_wsock32dll.Load(WINSOCK_DLL_NAME, wxDL_VERBATIM | wxDL_QUIET); + if ( !gs_wsock32dll.IsLoaded() ) + return false; + #ifndef __WXWINCE__ - gs_wsock32dll = LoadLibrary(wxT("wsock32.dll")); - if (!gs_wsock32dll) - return false; - gs_WSAAsyncSelect =(WSAAsyncSelectFunc)GetProcAddress(gs_wsock32dll, - "WSAAsyncSelect"); - if (!gs_WSAAsyncSelect) - return false; + wxDL_INIT_FUNC(gs_, WSAAsyncSelect, gs_wsock32dll); + if ( !gs_WSAAsyncSelect ) + return false; #else -/* On WinCE we load ws2.dll which will provide the needed functions. -*/ - gs_wsock32dll = LoadLibrary(wxT("ws2.dll")); - if (!gs_wsock32dll) - return false; - gs_WSAEventSelect =(WSAEventSelectFunc)GetProcAddress(gs_wsock32dll, - wxT("WSAEventSelect")); - if (!gs_WSAEventSelect) - return false; + wxDL_INIT_FUNC(gs_, WSAEventSelect, gs_wsock32dll); + if ( !gs_WSAEventSelect ) + return false; - gs_WSACreateEvent =(WSACreateEventFunc)GetProcAddress(gs_wsock32dll, - wxT("WSACreateEvent")); - if (!gs_WSACreateEvent) - return false; + wxDL_INIT_FUNC(gs_, WSACreateEvent, gs_wsock32dll); + if ( !gs_WSACreateEvent ) + return false; - gs_WSAWaitForMultipleEvents =(WSAWaitForMultipleEventsFunc)GetProcAddress(gs_wsock32dll, - wxT("WSAWaitForMultipleEvents")); - if (!gs_WSAWaitForMultipleEvents) - return false; + wxDL_INIT_FUNC(gs_, WSAWaitForMultipleEvents, gs_wsock32dll); + if ( !gs_WSAWaitForMultipleEvents ) + return false; - gs_WSAEnumNetworkEvents =(WSAEnumNetworkEventsFunc)GetProcAddress(gs_wsock32dll, - wxT("WSAEnumNetworkEvents")); - if (!gs_WSAEnumNetworkEvents) - return false; + wxDL_INIT_FUNC(gs_, WSAEnumNetworkEvents, gs_wsock32dll); + if ( !gs_WSAEnumNetworkEvents ) + return false; - currSocket = 0; -#endif + currSocket = 0; +#endif // !__WXWINCE__/__WXWINCE__ // finally initialize WinSock WSADATA wsaData; @@ -269,19 +258,11 @@ void wxSocketMSWManager::OnExit() #endif /* Destroy internal window */ DestroyWindow(hWin); - UnregisterClass(CLASSNAME, INSTANCE); - - /* Unlock wsock32.dll */ - if (gs_wsock32dll) - { - FreeLibrary(gs_wsock32dll); - gs_wsock32dll = 0; - } - - /* Delete critical section */ - DeleteCriticalSection(&critical); + UnregisterClass(CLASSNAME, wxGetInstance()); WSACleanup(); + + gs_wsock32dll.Unload(); } /* Per-socket GUI initialization / cleanup */ @@ -290,7 +271,7 @@ wxSocketImplMSW::wxSocketImplMSW(wxSocketBase& wxsocket) : wxSocketImpl(wxsocket) { /* Allocate a new message number for this socket */ - EnterCriticalSection(&critical); + wxCRIT_SECT_LOCKER(lock, gs_critical); int i = firstAvailable; while (socketList[i] != NULL) @@ -299,7 +280,6 @@ wxSocketImplMSW::wxSocketImplMSW(wxSocketBase& wxsocket) if (i == firstAvailable) /* abort! */ { - LeaveCriticalSection(&critical); m_msgnumber = 0; // invalid return; } @@ -307,14 +287,12 @@ wxSocketImplMSW::wxSocketImplMSW(wxSocketBase& wxsocket) socketList[i] = this; firstAvailable = (i + 1) % MAXSOCKETS; m_msgnumber = (i + WM_USER); - - LeaveCriticalSection(&critical); } wxSocketImplMSW::~wxSocketImplMSW() { /* Remove the socket from the list */ - EnterCriticalSection(&critical); + wxCRIT_SECT_LOCKER(lock, gs_critical); if ( m_msgnumber ) { @@ -328,8 +306,6 @@ wxSocketImplMSW::~wxSocketImplMSW() socketList[m_msgnumber - WM_USER] = NULL; } //else: the socket has never been created successfully - - LeaveCriticalSection(&critical); } /* Windows proc for asynchronous event handling */ @@ -339,55 +315,74 @@ LRESULT CALLBACK wxSocket_Internal_WinProc(HWND hWnd, WPARAM wParam, LPARAM lParam) { - wxSocketImplMSW *socket; - wxSocketNotify event; - - if (uMsg >= WM_USER && uMsg <= (WM_USER + MAXSOCKETS - 1)) - { - EnterCriticalSection(&critical); - socket = socketList[(uMsg - WM_USER)]; - event = (wxSocketNotify) -1; + if ( uMsg < WM_USER || uMsg > (WM_USER + MAXSOCKETS - 1)) + return DefWindowProc(hWnd, uMsg, wParam, lParam); - /* Check that the socket still exists (it has not been - * destroyed) and for safety, check that the m_fd field - * is what we expect it to be. - */ - if ((socket != NULL) && ((WPARAM)socket->m_fd == wParam)) + wxSocketImplMSW *socket; + wxSocketNotify event = (wxSocketNotify)-1; { - switch WSAGETSELECTEVENT(lParam) - { - case FD_READ: event = wxSOCKET_INPUT; break; - case FD_WRITE: event = wxSOCKET_OUTPUT; break; - case FD_ACCEPT: event = wxSOCKET_CONNECTION; break; - case FD_CONNECT: + wxCRIT_SECT_LOCKER(lock, gs_critical); + + socket = socketList[(uMsg - WM_USER)]; + if ( !socket ) + return 0; + + // the socket may be already closed but we could still receive + // notifications for it sent (asynchronously) before it got closed + if ( socket->m_fd == INVALID_SOCKET ) + return 0; + + wxASSERT_MSG( socket->m_fd == (SOCKET)wParam, + "mismatch between message and socket?" ); + + switch ( WSAGETSELECTEVENT(lParam) ) { - if (WSAGETSELECTERROR(lParam) != 0) - event = wxSOCKET_LOST; - else - event = wxSOCKET_CONNECTION; - break; + case FD_READ: + // We may get a FD_READ notification even when there is no data + // to read on the socket, in particular this happens on socket + // creation when we seem to always get FD_CONNECT, FD_WRITE and + // FD_READ notifications all at once (but it doesn't happen + // only then). Ignore such dummy notifications. + { + fd_set fds; + timeval tv = { 0, 0 }; + + wxFD_ZERO(&fds); + wxFD_SET(socket->m_fd, &fds); + + if ( select(socket->m_fd + 1, &fds, NULL, NULL, &tv) != 1 ) + return 0; + } + + event = wxSOCKET_INPUT; + break; + + case FD_WRITE: + event = wxSOCKET_OUTPUT; + break; + + case FD_ACCEPT: + event = wxSOCKET_CONNECTION; + break; + + case FD_CONNECT: + event = WSAGETSELECTERROR(lParam) ? wxSOCKET_LOST + : wxSOCKET_CONNECTION; + break; + + case FD_CLOSE: + event = wxSOCKET_LOST; + break; + + default: + wxFAIL_MSG( "unexpected socket notification" ); + return 0; } - case FD_CLOSE: event = wxSOCKET_LOST; break; - } - - if (event != -1) - { - if (event == wxSOCKET_LOST) - socket->m_detected = wxSOCKET_LOST_FLAG; - else - socket->m_detected |= (1 << event); - } - } - - LeaveCriticalSection(&critical); + } // unlock gs_critical - if ( socket ) - socket->NotifyOnStateChange(event); + socket->NotifyOnStateChange(event); - return (LRESULT) 0; - } - else - return DefWindowProc(hWnd, uMsg, wParam, lParam); + return 0; } /* @@ -430,7 +425,7 @@ void wxSocketMSWManager::Install_Callback(wxSocketImpl *socket_, * Disable event notifications (used when shutting down the socket) */ void wxSocketMSWManager::Uninstall_Callback(wxSocketImpl *socket_, - wxSocketNotify WXUNUSED(event)) + wxSocketNotify WXUNUSED(event)) { wxSocketImplMSW * const socket = static_cast(socket_); @@ -458,4 +453,36 @@ static struct ManagerSetter } } gs_managerSetter; +// see the relative linker macro in socket.cpp +wxFORCE_LINK_THIS_MODULE( mswsocket ); + +// ============================================================================ +// wxSocketImpl implementation +// ============================================================================ + +void wxSocketImplMSW::DoClose() +{ + wxSocketManager::Get()->Uninstall_Callback(this); + + closesocket(m_fd); +} + +wxSocketError wxSocketImplMSW::GetLastError() const +{ + switch ( WSAGetLastError() ) + { + case 0: + return wxSOCKET_NOERROR; + + case WSAENOTSOCK: + return wxSOCKET_INVSOCK; + + case WSAEWOULDBLOCK: + return wxSOCKET_WOULDBLOCK; + + default: + return wxSOCKET_IOERR; + } +} + #endif // wxUSE_SOCKETS