Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2018-02-15 00:21:58 +0300
committerCorinna Vinschen <corinna@vinschen.de>2018-02-15 00:21:58 +0300
commit913c6ca2c1467893bb0c3b7598cccdb02ca9f598 (patch)
tree635714e3c9a2365bffa324fb8c44b11812a41857 /winsup/cygwin
parent7ae73be14194ccadc9a7557be33c3940ca4667cb (diff)
Cygwin: socket: move socket creation inside fhandler_socket class
Add fhandler_socket::socket method Add fhandler_socket::set_socket_handle method, basically duplicating what fdsock is doing. This is the first step in getting rid of fdsock. Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Diffstat (limited to 'winsup/cygwin')
-rw-r--r--winsup/cygwin/fhandler.h5
-rw-r--r--winsup/cygwin/fhandler_socket.cc117
-rw-r--r--winsup/cygwin/net.cc90
3 files changed, 166 insertions, 46 deletions
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 9d2b26342..e1659db5a 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -556,6 +556,10 @@ class fhandler_socket: public fhandler_base
{}
} status;
+#ifdef __INSIDE_CYGWIN_NET__
+ int set_socket_handle (SOCKET sock);
+#endif
+
public:
fhandler_socket ();
~fhandler_socket ();
@@ -576,6 +580,7 @@ class fhandler_socket: public fhandler_base
IMPLEMENT_STATUS_FLAG (conn_state, connect_state)
IMPLEMENT_STATUS_FLAG (bool, no_getpeereid)
+ int socket (int af, int type, int protocol, int flags);
int bind (const struct sockaddr *name, int namelen);
int connect (const struct sockaddr *name, int namelen);
int listen (int backlog);
diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc
index 2d043bded..a30b49511 100644
--- a/winsup/cygwin/fhandler_socket.cc
+++ b/winsup/cygwin/fhandler_socket.cc
@@ -262,6 +262,120 @@ fhandler_socket::open (int flags, mode_t mode)
return 0;
}
+int
+fhandler_socket::set_socket_handle (SOCKET sock)
+{
+ DWORD flags;
+ bool lsp_fixup = 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) which, fortunately, are deprecated.
+
+ 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. */
+ if (!GetHandleInformation ((HANDLE) sock, &flags)
+ || !(flags & HANDLE_FLAG_INHERIT))
+ {
+ int ret;
+ SOCKET base_sock;
+ DWORD bret;
+
+ lsp_fixup = true;
+ debug_printf ("LSP handle: %p", sock);
+ ret = WSAIoctl (sock, SIO_BASE_HANDLE, NULL, 0, (void *) &base_sock,
+ sizeof (base_sock), &bret, NULL, NULL);
+ if (ret)
+ debug_printf ("WSAIoctl: %u", WSAGetLastError ());
+ else if (base_sock != sock)
+ {
+ if (GetHandleInformation ((HANDLE) base_sock, &flags)
+ && (flags & HANDLE_FLAG_INHERIT))
+ {
+ if (!DuplicateHandle (GetCurrentProcess (), (HANDLE) base_sock,
+ GetCurrentProcess (), (PHANDLE) &base_sock,
+ 0, TRUE, DUPLICATE_SAME_ACCESS))
+ debug_printf ("DuplicateHandle failed, %E");
+ else
+ {
+ closesocket (sock);
+ sock = base_sock;
+ lsp_fixup = false;
+ }
+ }
+ }
+ }
+ set_io_handle ((HANDLE) sock);
+ if (!init_events ())
+ {
+ closesocket (sock);
+ return -1;
+ }
+ if (lsp_fixup)
+ init_fixup_before ();
+ set_flags (O_RDWR | O_BINARY);
+ set_unique_id ();
+ if (get_socket_type () == SOCK_DGRAM)
+ {
+ /* Workaround the problem that a missing listener on a UDP socket
+ in a call to sendto will result in select/WSAEnumNetworkEvents
+ reporting that the socket has pending data and a subsequent call
+ to recvfrom will return -1 with error set to WSAECONNRESET.
+
+ This problem is a regression introduced in Windows 2000.
+ Instead of fixing the problem, a new socket IOCTL code has
+ been added, see http://support.microsoft.com/kb/263823 */
+ BOOL cr = FALSE;
+ DWORD blen;
+ if (WSAIoctl (sock, SIO_UDP_CONNRESET, &cr, sizeof cr, NULL, 0,
+ &blen, NULL, NULL) == SOCKET_ERROR)
+ debug_printf ("Reset SIO_UDP_CONNRESET: WinSock error %u",
+ WSAGetLastError ());
+ }
+#ifdef __x86_64__
+ rmem () = 212992;
+ wmem () = 212992;
+#else
+ rmem () = 64512;
+ wmem () = 64512;
+#endif
+ return 0;
+}
+
+int
+fhandler_socket::socket (int af, int type, int protocol, int flags)
+{
+ SOCKET sock;
+
+ sock = ::socket (af == AF_LOCAL ? AF_INET : af, type, protocol);
+ if (sock == INVALID_SOCKET)
+ {
+ set_winsock_errno ();
+ return -1;
+ }
+ set_addr_family (af);
+ set_socket_type (type);
+ if (flags & SOCK_NONBLOCK)
+ set_nonblocking (true);
+ if (flags & SOCK_CLOEXEC)
+ set_close_on_exec (true);
+ return set_socket_handle (sock);
+}
+
void
fhandler_socket::af_local_set_sockpair_cred ()
{
@@ -635,6 +749,9 @@ fhandler_socket::init_events ()
}
/* sock type not yet set here. */
+ /* FIXME: as soon as we switch to socket method, we're good to use
+ get_socket_type (). */
+
if (pc.dev == FH_UDP || pc.dev == FH_DGRAM)
wsock_events->events = FD_WRITE;
return true;
diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc
index c7bd73611..8497d5944 100644
--- a/winsup/cygwin/net.cc
+++ b/winsup/cygwin/net.cc
@@ -655,67 +655,65 @@ extern "C" int
cygwin_socket (int af, int type, int protocol)
{
int res = -1;
- SOCKET soc = 0;
+ const device *dev;
+ fhandler_socket *fh;
int flags = type & _SOCK_FLAG_MASK;
type &= ~_SOCK_FLAG_MASK;
debug_printf ("socket (%d, %d (flags %y), %d)", af, type, flags, protocol);
- if ((flags & ~(SOCK_NONBLOCK | SOCK_CLOEXEC)) != 0)
+ switch (af)
{
- set_errno (EINVAL);
+ case AF_LOCAL:
+ if (type != SOCK_STREAM && type != SOCK_DGRAM)
+ {
+ set_errno (EINVAL);
+ goto done;
+ }
+ if (protocol != 0)
+ {
+ set_errno (EPROTONOSUPPORT);
+ goto done;
+ }
+ dev = type == SOCK_STREAM ? stream_dev : dgram_dev;
+ break;
+ case AF_INET:
+ case AF_INET6:
+ if (type != SOCK_STREAM && type != SOCK_DGRAM && type != SOCK_RAW)
+ {
+ set_errno (EINVAL);
+ goto done;
+ }
+ dev = type == SOCK_STREAM ? tcp_dev : udp_dev;
+ break;
+ default:
+ set_errno (EAFNOSUPPORT);
goto done;
}
- soc = socket (af == AF_LOCAL ? AF_INET : af, type,
- af == AF_LOCAL ? 0 : protocol);
-
- if (soc == INVALID_SOCKET)
+ if ((flags & ~(SOCK_NONBLOCK | SOCK_CLOEXEC)) != 0)
{
- set_winsock_errno ();
+ set_errno (EINVAL);
goto done;
}
- const device *dev;
-
- if (af == AF_LOCAL)
- dev = type == SOCK_STREAM ? stream_dev : dgram_dev;
- else
- dev = type == SOCK_STREAM ? tcp_dev : udp_dev;
+ {
+ cygheap_fdnew fd;
- {
- cygheap_fdnew fd;
- if (fd < 0 || !fdsock (fd, dev, soc))
- closesocket (soc);
- else
- {
- ((fhandler_socket *) fd)->set_addr_family (af);
- ((fhandler_socket *) fd)->set_socket_type (type);
- if (flags & SOCK_NONBLOCK)
- ((fhandler_socket *) fd)->set_nonblocking (true);
- if (flags & SOCK_CLOEXEC)
- ((fhandler_socket *) fd)->set_close_on_exec (true);
- if (type == SOCK_DGRAM)
- {
- /* Workaround the problem that a missing listener on a UDP socket
- in a call to sendto will result in select/WSAEnumNetworkEvents
- reporting that the socket has pending data and a subsequent call
- to recvfrom will return -1 with error set to WSAECONNRESET.
-
- This problem is a regression introduced in Windows 2000.
- Instead of fixing the problem, a new socket IOCTL code has
- been added, see http://support.microsoft.com/kb/263823 */
- BOOL cr = FALSE;
- DWORD blen;
- if (WSAIoctl (soc, SIO_UDP_CONNRESET, &cr, sizeof cr, NULL, 0,
- &blen, NULL, NULL) == SOCKET_ERROR)
- debug_printf ("Reset SIO_UDP_CONNRESET: WinSock error %u",
- WSAGetLastError ());
- }
- res = fd;
- }
- }
+ if (fd < 0)
+ goto done;
+ fh = (fhandler_socket *) build_fh_dev (*dev);
+ if (fh && fh->socket (af, type, protocol, flags) == 0)
+ {
+ fd = fh;
+ if (fd <= 2)
+ set_std_handle (fd);
+ res = fd;
+ }
+ else
+ fd.release ();
+ }
done:
syscall_printf ("%R = socket(%d, %d (flags %y), %d)",