Cygwin: split out fhandler_socket into inet and local classes
First cut, still incomplete * fhandler_socket is now base class for other socket classes * fhandler_socket_inet handles AF_INET and AF_INET6 sockets * fhandler_socket_local handles AF_LOCAL/AF_UNIX sockets * finally get rid of fdsock by using set_socket_handle in accept4 * align file-related calls (fstat, fstatvfs, fchown, fchmod, facl) to Linux. Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
@ -500,146 +500,6 @@ 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)
|
||||
{
|
||||
fd = build_fh_dev (*dev);
|
||||
if (!fd.isopen ())
|
||||
return false;
|
||||
|
||||
/* 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 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.
|
||||
|
||||
There's a 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.
|
||||
|
||||
If that doesn't work for some reason, mark the sockets for duplication
|
||||
via WSADuplicateSocket/WSASocket. This requires to start the child
|
||||
process in SUSPENDED state so we only do this if really necessary. */
|
||||
DWORD flags;
|
||||
bool fixup = false;
|
||||
if (!GetHandleInformation ((HANDLE) soc, &flags)
|
||||
|| !(flags & HANDLE_FLAG_INHERIT))
|
||||
{
|
||||
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: %u", WSAGetLastError ());
|
||||
else if (base_soc != soc)
|
||||
{
|
||||
if (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);
|
||||
debug_printf ("fd %d, name '%s', soc %p", (int) fd, dev->name (), soc);
|
||||
|
||||
/* Raise default buffer sizes (instead of WinSock default 8K).
|
||||
|
||||
64K appear to have the best size/performance ratio for a default
|
||||
value. Tested with ssh/scp on Vista over Gigabit LAN.
|
||||
|
||||
NOTE. If the SO_RCVBUF size exceeds 65535(*), and if the socket is
|
||||
connected to a remote machine, then calling WSADuplicateSocket on
|
||||
fork/exec fails with WinSock error 10022, WSAEINVAL. Fortunately
|
||||
we don't use WSADuplicateSocket anymore, rather we just utilize
|
||||
handle inheritance. An explanation for this weird behaviour would
|
||||
be nice, though.
|
||||
|
||||
NOTE 2. Testing on x86_64 (Vista, 2008 R2, W8) indicates that
|
||||
this is no problem on 64 bit. So we set the default buffer size to
|
||||
the default values in current 3.x Linux versions.
|
||||
|
||||
NOTE 3. Setting the window size to 65535 results in extremely bad
|
||||
performance for apps that send data in multiples of Kb, as they
|
||||
eventually end up sending 1 byte on the network and naggle + delay
|
||||
ack kicks in. For example, iperf on a 10Gb network gives only 10
|
||||
Mbits/sec with a 65535 send buffer. We want this to be a multiple
|
||||
of 1k, but since 64k breaks WSADuplicateSocket we use 63Kb.
|
||||
|
||||
NOTE 4. Tests with iperf uncover a problem in setting the SO_RCVBUF
|
||||
and SO_SNDBUF sizes. Windows is using autotuning since Windows Vista.
|
||||
Manually setting SO_RCVBUF/SO_SNDBUF disables autotuning and leads to
|
||||
inferior send/recv performance in scenarios with larger RTTs, as is
|
||||
basically standard when accessing the internet. For a discussion,
|
||||
see https://cygwin.com/ml/cygwin-patches/2017-q1/msg00010.html.
|
||||
|
||||
(*) Maximum normal TCP window size. Coincidence? */
|
||||
#ifdef __x86_64__
|
||||
((fhandler_socket *) fd)->rmem () = 212992;
|
||||
((fhandler_socket *) fd)->wmem () = 212992;
|
||||
#else
|
||||
((fhandler_socket *) fd)->rmem () = 64512;
|
||||
((fhandler_socket *) fd)->wmem () = 64512;
|
||||
#endif
|
||||
#if 0 /* See NOTE 4 above. */
|
||||
int size;
|
||||
|
||||
if (::setsockopt (soc, SOL_SOCKET, SO_RCVBUF,
|
||||
(char *) &((fhandler_socket *) fd)->rmem (), sizeof (int)))
|
||||
{
|
||||
debug_printf ("setsockopt(SO_RCVBUF) failed, %u", WSAGetLastError ());
|
||||
if (::getsockopt (soc, SOL_SOCKET, SO_RCVBUF,
|
||||
(char *) &((fhandler_socket *) fd)->rmem (),
|
||||
(size = sizeof (int), &size)))
|
||||
system_printf ("getsockopt(SO_RCVBUF) failed, %u", WSAGetLastError ());
|
||||
}
|
||||
if (::setsockopt (soc, SOL_SOCKET, SO_SNDBUF,
|
||||
(char *) &((fhandler_socket *) fd)->wmem (), sizeof (int)))
|
||||
{
|
||||
debug_printf ("setsockopt(SO_SNDBUF) failed, %u", WSAGetLastError ());
|
||||
if (::getsockopt (soc, SOL_SOCKET, SO_SNDBUF,
|
||||
(char *) &((fhandler_socket *) fd)->wmem (),
|
||||
(size = sizeof (int), &size)))
|
||||
system_printf ("getsockopt(SO_SNDBUF) failed, %u", WSAGetLastError ());
|
||||
}
|
||||
#endif
|
||||
/* A unique ID is necessary to recognize fhandler entries which are
|
||||
duplicated by dup(2) or fork(2). This is used in BSD flock calls
|
||||
to identify the descriptor. */
|
||||
((fhandler_socket *) fd)->set_unique_id ();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* exported as socket: POSIX.1-2001, POSIX.1-2008, 4.4BSD */
|
||||
extern "C" int
|
||||
cygwin_socket (int af, int type, int protocol)
|
||||
|
Reference in New Issue
Block a user