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:
Corinna Vinschen
2018-02-21 21:40:01 +01:00
parent dff3bc9a86
commit 859d215b7e
10 changed files with 3293 additions and 2218 deletions

View File

@ -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)