Reintegrate socket duplication via WSADuplicateSocket/WSASocket.

* autoload.cc (WSADuplicateSocketW): Define.
	(WSASocketW): Define.
	* dtable.cc (dtable::release): Call dec_need_fixup_before if necessary.
	(dtable::fixup_before_fork): New function.
	(dtable::fixup_before_exec): New function.
	* dtable.h (class dtable): Add member cnt_need_fixup_before.  Add
	declarations for above new functions.
	(dtable::dec_need_fixup_before): New inline method.
	(dtable::inc_need_fixup_before): New inline method.
	(dtable::need_fixup_before): New inline method.
	* fhandler.h (fhandler_base::fixup_before_fork_exec): New virtual
	method.
	(fhandler_base::need_fixup_before): New virtual method.
	(class fhandler_socket): Add member prot_info_ptr.
	(fhandler_socket::init_fixup_before): Declare.
	(fhandler_socket::need_fixup_before): New inline method.
	(fhandler_socket::fixup_before_fork_exec): Declare.
	(fhandler_socket::fixup_after_exec): Declare.
	* fhandler_socket.cc (fhandler_socket::fhandler_socket): Initialize
	prot_info_ptr to NULL.
	(fhandler_socket::~fhandler_socket): Free prot_info_ptr conditionally.
	(fhandler_socket::init_fixup_before): New method.
	(fhandler_socket::fixup_before_fork_exec): Ditto.
	(fhandler_socket::fixup_after_fork): Use WSASocketW to duplicate
	socket if necessary.
	(fhandler_socket::fixup_after_exec): New method.
	(fhandler_socket::dup): Use fixup_before_fork_exec/fixup_after_fork
	to duplicate socket if necessary.
	* fork.cc (frok::parent): Start child suspended if some fhandler
	needs fixup before fork.  If so, call dtable::fixup_before_fork after
	CreateProcess and resume child.
	* net.cc (fdsock): Try to find out if socket needs fixup before and
	initialize socket accordingly.  Add HUGE comment to explain what happens
	and why.
	* spawn.cc (spawn_guts): Start child suspended if some fhandler needs
	fixup before exec.  If so, call dtable::fixup_before_exec after
	CreateProcess.
This commit is contained in:
Corinna Vinschen
2009-11-17 10:43:01 +00:00
parent 88242190ec
commit b14f53a8ec
9 changed files with 221 additions and 8 deletions

View File

@ -495,6 +495,34 @@ fdsock (cygheap_fdmanip& fd, const device *dev, SOCKET soc)
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.
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
some incredible amount of extra processing 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. */
DWORD flags;
WSAPROTOCOL_INFOW wpi;
if (!GetHandleInformation ((HANDLE) soc, &flags)
|| !(flags & HANDLE_FLAG_INHERIT)
|| WSADuplicateSocketW (soc, GetCurrentProcessId (), &wpi)
|| !(wpi.dwServiceFlags1 & XP1_IFS_HANDLES))
((fhandler_socket *) fd)->init_fixup_before ();
/* Raise default buffer sizes (instead of WinSock default 8K).
64K appear to have the best size/performance ratio for a default