]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/sockmsw.cpp
Use "wx" prefix for the GUIDs we (re)define in wxMSW code.
[wxWidgets.git] / src / msw / sockmsw.cpp
index 4215428a26cf28c5a5777cbcf04a0f4b5a1efbeb..7ea56a4ea123ff12fa74b29a1977a36025219fe0 100644 (file)
@@ -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
 /////////////////////////////////////////////////////////////////////////////
 
 
 
 #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 */
@@ -83,7 +76,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 +84,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 +95,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 +119,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 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)
 {
@@ -190,11 +181,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 +203,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 +260,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 +273,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 +282,6 @@ wxSocketImplMSW::wxSocketImplMSW(wxSocketBase& wxsocket)
 
     if (i == firstAvailable)    /* abort! */
     {
-      LeaveCriticalSection(&critical);
       m_msgnumber = 0; // invalid
       return;
     }
@@ -307,14 +289,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 +308,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 +317,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))
+        return DefWindowProc(hWnd, uMsg, wParam, lParam);
 
-  if (uMsg >= WM_USER && uMsg <= (WM_USER + MAXSOCKETS - 1))
-  {
-    EnterCriticalSection(&critical);
-    socket = socketList[(uMsg - WM_USER)];
-    event = (wxSocketNotify) -1;
-
-    /* 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 };
+
+                    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);
-      }
-    }
+    } // unlock gs_critical
 
-    LeaveCriticalSection(&critical);
+    socket->NotifyOnStateChange(event);
 
-    if ( socket )
-        socket->NotifyOnStateChange(event);
-
-    return (LRESULT) 0;
-  }
-  else
-    return DefWindowProc(hWnd, uMsg, wParam, lParam);
+    return 0;
 }
 
 /*
@@ -430,7 +427,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<wxSocketImplMSW *>(socket_);
 
@@ -458,4 +455,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