* 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:
parent
b8fe0ec799
commit
a011f95216
|
@ -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>
|
||||
|
||||
* include/cygwin/version.h: Bump CYGWIN_VERSION_DLL_MINOR to 10.
|
||||
|
|
|
@ -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).
|
||||
|
||||
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.
|
||||
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 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. */
|
||||
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.
|
||||
|
||||
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).
|
||||
|
||||
|
|
Loading…
Reference in New Issue