/////////////////////////////////////////////////////////////////////////////
-// 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
/////////////////////////////////////////////////////////////////////////////
#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
#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 <winsock.h>
+/*
+ * 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 <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <ctype.h>
+#ifndef isdigit
+#define isdigit(x) (x > 47 && x < 58)
+#endif
+#include "wx/msw/wince/net.h"
-#include <winsock.h>
+#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
#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
*/
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);
/* 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{
}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 happend 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)
{
{
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()
{
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;
#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 */
: 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)
if (i == firstAvailable) /* abort! */
{
- LeaveCriticalSection(&critical);
m_msgnumber = 0; // invalid
return;
}
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 )
{
socketList[m_msgnumber - WM_USER] = NULL;
}
//else: the socket has never been created successfully
-
- LeaveCriticalSection(&critical);
}
/* Windows proc for asynchronous event handling */
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;
}
/*
* 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<wxSocketImplMSW *>(socket_);
}
} 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