* 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.
This commit is contained in:
Corinna Vinschen 2011-03-29 10:25:20 +00:00
parent b8fe0ec799
commit a011f95216
2 changed files with 64 additions and 35 deletions

View File

@ -1,3 +1,9 @@
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> 2011-03-29 Corinna Vinschen <corinna@vinschen.de>
* include/cygwin/version.h: Bump CYGWIN_VERSION_DLL_MINOR to 10. * include/cygwin/version.h: Bump CYGWIN_VERSION_DLL_MINOR to 10.

View File

@ -480,6 +480,10 @@ cygwin_getprotobynumber (int number)
return dup_ent (getprotobynumber (number)); return dup_ent (getprotobynumber (number));
} }
#ifndef SIO_BASE_HANDLE
#define SIO_BASE_HANDLE _WSAIOR(IOC_WS2,34)
#endif
bool bool
fdsock (cygheap_fdmanip& fd, const device *dev, SOCKET soc) 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); fd = build_fh_dev (*dev);
if (!fd.isopen ()) if (!fd.isopen ())
return false; 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 /* Usually sockets are inheritable IFS objects. Unfortunately some virus
scanners or other network-oriented software replace normal sockets 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).
The result is that these new sockets are not normal kernel objects LSP sockets are not kernel objects. They are typically not marked as
anymore. They are typically not marked as inheritable, nor are they inheritable, nor are they IFS handles. They are in fact not inheritable
IFS handles, as normal OS sockets are. They are in fact not inheritable to child processes, and it does not help to mark them inheritable via
to child processes, and subsequent socket calls in the child process SetHandleInformation. Subsequent socket calls in the child process fail
will fail with error 10038, WSAENOTSOCK. And worse, while DuplicateHandle with error 10038, WSAENOTSOCK.
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 The only way up to Windows Server 2003 to make these sockets usable in
duplicate them via WSADuplicateSocket/WSASocket calls. This requires child processes is to duplicate them via WSADuplicateSocket/WSASocket
to start the child process in SUSPENDED state so we only do this on calls. This requires to start the child process in SUSPENDED state so
affected systems. If we recognize a non-inheritable socket, or if we only do this on affected systems. If we recognize a non-inheritable
the XP1_IFS_HANDLES flag is not set in a call to WSADuplicateSocket, socket we switch to inheritance/dup via WSADuplicateSocket/WSASocket for
we switch to inheritance/dup via WSADuplicateSocket/WSASocket for that socket.
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; DWORD flags;
#if 0 bool fixup = false;
/* 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
if (!GetHandleInformation ((HANDLE) soc, &flags) if (!GetHandleInformation ((HANDLE) soc, &flags)
|| !(flags & HANDLE_FLAG_INHERIT)) || !(flags & HANDLE_FLAG_INHERIT))
#if 0 {
|| WSADuplicateSocketW (soc, GetCurrentProcessId (), &wpi) int ret;
/* dwProviderReserved contains the actual SOCKET value of the duplicated SOCKET base_soc;
socket. Close it or suffer a handle leak. Worse, one socket for each DWORD bret;
connection remains in CLOSE_WAIT state. */
|| (closesocket ((SOCKET) wpi.dwProviderReserved), FALSE) fixup = true;
|| !(wpi.dwServiceFlags1 & XP1_IFS_HANDLES)) debug_printf ("LSP handle: %p", soc);
#endif 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 (); ((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). /* Raise default buffer sizes (instead of WinSock default 8K).