OSDN Git Service

* net.cc (SIO_BASE_HANDLE): Define.
authorcorinna <corinna>
Tue, 29 Mar 2011 10:25:20 +0000 (10:25 +0000)
committercorinna <corinna>
Tue, 29 Mar 2011 10:25:20 +0000 (10:25 +0000)
(fdsock): If we got an LSP handle, try to create a copy of the base
handle instead.  Change comment to explain.

winsup/cygwin/ChangeLog
winsup/cygwin/net.cc

index 2d5739d..0c1a610 100644 (file)
@@ -1,5 +1,11 @@
 2011-03-29  Corinna Vinschen  <corinna@vinschen.de>
 
+       * net.cc (SIO_BASE_HANDLE): Define.
+       (fdsock): If we got an LSP handle, try to create a copy of the base
+       handle instead.  Change comment to explain.
+
+2011-03-29  Corinna Vinschen  <corinna@vinschen.de>
+
        * include/cygwin/version.h: Bump CYGWIN_VERSION_DLL_MINOR to 10.
 
 2011-03-29  Corinna Vinschen  <corinna@vinschen.de>
index 71423d0..c9d219d 100644 (file)
@@ -480,6 +480,10 @@ cygwin_getprotobynumber (int number)
   return dup_ent (getprotobynumber (number));
 }
 
+#ifndef SIO_BASE_HANDLE
+#define SIO_BASE_HANDLE _WSAIOR(IOC_WS2,34)
+#endif
+
 bool
 fdsock (cygheap_fdmanip& fd, const device *dev, SOCKET soc)
 {
@@ -488,50 +492,69 @@ fdsock (cygheap_fdmanip& fd, const device *dev, SOCKET soc)
   fd = build_fh_dev (*dev);
   if (!fd.isopen ())
     return false;
-  fd->set_io_handle ((HANDLE) soc);
-  if (!((fhandler_socket *) fd)->init_events ())
-    return false;
-  fd->set_flags (O_RDWR | O_BINARY);
-  fd->uninterruptible_io (true);
-  debug_printf ("fd %d, name '%s', soc %p", (int) fd, dev->name, soc);
 
   /* Usually sockets are inheritable IFS objects.  Unfortunately some virus
      scanners or other network-oriented software replace normal sockets
-     with their own kind, which is running through a filter driver.
+     with their own kind, which is running through a filter driver called
+     "layered service provider" (LSP).
+     
+     LSP sockets are not kernel objects.  They are typically not marked as
+     inheritable, nor are they IFS handles.  They are in fact not inheritable
+     to child processes, and it does not help to mark them inheritable via
+     SetHandleInformation.  Subsequent socket calls in the child process fail
+     with error 10038, WSAENOTSOCK. 
+
+     The only way up to Windows Server 2003 to make these sockets usable in
+     child processes is to duplicate them via WSADuplicateSocket/WSASocket
+     calls.  This requires to start the child process in SUSPENDED state so
+     we only do this on affected systems.  If we recognize a non-inheritable
+     socket we switch to inheritance/dup via WSADuplicateSocket/WSASocket for
+     that socket.
      
-     The result is that these new sockets are not normal kernel objects
-     anymore.  They are typically not marked as inheritable, nor are they
-     IFS handles, as normal OS sockets are.  They are in fact not inheritable
-     to child processes, and subsequent socket calls in the child process
-     will fail with error 10038, WSAENOTSOCK.  And worse, while DuplicateHandle
-     on these sockets mostly works in the process which created the socket,
-     DuplicateHandle does quite often not work anymore in a child process.
-     It does not help to mark them inheritable via SetHandleInformation.
-
-     The only way to make these sockets usable in child processes is to
-     duplicate them via WSADuplicateSocket/WSASocket calls.  This requires
-     to start the child process in SUSPENDED state so we only do this on
-     affected systems.  If we recognize a non-inheritable socket, or if
-     the XP1_IFS_HANDLES flag is not set in a call to WSADuplicateSocket,
-     we switch to inheritance/dup via WSADuplicateSocket/WSASocket for
-     that socket. */
+     Starting with Vista there's another neat way to workaround these annoying
+     LSP sockets.  WSAIoctl allows to fetch the underlying base socket, which
+     is a normal, inheritable IFS handle.  So we fetch the base socket,
+     duplicate it, and close the original socket.  Now we have a standard IFS
+     socket which (hopefully) works as expected. */
   DWORD flags;
-#if 0
-  /* Disable checking for IFS handle for now.  In theory, checking the fact
-     that the socket handle is not inheritable should be sufficient. */
-  WSAPROTOCOL_INFOW wpi;
-#endif
+  bool fixup = false;
   if (!GetHandleInformation ((HANDLE) soc, &flags)
       || !(flags & HANDLE_FLAG_INHERIT))
-#if 0
-      || WSADuplicateSocketW (soc, GetCurrentProcessId (), &wpi)
-      /* dwProviderReserved contains the actual SOCKET value of the duplicated
-        socket.  Close it or suffer a handle leak.  Worse, one socket for each
-        connection remains in CLOSE_WAIT state. */
-      || (closesocket ((SOCKET) wpi.dwProviderReserved), FALSE)
-      || !(wpi.dwServiceFlags1 & XP1_IFS_HANDLES))
-#endif
+    {
+      int ret;
+      SOCKET base_soc;
+      DWORD bret;
+
+      fixup = true;
+      debug_printf ("LSP handle: %p", soc);
+      ret = WSAIoctl (soc, SIO_BASE_HANDLE, NULL, 0, (void *) &base_soc,
+                     sizeof (base_soc), &bret, NULL, NULL);
+      if (ret)
+       debug_printf ("WSAIoctl: %lu", WSAGetLastError ());
+      else if (base_soc != soc
+              && GetHandleInformation ((HANDLE) base_soc, &flags)
+              && (flags & HANDLE_FLAG_INHERIT))
+       {
+         if (!DuplicateHandle (GetCurrentProcess (), (HANDLE) base_soc,
+                               GetCurrentProcess (), (PHANDLE) &base_soc,
+                               0, TRUE, DUPLICATE_SAME_ACCESS))
+           debug_printf ("DuplicateHandle failed, %E");
+         else
+           {
+             closesocket (soc);
+             soc = base_soc;
+             fixup = false;
+           }
+       }
+    }
+  fd->set_io_handle ((HANDLE) soc);
+  if (!((fhandler_socket *) fd)->init_events ())
+    return false;
+  if (fixup)
     ((fhandler_socket *) fd)->init_fixup_before ();
+  fd->set_flags (O_RDWR | O_BINARY);
+  fd->uninterruptible_io (true);
+  debug_printf ("fd %d, name '%s', soc %p", (int) fd, dev->name, soc);
 
   /* Raise default buffer sizes (instead of WinSock default 8K).