Bugzilla bug 363997: when running on Windows Vista, set the sockets in the NSPR_4_6_BRANCH
authorwtc%google.com
Fri, 27 Apr 2007 20:41:58 +0000
branchNSPR_4_6_BRANCH
changeset 3820 ffb9b96d25e443f8cf17a6868c9204f807c5ea81
parent 3819 e669ae3b2344a7f82d51e065281f96fc158812c3
child 3821 3780ff8b0521a9be5742d552fa4dadd14c6ed28e
push idunknown
push userunknown
push dateunknown
bugs363997
Bugzilla bug 363997: when running on Windows Vista, set the sockets in the compatibility mode so that the new TCP/IP stack in Windows Vista can interoperate with all the TCP/IP implementations. The patch is contributed by Seth Spitzer <sspitzer@mozilla.com>. r=wtc,biesi Modified Files: _win95.h /w95io.c w95sock.c w95thred.c Tag: NSPR_4_6_BRANCH
pr/include/md/_win95.h
pr/src/md/windows/w95io.c
pr/src/md/windows/w95sock.c
pr/src/md/windows/w95thred.c
--- a/pr/include/md/_win95.h
+++ b/pr/include/md/_win95.h
@@ -271,16 +271,18 @@ extern PRBool _pr_useUnicode;
 #define _MD_OPEN_FILE_UTF16           _PR_MD_OPEN_FILE_UTF16
 #define _MD_OPEN_DIR_UTF16            _PR_MD_OPEN_DIR_UTF16
 #define _MD_READ_DIR_UTF16            _PR_MD_READ_DIR_UTF16
 #define _MD_CLOSE_DIR_UTF16           _PR_MD_CLOSE_DIR_UTF16
 #define _MD_GETFILEINFO64_UTF16       _PR_MD_GETFILEINFO64_UTF16
 #endif /* MOZ_UNICODE */
 
 /* --- Socket IO stuff --- */
+extern void _PR_MD_InitSockets(void);
+extern void _PR_MD_CleanupSockets(void);
 #define _MD_EACCES                WSAEACCES
 #define _MD_EADDRINUSE            WSAEADDRINUSE
 #define _MD_EADDRNOTAVAIL         WSAEADDRNOTAVAIL
 #define _MD_EAFNOSUPPORT          WSAEAFNOSUPPORT
 #define _MD_EAGAIN                WSAEWOULDBLOCK
 #define _MD_EALREADY              WSAEALREADY
 #define _MD_EBADF                 WSAEBADF
 #define _MD_ECONNREFUSED          WSAECONNREFUSED
--- a/pr/src/md/windows/w95io.c
+++ b/pr/src/md/windows/w95io.c
@@ -118,16 +118,18 @@ void
         PR_ASSERT(0 != rv);
         PR_ASSERT(filetime.prt == _pr_filetime_offset);
     }
 #endif /* DEBUG */
 
     _PR_NT_InitSids();
 
     InitUnicodeSupport();
+
+    _PR_MD_InitSockets();
 }
 
 PRStatus
 _PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks)
 {
     DWORD rv;
 
     PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ?
--- a/pr/src/md/windows/w95sock.c
+++ b/pr/src/md/windows/w95sock.c
@@ -48,16 +48,105 @@
 static PRInt32 socket_io_wait(
     PRInt32 osfd, 
     PRInt32 fd_type,
     PRIntervalTime timeout);
 
 
 /* --- SOCKET IO --------------------------------------------------------- */
 
+/*
+ * we only want to call WSAIoctl() on Vista and later
+ * so don't pay for it at build time (and avoid including winsock2.h)
+ */
+
+/* from ws2def.h */
+#define IOC_IN                      0x80000000      /* copy in parameters */
+#define IOC_VENDOR                  0x18000000
+#define _WSAIOW(x,y)                (IOC_IN|(x)|(y))
+/* from MSWSockDef.h */
+#define SIO_SET_COMPATIBILITY_MODE  _WSAIOW(IOC_VENDOR,300)
+
+typedef enum _WSA_COMPATIBILITY_BEHAVIOR_ID {
+    WsaBehaviorAll = 0,
+    WsaBehaviorReceiveBuffering,
+    WsaBehaviorAutoTuning
+} WSA_COMPATIBILITY_BEHAVIOR_ID, *PWSA_COMPATIBILITY_BEHAVIOR_ID;
+
+/* from sdkddkver.h */
+#define NTDDI_LONGHORN                      0x06000000
+
+/* from winsock2.h */
+#define WSAEVENT                HANDLE
+
+#define WSAOVERLAPPED           OVERLAPPED
+typedef struct _OVERLAPPED *    LPWSAOVERLAPPED;
+
+typedef void (CALLBACK * LPWSAOVERLAPPED_COMPLETION_ROUTINE)(
+    IN DWORD dwError,
+    IN DWORD cbTransferred,
+    IN LPWSAOVERLAPPED lpOverlapped,
+    IN DWORD dwFlags
+);
+
+typedef int (__stdcall * WSAIOCTLPROC) (
+    SOCKET s,
+    DWORD dwIoControlCode,
+    LPVOID lpvInBuffer,
+    DWORD cbInBuffer,
+    LPVOID lpvOutBuffer,
+    DWORD cbOutBuffer,
+    LPDWORD lpcbBytesReturned,
+    LPWSAOVERLAPPED lpOverlapped,
+    LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
+);
+
+typedef struct _WSA_COMPATIBILITY_MODE {
+    WSA_COMPATIBILITY_BEHAVIOR_ID BehaviorId;
+    ULONG TargetOsVersion;
+} WSA_COMPATIBILITY_MODE, *PWSA_COMPATIBILITY_MODE;
+
+static HMODULE libWinsock2 = NULL;
+static WSAIOCTLPROC wsaioctlProc = NULL;
+static PRBool socketSetCompatMode = PR_FALSE;
+
+void _PR_MD_InitSockets(void)
+{
+    OSVERSIONINFO osvi;
+
+    memset(&osvi, 0, sizeof(osvi));
+    osvi.dwOSVersionInfoSize = sizeof(osvi);
+    GetVersionEx(&osvi);
+
+    /* if Vista or later... */
+    if (osvi.dwMajorVersion >= 6)
+    {
+        libWinsock2 = LoadLibrary("Ws2_32.dll");
+        if (libWinsock2)
+        {
+            wsaioctlProc = (WSAIOCTLPROC)GetProcAddress(libWinsock2, 
+                                                        "WSAIoctl");
+            if (wsaioctlProc)
+            {
+                socketSetCompatMode = PR_TRUE;
+            }
+        }
+    }
+}
+
+void _PR_MD_CleanupSockets(void)
+{
+    socketSetCompatMode = PR_FALSE;
+    wsaioctlProc = NULL;
+    if (libWinsock2)
+    {
+        FreeLibrary(libWinsock2);
+        libWinsock2 = NULL;
+    }
+}
 
 PRInt32
 _PR_MD_SOCKET(int af, int type, int flags)
 {
     SOCKET sock;
     u_long one = 1;
 
     sock = socket(af, type, flags);
@@ -73,16 +162,39 @@ PRInt32
     */
     if (ioctlsocket( sock, FIONBIO, &one) != 0)
     {
         PR_SetError(PR_UNKNOWN_ERROR, WSAGetLastError());
         closesocket(sock);
         return -1;
     }
 
+    if ((af == AF_INET || af == AF_INET6) && 
+        type == SOCK_STREAM && socketSetCompatMode)
+    {
+        WSA_COMPATIBILITY_MODE mode;
+        char dummy[4];
+        int ret_dummy;
+
+        mode.BehaviorId = WsaBehaviorAutoTuning;
+        mode.TargetOsVersion = NTDDI_LONGHORN;
+        if (wsaioctlProc(sock, SIO_SET_COMPATIBILITY_MODE,  
+                         (char *)&mode, sizeof(mode),
+                         dummy, 4, &ret_dummy, 0, NULL) == SOCKET_ERROR)
+        {
+            int err = WSAGetLastError();
+            PR_LOG(_pr_io_lm, PR_LOG_DEBUG, ("WSAIoctl() failed with %d", err));
+
+            /* SIO_SET_COMPATIBILITY_MODE may not be supported.
+            ** If the call to WSAIoctl() fails with WSAEOPNOTSUPP,
+            ** don't close the socket.
+            */ 
+        }
+    }
+
     return (PRInt32)sock;
 }
 
 /*
 ** _MD_CloseSocket() -- Close a socket
 **
 */
 PRInt32
--- a/pr/src/md/windows/w95thred.c
+++ b/pr/src/md/windows/w95thred.c
@@ -60,16 +60,18 @@ void
     _pr_currentCPUIndex = TlsAlloc();
 #endif
 }
 
 void _PR_MD_CLEANUP_BEFORE_EXIT(void)
 {
     _PR_NT_FreeSids();
 
+    _PR_MD_CleanupSockets();
+
     WSACleanup();
 
 #ifndef _PR_USE_STATIC_TLS
     TlsFree(_pr_currentThreadIndex);
     TlsFree(_pr_lastThreadIndex);
     TlsFree(_pr_currentCPUIndex);
 #endif
 }