From b79018ee3a36140a82e2dfa2d7a71fc0bf15d892 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Fri, 23 Feb 2018 15:24:18 +0100 Subject: [PATCH] Cygwin: encapsulate Winsock based fhandler_socket classes Insert another class fhandler_socket_wsock between fhandler_socket and fhandler_socket_inet/fhandler_socket_local. Also, add a new method fhandler::is_wsock_socket to allow asking for sockets in general (is_socket) vs. Winsock-based sockets (is_wsock_socket). This allows to develop a new handler_socket_unix class as derived class from fhandler_socket without any trace of wsock code left in fhandler_socket. While this is basically a temporary measure at this time, it may prove useful for later interoperability with the upcoming Windows 10 AF_UNIX implementation at one point. Signed-off-by: Corinna Vinschen --- winsup/cygwin/fhandler.cc | 2 +- winsup/cygwin/fhandler.h | 194 ++++---- winsup/cygwin/fhandler_socket.cc | 559 ----------------------- winsup/cygwin/fhandler_socket_inet.cc | 607 ++++++++++++++++++++++++- winsup/cygwin/fhandler_socket_local.cc | 427 +---------------- winsup/cygwin/net.cc | 3 +- winsup/cygwin/poll.cc | 6 +- winsup/cygwin/select.cc | 70 +-- 8 files changed, 711 insertions(+), 1157 deletions(-) diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc index 086be7311..93bbdfed2 100644 --- a/winsup/cygwin/fhandler.cc +++ b/winsup/cygwin/fhandler.cc @@ -1567,7 +1567,7 @@ fhandler_base::fork_fixup (HANDLE parent, HANDLE &h, const char *name) { HANDLE oh = h; bool res = false; - if (/* !is_socket () && */ !close_on_exec ()) + if (!close_on_exec ()) debug_printf ("handle %p already opened", h); else if (!DuplicateHandle (parent, h, GetCurrentProcess (), &h, 0, !close_on_exec (), DUPLICATE_SAME_ACCESS)) diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 4c7fea3e3..3816110a0 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -406,6 +406,7 @@ public: virtual bool isfifo () const { return false; } virtual int ptsname_r (char *, size_t); virtual class fhandler_socket *is_socket () { return NULL; } + virtual class fhandler_socket_wsock *is_wsock_socket () { return NULL; } virtual class fhandler_console *is_console () { return 0; } virtual int is_windows () {return 0; } @@ -488,7 +489,6 @@ class fhandler_socket: public fhandler_base protected: int addr_family; int type; - virtual int af_local_connect () = 0; inline int get_socket_flags () { int ret = 0; @@ -499,18 +499,6 @@ class fhandler_socket: public fhandler_base return ret; } - protected: - wsa_event *wsock_events; - HANDLE wsock_mtx; - HANDLE wsock_evt; - bool init_events (); - int wait_for_events (const long event_mask, const DWORD flags); - void release_events (); - public: - const HANDLE wsock_event () const { return wsock_evt; } - int evaluate_events (const long event_mask, long &events, const bool erase); - const LONG serial_number () const { return wsock_events->serial_number; } - protected: int _rmem; int _wmem; @@ -527,56 +515,30 @@ class fhandler_socket: public fhandler_base DWORD &rcvtimeo () { return _rcvtimeo; } DWORD &sndtimeo () { return _sndtimeo; } - protected: - struct _WSAPROTOCOL_INFOW *prot_info_ptr; - protected: struct status_flags { unsigned async_io : 1; /* async I/O */ unsigned saw_shutdown_read : 1; /* Socket saw a SHUT_RD */ unsigned saw_shutdown_write : 1; /* Socket saw a SHUT_WR */ - unsigned saw_reuseaddr : 1; /* Socket saw SO_REUSEADDR call */ unsigned connect_state : 3; - unsigned no_getpeereid : 1; public: status_flags () : async_io (0), saw_shutdown_read (0), saw_shutdown_write (0), - connect_state (unconnected), no_getpeereid (0) + connect_state (unconnected) {} } status; - -#ifdef __INSIDE_CYGWIN_NET__ - int set_socket_handle (SOCKET sock, int af, int type, int flags); -#endif + public: + IMPLEMENT_STATUS_FLAG (bool, async_io) + IMPLEMENT_STATUS_FLAG (bool, saw_shutdown_read) + IMPLEMENT_STATUS_FLAG (bool, saw_shutdown_write) + IMPLEMENT_STATUS_FLAG (conn_state, connect_state) public: fhandler_socket (); ~fhandler_socket (); -/* Originally get_socket returned an int, which is not a good idea - to cast a handle to on 64 bit. The right type here is very certainly - SOCKET instead. On the other hand, we don't want to have to include - winsock.h just to build fhandler.h. Therefore we define get_socket - now only when building network related code. */ -#ifdef __INSIDE_CYGWIN_NET__ - SOCKET get_socket () { return (SOCKET) get_handle(); } -#endif fhandler_socket *is_socket () { return this; } - IMPLEMENT_STATUS_FLAG (bool, async_io) - IMPLEMENT_STATUS_FLAG (bool, saw_shutdown_read) - IMPLEMENT_STATUS_FLAG (bool, saw_shutdown_write) - IMPLEMENT_STATUS_FLAG (bool, saw_reuseaddr) - IMPLEMENT_STATUS_FLAG (conn_state, connect_state) - IMPLEMENT_STATUS_FLAG (bool, no_getpeereid) - - bool need_fixup_before () const {return prot_info_ptr != NULL;} - void set_close_on_exec (bool val); - void init_fixup_before (); - int fixup_before_fork_exec (DWORD); - void fixup_after_fork (HANDLE); - void fixup_after_exec (); - int dup (fhandler_base *child, int); char *get_proc_fd_name (char *buf); virtual int socket (int af, int type, int protocol, int flags) = 0; @@ -633,14 +595,96 @@ class fhandler_socket: public fhandler_base virtual select_record *select_except (select_stuff *) = 0; }; -class fhandler_socket_inet: public fhandler_socket +/* Encapsulate wsock-based socket classes fhandler_socket_inet and + fhandler_socket_local during development of fhandler_socket_unix. + TODO: Perhaps we should keep it that way, under the assumption that + the Windows 10 AF_UNIX class will eventually get useful at one point. */ +class fhandler_socket_wsock: public fhandler_socket +{ + protected: + virtual int af_local_connect () = 0; + + protected: + wsa_event *wsock_events; + HANDLE wsock_mtx; + HANDLE wsock_evt; + bool init_events (); + int wait_for_events (const long event_mask, const DWORD flags); + void release_events (); + public: + const HANDLE wsock_event () const { return wsock_evt; } + int evaluate_events (const long event_mask, long &events, const bool erase); + const LONG serial_number () const { return wsock_events->serial_number; } + + protected: + struct _WSAPROTOCOL_INFOW *prot_info_ptr; + public: + bool need_fixup_before () const {return prot_info_ptr != NULL;} + void set_close_on_exec (bool val); + void init_fixup_before (); + int fixup_before_fork_exec (DWORD); + void fixup_after_fork (HANDLE); + void fixup_after_exec (); + int dup (fhandler_base *child, int); + +#ifdef __INSIDE_CYGWIN_NET__ + protected: + int set_socket_handle (SOCKET sock, int af, int type, int flags); + public: + /* Originally get_socket returned an int, which is not a good idea + to cast a handle to on 64 bit. The right type here is very certainly + SOCKET instead. On the other hand, we don't want to have to include + winsock.h just to build fhandler.h. Therefore we define get_socket + now only when building network related code. */ + SOCKET get_socket () { return (SOCKET) get_handle(); } +#endif + + protected: + struct status_flags + { + unsigned saw_reuseaddr : 1; /* Socket saw SO_REUSEADDR call */ + public: + status_flags () : saw_reuseaddr (0) {} + } status; + public: + IMPLEMENT_STATUS_FLAG (bool, saw_reuseaddr) + + protected: + virtual ssize_t recv_internal (struct _WSAMSG *wsamsg, bool use_recvmsg) = 0; + ssize_t send_internal (struct _WSAMSG *wsamsg, int flags); + + public: + fhandler_socket_wsock (); + ~fhandler_socket_wsock (); + + fhandler_socket_wsock *is_wsock_socket () { return this; } + + ssize_t recvfrom (void *ptr, size_t len, int flags, + struct sockaddr *from, int *fromlen); + ssize_t recvmsg (struct msghdr *msg, int flags); + void __reg3 read (void *ptr, size_t& len); + ssize_t __stdcall readv (const struct iovec *, int iovcnt, ssize_t tot = -1); + ssize_t __stdcall write (const void *ptr, size_t len); + ssize_t __stdcall writev (const struct iovec *, int iovcnt, ssize_t tot = -1); + int shutdown (int how); + int close (); + + int ioctl (unsigned int cmd, void *); + int fcntl (int cmd, intptr_t); + + /* select.cc */ + select_record *select_read (select_stuff *); + select_record *select_write (select_stuff *); + select_record *select_except (select_stuff *); +}; + +class fhandler_socket_inet: public fhandler_socket_wsock { protected: int af_local_connect () { return 0; } - private: - inline ssize_t recv_internal (struct _WSAMSG *wsamsg, bool use_recvmsg); - inline ssize_t send_internal (struct _WSAMSG *wsamsg, int flags); + protected: + ssize_t recv_internal (struct _WSAMSG *wsamsg, bool use_recvmsg); public: fhandler_socket_inet (); @@ -653,31 +697,14 @@ class fhandler_socket_inet: public fhandler_socket int connect (const struct sockaddr *name, int namelen); int getsockname (struct sockaddr *name, int *namelen); int getpeername (struct sockaddr *name, int *namelen); - int shutdown (int how); - int close (); - ssize_t recvfrom (void *ptr, size_t len, int flags, - struct sockaddr *from, int *fromlen); - ssize_t recvmsg (struct msghdr *msg, int flags); - void __reg3 read (void *ptr, size_t& len); - ssize_t __stdcall readv (const struct iovec *, int iovcnt, ssize_t tot = -1); ssize_t sendto (const void *ptr, size_t len, int flags, const struct sockaddr *to, int tolen); ssize_t sendmsg (const struct msghdr *msg, int flags); - ssize_t __stdcall write (const void *ptr, size_t len); - ssize_t __stdcall writev (const struct iovec *, int iovcnt, ssize_t tot = -1); int setsockopt (int level, int optname, const void *optval, __socklen_t optlen); int getsockopt (int level, int optname, const void *optval, __socklen_t *optlen); - int ioctl (unsigned int cmd, void *); - int fcntl (int cmd, intptr_t); - - /* select.cc */ - select_record *select_read (select_stuff *); - select_record *select_write (select_stuff *); - select_record *select_except (select_stuff *); - /* from here on: CLONING */ fhandler_socket_inet (void *) {} @@ -697,7 +724,7 @@ class fhandler_socket_inet: public fhandler_socket } }; -class fhandler_socket_local: public fhandler_socket +class fhandler_socket_local: public fhandler_socket_wsock { protected: char *sun_path; @@ -729,9 +756,18 @@ class fhandler_socket_local: public fhandler_socket int af_local_set_no_getpeereid (); void af_local_set_sockpair_cred (); - private: - inline ssize_t recv_internal (struct _WSAMSG *wsamsg, bool use_recvmsg); - inline ssize_t send_internal (struct _WSAMSG *wsamsg, int flags); + protected: + ssize_t recv_internal (struct _WSAMSG *wsamsg, bool use_recvmsg); + + protected: + struct status_flags + { + unsigned no_getpeereid : 1; + public: + status_flags () : no_getpeereid (0) {} + } status; + public: + IMPLEMENT_STATUS_FLAG (bool, no_getpeereid) public: fhandler_socket_local (); @@ -748,27 +784,15 @@ class fhandler_socket_local: public fhandler_socket int connect (const struct sockaddr *name, int namelen); int getsockname (struct sockaddr *name, int *namelen); int getpeername (struct sockaddr *name, int *namelen); - int shutdown (int how); - int close (); int getpeereid (pid_t *pid, uid_t *euid, gid_t *egid); - ssize_t recvfrom (void *ptr, size_t len, int flags, - struct sockaddr *from, int *fromlen); - ssize_t recvmsg (struct msghdr *msg, int flags); - void __reg3 read (void *ptr, size_t& len); - ssize_t __stdcall readv (const struct iovec *, int iovcnt, ssize_t tot = -1); ssize_t sendto (const void *ptr, size_t len, int flags, const struct sockaddr *to, int tolen); ssize_t sendmsg (const struct msghdr *msg, int flags); - ssize_t __stdcall write (const void *ptr, size_t len); - ssize_t __stdcall writev (const struct iovec *, int iovcnt, ssize_t tot = -1); int setsockopt (int level, int optname, const void *optval, __socklen_t optlen); int getsockopt (int level, int optname, const void *optval, __socklen_t *optlen); - int ioctl (unsigned int cmd, void *); - int fcntl (int cmd, intptr_t); - int __reg2 fstat (struct stat *buf); int __reg2 fstatvfs (struct statvfs *buf); int __reg1 fchmod (mode_t newmode); @@ -776,11 +800,6 @@ class fhandler_socket_local: public fhandler_socket int __reg3 facl (int, int, struct acl *); int __reg2 link (const char *); - /* select.cc */ - select_record *select_read (select_stuff *); - select_record *select_write (select_stuff *); - select_record *select_except (select_stuff *); - /* from here on: CLONING */ fhandler_socket_local (void *) {} @@ -2357,7 +2376,6 @@ typedef union char __pty_master[sizeof (fhandler_pty_master)]; char __registry[sizeof (fhandler_registry)]; char __serial[sizeof (fhandler_serial)]; - char __socket[sizeof (fhandler_socket)]; char __socket_inet[sizeof (fhandler_socket_inet)]; char __socket_local[sizeof (fhandler_socket_local)]; char __termios[sizeof (fhandler_termios)]; diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc index 0cdf6fa69..292e648c8 100644 --- a/winsup/cygwin/fhandler_socket.cc +++ b/winsup/cygwin/fhandler_socket.cc @@ -60,573 +60,14 @@ fhandler_socket::fhandler_socket () : uid (myself->uid), gid (myself->gid), mode (S_IFSOCK | S_IRWXU | S_IRWXG | S_IRWXO), - wsock_events (NULL), - wsock_mtx (NULL), - wsock_evt (NULL), _rcvtimeo (INFINITE), _sndtimeo (INFINITE), - prot_info_ptr (NULL), status () { - need_fork_fixup (true); } fhandler_socket::~fhandler_socket () { - if (prot_info_ptr) - cfree (prot_info_ptr); -} - -int -fhandler_socket::set_socket_handle (SOCKET sock, int af, int type, int flags) -{ - DWORD hdl_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, &hdl_flags) - || !(hdl_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, &hdl_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_addr_family (af); - set_socket_type (type); - if (flags & SOCK_NONBLOCK) - set_nonblocking (true); - if (flags & SOCK_CLOEXEC) - set_close_on_exec (true); - set_io_handle ((HANDLE) sock); - if (!init_events ()) - 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; -} - -/* Maximum number of concurrently opened sockets from all Cygwin processes - per session. Note that shared sockets (through dup/fork/exec) are - counted as one socket. */ -#define NUM_SOCKS 2048U - -#define LOCK_EVENTS \ - if (wsock_mtx && \ - WaitForSingleObject (wsock_mtx, INFINITE) != WAIT_FAILED) \ - { - -#define UNLOCK_EVENTS \ - ReleaseMutex (wsock_mtx); \ - } - -static wsa_event wsa_events[NUM_SOCKS] __attribute__((section (".cygwin_dll_common"), shared)); - -static LONG socket_serial_number __attribute__((section (".cygwin_dll_common"), shared)); - -static HANDLE wsa_slot_mtx; - -static PWCHAR -sock_shared_name (PWCHAR buf, LONG num) -{ - __small_swprintf (buf, L"socket.%d", num); - return buf; -} - -static wsa_event * -search_wsa_event_slot (LONG new_serial_number) -{ - WCHAR name[32], searchname[32]; - UNICODE_STRING uname; - OBJECT_ATTRIBUTES attr; - NTSTATUS status; - - if (!wsa_slot_mtx) - { - RtlInitUnicodeString (&uname, sock_shared_name (name, 0)); - InitializeObjectAttributes (&attr, &uname, OBJ_INHERIT | OBJ_OPENIF, - get_session_parent_dir (), - everyone_sd (CYG_MUTANT_ACCESS)); - status = NtCreateMutant (&wsa_slot_mtx, CYG_MUTANT_ACCESS, &attr, FALSE); - if (!NT_SUCCESS (status)) - api_fatal ("Couldn't create/open shared socket mutex %S, %y", - &uname, status); - } - switch (WaitForSingleObject (wsa_slot_mtx, INFINITE)) - { - case WAIT_OBJECT_0: - case WAIT_ABANDONED: - break; - default: - api_fatal ("WFSO failed for shared socket mutex, %E"); - break; - } - unsigned int slot = new_serial_number % NUM_SOCKS; - while (wsa_events[slot].serial_number) - { - HANDLE searchmtx; - RtlInitUnicodeString (&uname, sock_shared_name (searchname, - wsa_events[slot].serial_number)); - InitializeObjectAttributes (&attr, &uname, 0, get_session_parent_dir (), - NULL); - status = NtOpenMutant (&searchmtx, READ_CONTROL, &attr); - if (!NT_SUCCESS (status)) - break; - /* Mutex still exists, attached socket is active, try next slot. */ - NtClose (searchmtx); - slot = (slot + 1) % NUM_SOCKS; - if (slot == (new_serial_number % NUM_SOCKS)) - { - /* Did the whole array once. Too bad. */ - debug_printf ("No free socket slot"); - ReleaseMutex (wsa_slot_mtx); - return NULL; - } - } - memset (&wsa_events[slot], 0, sizeof (wsa_event)); - wsa_events[slot].serial_number = new_serial_number; - ReleaseMutex (wsa_slot_mtx); - return wsa_events + slot; -} - -bool -fhandler_socket::init_events () -{ - LONG new_serial_number; - WCHAR name[32]; - UNICODE_STRING uname; - OBJECT_ATTRIBUTES attr; - NTSTATUS status; - - do - { - new_serial_number = - InterlockedIncrement (&socket_serial_number); - if (!new_serial_number) /* 0 is reserved for global mutex */ - InterlockedIncrement (&socket_serial_number); - set_ino (new_serial_number); - RtlInitUnicodeString (&uname, sock_shared_name (name, new_serial_number)); - InitializeObjectAttributes (&attr, &uname, OBJ_INHERIT | OBJ_OPENIF, - get_session_parent_dir (), - everyone_sd (CYG_MUTANT_ACCESS)); - status = NtCreateMutant (&wsock_mtx, CYG_MUTANT_ACCESS, &attr, FALSE); - if (!NT_SUCCESS (status)) - { - debug_printf ("NtCreateMutant(%S), %y", &uname, status); - set_errno (ENOBUFS); - return false; - } - if (status == STATUS_OBJECT_NAME_EXISTS) - NtClose (wsock_mtx); - } - while (status == STATUS_OBJECT_NAME_EXISTS); - if ((wsock_evt = CreateEvent (&sec_all, TRUE, FALSE, NULL)) - == WSA_INVALID_EVENT) - { - debug_printf ("CreateEvent, %E"); - set_errno (ENOBUFS); - NtClose (wsock_mtx); - return false; - } - if (WSAEventSelect (get_socket (), wsock_evt, EVENT_MASK) == SOCKET_ERROR) - { - debug_printf ("WSAEventSelect, %E"); - set_winsock_errno (); - NtClose (wsock_evt); - NtClose (wsock_mtx); - return false; - } - if (!(wsock_events = search_wsa_event_slot (new_serial_number))) - { - set_errno (ENOBUFS); - NtClose (wsock_evt); - NtClose (wsock_mtx); - return false; - } - if (get_socket_type () == SOCK_DGRAM) - wsock_events->events = FD_WRITE; - return true; -} - -int -fhandler_socket::evaluate_events (const long event_mask, long &events, - const bool erase) -{ - int ret = 0; - long events_now = 0; - - WSANETWORKEVENTS evts = { 0 }; - if (!(WSAEnumNetworkEvents (get_socket (), wsock_evt, &evts))) - { - if (evts.lNetworkEvents) - { - LOCK_EVENTS; - wsock_events->events |= evts.lNetworkEvents; - events_now = (wsock_events->events & event_mask); - if (evts.lNetworkEvents & FD_CONNECT) - { - wsock_events->connect_errorcode = evts.iErrorCode[FD_CONNECT_BIT]; - - /* Setting the connect_state and calling the AF_LOCAL handshake - here allows to handle this stuff from a single point. This - is independent of FD_CONNECT being requested. Consider a - server calling connect(2) and then immediately poll(2) with - only polling for POLLIN (example: postfix), or select(2) just - asking for descriptors ready to read. - - Something weird occurs in Winsock: If you fork off and call - recv/send on the duplicated, already connected socket, another - FD_CONNECT event is generated in the child process. This - would trigger a call to af_local_connect which obviously fail. - Avoid this by calling set_connect_state only if connect_state - is connect_pending. */ - if (connect_state () == connect_pending) - { - if (wsock_events->connect_errorcode) - connect_state (connect_failed); - else if (af_local_connect ()) - { - wsock_events->connect_errorcode = WSAGetLastError (); - connect_state (connect_failed); - } - else - connect_state (connected); - } - } - UNLOCK_EVENTS; - if ((evts.lNetworkEvents & FD_OOB) && wsock_events->owner) - kill (wsock_events->owner, SIGURG); - } - } - - LOCK_EVENTS; - if ((events = events_now) != 0 - || (events = (wsock_events->events & event_mask)) != 0) - { - if (events & FD_CONNECT) - { - int wsa_err = wsock_events->connect_errorcode; - if (wsa_err) - { - /* CV 2014-04-23: This is really weird. If you call connect - asynchronously on a socket and then select, an error like - "Connection refused" is set in the event and in the SO_ERROR - socket option. If you call connect, then dup, then select, - the error is set in the event, but not in the SO_ERROR socket - option, despite the dup'ed socket handle referring to the same - socket. We're trying to workaround this problem here by - taking the connect errorcode from the event and write it back - into the SO_ERROR socket option. - - CV 2014-06-16: Call WSASetLastError *after* setsockopt since, - apparently, setsockopt sets the last WSA error code to 0 on - success. */ - ::setsockopt (get_socket (), SOL_SOCKET, SO_ERROR, - (const char *) &wsa_err, sizeof wsa_err); - WSASetLastError (wsa_err); - ret = SOCKET_ERROR; - } - else - wsock_events->events |= FD_WRITE; - wsock_events->events &= ~FD_CONNECT; - wsock_events->connect_errorcode = 0; - } - /* This test makes accept/connect behave as on Linux when accept/connect - is called on a socket for which shutdown has been called. The second - half of this code is in the shutdown method. */ - if (events & FD_CLOSE) - { - if ((event_mask & FD_ACCEPT) && saw_shutdown_read ()) - { - WSASetLastError (WSAEINVAL); - ret = SOCKET_ERROR; - } - if (event_mask & FD_CONNECT) - { - WSASetLastError (WSAECONNRESET); - ret = SOCKET_ERROR; - } - } - if (erase) - wsock_events->events &= ~(events & ~(FD_WRITE | FD_CLOSE)); - } - UNLOCK_EVENTS; - - return ret; -} - -int -fhandler_socket::wait_for_events (const long event_mask, const DWORD flags) -{ - if (async_io ()) - return 0; - - int ret; - long events = 0; - DWORD wfmo_timeout = 50; - DWORD timeout; - - WSAEVENT ev[3] = { wsock_evt, NULL, NULL }; - wait_signal_arrived here (ev[1]); - DWORD ev_cnt = 2; - if ((ev[2] = pthread::get_cancel_event ()) != NULL) - ++ev_cnt; - - if (is_nonblocking () || (flags & MSG_DONTWAIT)) - timeout = 0; - else if (event_mask & FD_READ) - timeout = rcvtimeo (); - else if (event_mask & FD_WRITE) - timeout = sndtimeo (); - else - timeout = INFINITE; - - while (!(ret = evaluate_events (event_mask, events, !(flags & MSG_PEEK))) - && !events) - { - if (timeout == 0) - { - WSASetLastError (WSAEWOULDBLOCK); - return SOCKET_ERROR; - } - - if (timeout < wfmo_timeout) - wfmo_timeout = timeout; - switch (WSAWaitForMultipleEvents (ev_cnt, ev, FALSE, wfmo_timeout, FALSE)) - { - case WSA_WAIT_TIMEOUT: - case WSA_WAIT_EVENT_0: - if (timeout != INFINITE) - timeout -= wfmo_timeout; - break; - - case WSA_WAIT_EVENT_0 + 1: - if (_my_tls.call_signal_handler ()) - break; - WSASetLastError (WSAEINTR); - return SOCKET_ERROR; - - case WSA_WAIT_EVENT_0 + 2: - pthread::static_cancel_self (); - break; - - default: - /* wsock_evt can be NULL. We're generating the same errno values - as for sockets on which shutdown has been called. */ - if (WSAGetLastError () != WSA_INVALID_HANDLE) - WSASetLastError (WSAEFAULT); - else - WSASetLastError ((event_mask & FD_CONNECT) ? WSAECONNRESET - : WSAEINVAL); - return SOCKET_ERROR; - } - } - return ret; -} - -void -fhandler_socket::release_events () -{ - if (WaitForSingleObject (wsock_mtx, INFINITE) != WAIT_FAILED) - { - HANDLE evt = wsock_evt; - HANDLE mtx = wsock_mtx; - - wsock_evt = wsock_mtx = NULL; - ReleaseMutex (mtx); - NtClose (evt); - NtClose (mtx); - } -} - -void -fhandler_socket::set_close_on_exec (bool val) -{ - set_no_inheritance (wsock_mtx, val); - set_no_inheritance (wsock_evt, val); - if (need_fixup_before ()) - { - close_on_exec (val); - debug_printf ("set close_on_exec for %s to %d", get_name (), val); - } - else - fhandler_base::set_close_on_exec (val); -} - -/* Called if a freshly created socket is not inheritable. In that case we - have to use fixup_before_fork_exec. See comment in set_socket_handle for - a description of the problem. */ -void -fhandler_socket::init_fixup_before () -{ - prot_info_ptr = (LPWSAPROTOCOL_INFOW) - cmalloc_abort (HEAP_BUF, sizeof (WSAPROTOCOL_INFOW)); - cygheap->fdtab.inc_need_fixup_before (); -} - -int -fhandler_socket::fixup_before_fork_exec (DWORD win_pid) -{ - SOCKET ret = WSADuplicateSocketW (get_socket (), win_pid, prot_info_ptr); - if (ret) - set_winsock_errno (); - else - debug_printf ("WSADuplicateSocket succeeded (%x)", prot_info_ptr->dwProviderReserved); - return (int) ret; -} - -void -fhandler_socket::fixup_after_fork (HANDLE parent) -{ - fork_fixup (parent, wsock_mtx, "wsock_mtx"); - fork_fixup (parent, wsock_evt, "wsock_evt"); - - if (!need_fixup_before ()) - { - fhandler_base::fixup_after_fork (parent); - return; - } - - SOCKET new_sock = WSASocketW (FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, - FROM_PROTOCOL_INFO, prot_info_ptr, 0, - WSA_FLAG_OVERLAPPED); - if (new_sock == INVALID_SOCKET) - { - set_winsock_errno (); - set_io_handle ((HANDLE) INVALID_SOCKET); - } - else - { - /* Even though the original socket was not inheritable, the duplicated - socket is potentially inheritable again. */ - SetHandleInformation ((HANDLE) new_sock, HANDLE_FLAG_INHERIT, 0); - set_io_handle ((HANDLE) new_sock); - debug_printf ("WSASocket succeeded (%p)", new_sock); - } -} - -void -fhandler_socket::fixup_after_exec () -{ - if (need_fixup_before () && !close_on_exec ()) - fixup_after_fork (NULL); -} - -int -fhandler_socket::dup (fhandler_base *child, int flags) -{ - debug_printf ("here"); - fhandler_socket *fhs = (fhandler_socket *) child; - - if (!DuplicateHandle (GetCurrentProcess (), wsock_mtx, - GetCurrentProcess (), &fhs->wsock_mtx, - 0, TRUE, DUPLICATE_SAME_ACCESS)) - { - __seterrno (); - return -1; - } - if (!DuplicateHandle (GetCurrentProcess (), wsock_evt, - GetCurrentProcess (), &fhs->wsock_evt, - 0, TRUE, DUPLICATE_SAME_ACCESS)) - { - __seterrno (); - NtClose (fhs->wsock_mtx); - return -1; - } - if (!need_fixup_before ()) - { - int ret = fhandler_base::dup (child, flags); - if (ret) - { - NtClose (fhs->wsock_evt); - NtClose (fhs->wsock_mtx); - } - return ret; - } - - cygheap->user.deimpersonate (); - fhs->init_fixup_before (); - fhs->set_io_handle (get_io_handle ()); - int ret = fhs->fixup_before_fork_exec (GetCurrentProcessId ()); - cygheap->user.reimpersonate (); - if (!ret) - { - fhs->fixup_after_fork (GetCurrentProcess ()); - if (fhs->get_io_handle() != (HANDLE) INVALID_SOCKET) - return 0; - } - cygheap->fdtab.dec_need_fixup_before (); - NtClose (fhs->wsock_evt); - NtClose (fhs->wsock_mtx); - return -1; } char * diff --git a/winsup/cygwin/fhandler_socket_inet.cc b/winsup/cygwin/fhandler_socket_inet.cc index b2bc1934a..0668c1063 100644 --- a/winsup/cygwin/fhandler_socket_inet.cc +++ b/winsup/cygwin/fhandler_socket_inet.cc @@ -59,6 +59,89 @@ ReleaseMutex (wsock_mtx); \ } +/* Maximum number of concurrently opened sockets from all Cygwin processes + per session. Note that shared sockets (through dup/fork/exec) are + counted as one socket. */ +#define NUM_SOCKS 2048U + +#define LOCK_EVENTS \ + if (wsock_mtx && \ + WaitForSingleObject (wsock_mtx, INFINITE) != WAIT_FAILED) \ + { + +#define UNLOCK_EVENTS \ + ReleaseMutex (wsock_mtx); \ + } + +static wsa_event wsa_events[NUM_SOCKS] __attribute__((section (".cygwin_dll_common"), shared)); + +static LONG socket_serial_number __attribute__((section (".cygwin_dll_common"), shared)); + +static HANDLE wsa_slot_mtx; + +static PWCHAR +sock_shared_name (PWCHAR buf, LONG num) +{ + __small_swprintf (buf, L"socket.%d", num); + return buf; +} + +static wsa_event * +search_wsa_event_slot (LONG new_serial_number) +{ + WCHAR name[32], searchname[32]; + UNICODE_STRING uname; + OBJECT_ATTRIBUTES attr; + NTSTATUS status; + + if (!wsa_slot_mtx) + { + RtlInitUnicodeString (&uname, sock_shared_name (name, 0)); + InitializeObjectAttributes (&attr, &uname, OBJ_INHERIT | OBJ_OPENIF, + get_session_parent_dir (), + everyone_sd (CYG_MUTANT_ACCESS)); + status = NtCreateMutant (&wsa_slot_mtx, CYG_MUTANT_ACCESS, &attr, FALSE); + if (!NT_SUCCESS (status)) + api_fatal ("Couldn't create/open shared socket mutex %S, %y", + &uname, status); + } + switch (WaitForSingleObject (wsa_slot_mtx, INFINITE)) + { + case WAIT_OBJECT_0: + case WAIT_ABANDONED: + break; + default: + api_fatal ("WFSO failed for shared socket mutex, %E"); + break; + } + unsigned int slot = new_serial_number % NUM_SOCKS; + while (wsa_events[slot].serial_number) + { + HANDLE searchmtx; + RtlInitUnicodeString (&uname, sock_shared_name (searchname, + wsa_events[slot].serial_number)); + InitializeObjectAttributes (&attr, &uname, 0, get_session_parent_dir (), + NULL); + status = NtOpenMutant (&searchmtx, READ_CONTROL, &attr); + if (!NT_SUCCESS (status)) + break; + /* Mutex still exists, attached socket is active, try next slot. */ + NtClose (searchmtx); + slot = (slot + 1) % NUM_SOCKS; + if (slot == (new_serial_number % NUM_SOCKS)) + { + /* Did the whole array once. Too bad. */ + debug_printf ("No free socket slot"); + ReleaseMutex (wsa_slot_mtx); + return NULL; + } + } + memset (&wsa_events[slot], 0, sizeof (wsa_event)); + wsa_events[slot].serial_number = new_serial_number; + ReleaseMutex (wsa_slot_mtx); + return wsa_events + slot; +} + /* cygwin internal: map sockaddr into internet domain address */ static int get_inet_addr_inet (const struct sockaddr *in, int inlen, @@ -123,8 +206,496 @@ convert_ws1_ip_optname (int optname) : ws2_optname[optname]; } +fhandler_socket_wsock::fhandler_socket_wsock () : + fhandler_socket (), + wsock_events (NULL), + wsock_mtx (NULL), + wsock_evt (NULL), + prot_info_ptr (NULL), + status () +{ + need_fork_fixup (true); +} + +fhandler_socket_wsock::~fhandler_socket_wsock () +{ + if (prot_info_ptr) + cfree (prot_info_ptr); +} + +bool +fhandler_socket_wsock::init_events () +{ + LONG new_serial_number; + WCHAR name[32]; + UNICODE_STRING uname; + OBJECT_ATTRIBUTES attr; + NTSTATUS status; + + do + { + new_serial_number = + InterlockedIncrement (&socket_serial_number); + if (!new_serial_number) /* 0 is reserved for global mutex */ + InterlockedIncrement (&socket_serial_number); + set_ino (new_serial_number); + RtlInitUnicodeString (&uname, sock_shared_name (name, new_serial_number)); + InitializeObjectAttributes (&attr, &uname, OBJ_INHERIT | OBJ_OPENIF, + get_session_parent_dir (), + everyone_sd (CYG_MUTANT_ACCESS)); + status = NtCreateMutant (&wsock_mtx, CYG_MUTANT_ACCESS, &attr, FALSE); + if (!NT_SUCCESS (status)) + { + debug_printf ("NtCreateMutant(%S), %y", &uname, status); + set_errno (ENOBUFS); + return false; + } + if (status == STATUS_OBJECT_NAME_EXISTS) + NtClose (wsock_mtx); + } + while (status == STATUS_OBJECT_NAME_EXISTS); + if ((wsock_evt = CreateEvent (&sec_all, TRUE, FALSE, NULL)) + == WSA_INVALID_EVENT) + { + debug_printf ("CreateEvent, %E"); + set_errno (ENOBUFS); + NtClose (wsock_mtx); + return false; + } + if (WSAEventSelect (get_socket (), wsock_evt, EVENT_MASK) == SOCKET_ERROR) + { + debug_printf ("WSAEventSelect, %E"); + set_winsock_errno (); + NtClose (wsock_evt); + NtClose (wsock_mtx); + return false; + } + if (!(wsock_events = search_wsa_event_slot (new_serial_number))) + { + set_errno (ENOBUFS); + NtClose (wsock_evt); + NtClose (wsock_mtx); + return false; + } + if (get_socket_type () == SOCK_DGRAM) + wsock_events->events = FD_WRITE; + return true; +} + +int +fhandler_socket_wsock::evaluate_events (const long event_mask, long &events, + const bool erase) +{ + int ret = 0; + long events_now = 0; + + WSANETWORKEVENTS evts = { 0 }; + if (!(WSAEnumNetworkEvents (get_socket (), wsock_evt, &evts))) + { + if (evts.lNetworkEvents) + { + LOCK_EVENTS; + wsock_events->events |= evts.lNetworkEvents; + events_now = (wsock_events->events & event_mask); + if (evts.lNetworkEvents & FD_CONNECT) + { + wsock_events->connect_errorcode = evts.iErrorCode[FD_CONNECT_BIT]; + + /* Setting the connect_state and calling the AF_LOCAL handshake + here allows to handle this stuff from a single point. This + is independent of FD_CONNECT being requested. Consider a + server calling connect(2) and then immediately poll(2) with + only polling for POLLIN (example: postfix), or select(2) just + asking for descriptors ready to read. + + Something weird occurs in Winsock: If you fork off and call + recv/send on the duplicated, already connected socket, another + FD_CONNECT event is generated in the child process. This + would trigger a call to af_local_connect which obviously fail. + Avoid this by calling set_connect_state only if connect_state + is connect_pending. */ + if (connect_state () == connect_pending) + { + if (wsock_events->connect_errorcode) + connect_state (connect_failed); + else if (af_local_connect ()) + { + wsock_events->connect_errorcode = WSAGetLastError (); + connect_state (connect_failed); + } + else + connect_state (connected); + } + } + UNLOCK_EVENTS; + if ((evts.lNetworkEvents & FD_OOB) && wsock_events->owner) + kill (wsock_events->owner, SIGURG); + } + } + + LOCK_EVENTS; + if ((events = events_now) != 0 + || (events = (wsock_events->events & event_mask)) != 0) + { + if (events & FD_CONNECT) + { + int wsa_err = wsock_events->connect_errorcode; + if (wsa_err) + { + /* CV 2014-04-23: This is really weird. If you call connect + asynchronously on a socket and then select, an error like + "Connection refused" is set in the event and in the SO_ERROR + socket option. If you call connect, then dup, then select, + the error is set in the event, but not in the SO_ERROR socket + option, despite the dup'ed socket handle referring to the same + socket. We're trying to workaround this problem here by + taking the connect errorcode from the event and write it back + into the SO_ERROR socket option. + + CV 2014-06-16: Call WSASetLastError *after* setsockopt since, + apparently, setsockopt sets the last WSA error code to 0 on + success. */ + ::setsockopt (get_socket (), SOL_SOCKET, SO_ERROR, + (const char *) &wsa_err, sizeof wsa_err); + WSASetLastError (wsa_err); + ret = SOCKET_ERROR; + } + else + wsock_events->events |= FD_WRITE; + wsock_events->events &= ~FD_CONNECT; + wsock_events->connect_errorcode = 0; + } + /* This test makes accept/connect behave as on Linux when accept/connect + is called on a socket for which shutdown has been called. The second + half of this code is in the shutdown method. */ + if (events & FD_CLOSE) + { + if ((event_mask & FD_ACCEPT) && saw_shutdown_read ()) + { + WSASetLastError (WSAEINVAL); + ret = SOCKET_ERROR; + } + if (event_mask & FD_CONNECT) + { + WSASetLastError (WSAECONNRESET); + ret = SOCKET_ERROR; + } + } + if (erase) + wsock_events->events &= ~(events & ~(FD_WRITE | FD_CLOSE)); + } + UNLOCK_EVENTS; + + return ret; +} + +int +fhandler_socket_wsock::wait_for_events (const long event_mask, + const DWORD flags) +{ + if (async_io ()) + return 0; + + int ret; + long events = 0; + DWORD wfmo_timeout = 50; + DWORD timeout; + + WSAEVENT ev[3] = { wsock_evt, NULL, NULL }; + wait_signal_arrived here (ev[1]); + DWORD ev_cnt = 2; + if ((ev[2] = pthread::get_cancel_event ()) != NULL) + ++ev_cnt; + + if (is_nonblocking () || (flags & MSG_DONTWAIT)) + timeout = 0; + else if (event_mask & FD_READ) + timeout = rcvtimeo (); + else if (event_mask & FD_WRITE) + timeout = sndtimeo (); + else + timeout = INFINITE; + + while (!(ret = evaluate_events (event_mask, events, !(flags & MSG_PEEK))) + && !events) + { + if (timeout == 0) + { + WSASetLastError (WSAEWOULDBLOCK); + return SOCKET_ERROR; + } + + if (timeout < wfmo_timeout) + wfmo_timeout = timeout; + switch (WSAWaitForMultipleEvents (ev_cnt, ev, FALSE, wfmo_timeout, FALSE)) + { + case WSA_WAIT_TIMEOUT: + case WSA_WAIT_EVENT_0: + if (timeout != INFINITE) + timeout -= wfmo_timeout; + break; + + case WSA_WAIT_EVENT_0 + 1: + if (_my_tls.call_signal_handler ()) + break; + WSASetLastError (WSAEINTR); + return SOCKET_ERROR; + + case WSA_WAIT_EVENT_0 + 2: + pthread::static_cancel_self (); + break; + + default: + /* wsock_evt can be NULL. We're generating the same errno values + as for sockets on which shutdown has been called. */ + if (WSAGetLastError () != WSA_INVALID_HANDLE) + WSASetLastError (WSAEFAULT); + else + WSASetLastError ((event_mask & FD_CONNECT) ? WSAECONNRESET + : WSAEINVAL); + return SOCKET_ERROR; + } + } + return ret; +} + +void +fhandler_socket_wsock::release_events () +{ + if (WaitForSingleObject (wsock_mtx, INFINITE) != WAIT_FAILED) + { + HANDLE evt = wsock_evt; + HANDLE mtx = wsock_mtx; + + wsock_evt = wsock_mtx = NULL; + ReleaseMutex (mtx); + NtClose (evt); + NtClose (mtx); + } +} + +void +fhandler_socket_wsock::set_close_on_exec (bool val) +{ + set_no_inheritance (wsock_mtx, val); + set_no_inheritance (wsock_evt, val); + if (need_fixup_before ()) + { + close_on_exec (val); + debug_printf ("set close_on_exec for %s to %d", get_name (), val); + } + else + fhandler_base::set_close_on_exec (val); +} + +/* Called if a freshly created socket is not inheritable. In that case we + have to use fixup_before_fork_exec. See comment in set_socket_handle for + a description of the problem. */ +void +fhandler_socket_wsock::init_fixup_before () +{ + prot_info_ptr = (LPWSAPROTOCOL_INFOW) + cmalloc_abort (HEAP_BUF, sizeof (WSAPROTOCOL_INFOW)); + cygheap->fdtab.inc_need_fixup_before (); +} + +int +fhandler_socket_wsock::fixup_before_fork_exec (DWORD win_pid) +{ + SOCKET ret = WSADuplicateSocketW (get_socket (), win_pid, prot_info_ptr); + if (ret) + set_winsock_errno (); + else + debug_printf ("WSADuplicateSocket succeeded (%x)", prot_info_ptr->dwProviderReserved); + return (int) ret; +} + +void +fhandler_socket_wsock::fixup_after_fork (HANDLE parent) +{ + fork_fixup (parent, wsock_mtx, "wsock_mtx"); + fork_fixup (parent, wsock_evt, "wsock_evt"); + + if (!need_fixup_before ()) + { + fhandler_base::fixup_after_fork (parent); + return; + } + + SOCKET new_sock = WSASocketW (FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, prot_info_ptr, 0, + WSA_FLAG_OVERLAPPED); + if (new_sock == INVALID_SOCKET) + { + set_winsock_errno (); + set_io_handle ((HANDLE) INVALID_SOCKET); + } + else + { + /* Even though the original socket was not inheritable, the duplicated + socket is potentially inheritable again. */ + SetHandleInformation ((HANDLE) new_sock, HANDLE_FLAG_INHERIT, 0); + set_io_handle ((HANDLE) new_sock); + debug_printf ("WSASocket succeeded (%p)", new_sock); + } +} + +void +fhandler_socket_wsock::fixup_after_exec () +{ + if (need_fixup_before () && !close_on_exec ()) + fixup_after_fork (NULL); +} + +int +fhandler_socket_wsock::dup (fhandler_base *child, int flags) +{ + debug_printf ("here"); + fhandler_socket_wsock *fhs = (fhandler_socket_wsock *) child; + + if (!DuplicateHandle (GetCurrentProcess (), wsock_mtx, + GetCurrentProcess (), &fhs->wsock_mtx, + 0, TRUE, DUPLICATE_SAME_ACCESS)) + { + __seterrno (); + return -1; + } + if (!DuplicateHandle (GetCurrentProcess (), wsock_evt, + GetCurrentProcess (), &fhs->wsock_evt, + 0, TRUE, DUPLICATE_SAME_ACCESS)) + { + __seterrno (); + NtClose (fhs->wsock_mtx); + return -1; + } + if (!need_fixup_before ()) + { + int ret = fhandler_base::dup (child, flags); + if (ret) + { + NtClose (fhs->wsock_evt); + NtClose (fhs->wsock_mtx); + } + return ret; + } + + cygheap->user.deimpersonate (); + fhs->init_fixup_before (); + fhs->set_io_handle (get_io_handle ()); + int ret = fhs->fixup_before_fork_exec (GetCurrentProcessId ()); + cygheap->user.reimpersonate (); + if (!ret) + { + fhs->fixup_after_fork (GetCurrentProcess ()); + if (fhs->get_io_handle() != (HANDLE) INVALID_SOCKET) + return 0; + } + cygheap->fdtab.dec_need_fixup_before (); + NtClose (fhs->wsock_evt); + NtClose (fhs->wsock_mtx); + return -1; +} + +int +fhandler_socket_wsock::set_socket_handle (SOCKET sock, int af, int type, + int flags) +{ + DWORD hdl_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, &hdl_flags) + || !(hdl_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, &hdl_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_addr_family (af); + set_socket_type (type); + if (flags & SOCK_NONBLOCK) + set_nonblocking (true); + if (flags & SOCK_CLOEXEC) + set_close_on_exec (true); + set_io_handle ((HANDLE) sock); + if (!init_events ()) + 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; +} + fhandler_socket_inet::fhandler_socket_inet () : - fhandler_socket () + fhandler_socket_wsock () { } @@ -398,7 +969,7 @@ fhandler_socket_inet::getpeername (struct sockaddr *name, int *namelen) } int -fhandler_socket_inet::shutdown (int how) +fhandler_socket_wsock::shutdown (int how) { int res = ::shutdown (get_socket (), how); @@ -437,7 +1008,7 @@ fhandler_socket_inet::shutdown (int how) } int -fhandler_socket_inet::close () +fhandler_socket_wsock::close () { int res = 0; @@ -458,12 +1029,10 @@ fhandler_socket_inet::close () } WSASetLastError (0); } - - debug_printf ("%d = fhandler_socket::close()", res); return res; } -inline ssize_t +ssize_t fhandler_socket_inet::recv_internal (LPWSAMSG wsamsg, bool use_recvmsg) { ssize_t res = 0; @@ -594,8 +1163,8 @@ fhandler_socket_inet::recv_internal (LPWSAMSG wsamsg, bool use_recvmsg) } ssize_t -fhandler_socket_inet::recvfrom (void *in_ptr, size_t len, int flags, - struct sockaddr *from, int *fromlen) +fhandler_socket_wsock::recvfrom (void *in_ptr, size_t len, int flags, + struct sockaddr *from, int *fromlen) { char *ptr = (char *) in_ptr; @@ -630,7 +1199,7 @@ fhandler_socket_inet::recvfrom (void *in_ptr, size_t len, int flags, } ssize_t -fhandler_socket_inet::recvmsg (struct msghdr *msg, int flags) +fhandler_socket_wsock::recvmsg (struct msghdr *msg, int flags) { /* Disappointing but true: Even if WSARecvMsg is supported, it's only supported for datagram and raw sockets. */ @@ -665,7 +1234,7 @@ fhandler_socket_inet::recvmsg (struct msghdr *msg, int flags) } void __reg3 -fhandler_socket_inet::read (void *in_ptr, size_t& len) +fhandler_socket_wsock::read (void *in_ptr, size_t& len) { char *ptr = (char *) in_ptr; @@ -692,8 +1261,8 @@ fhandler_socket_inet::read (void *in_ptr, size_t& len) } ssize_t -fhandler_socket_inet::readv (const struct iovec *const iov, const int iovcnt, - ssize_t tot) +fhandler_socket_wsock::readv (const struct iovec *const iov, const int iovcnt, + ssize_t tot) { WSABUF wsabuf[iovcnt]; WSABUF *wsaptr = wsabuf + iovcnt; @@ -707,8 +1276,8 @@ fhandler_socket_inet::readv (const struct iovec *const iov, const int iovcnt, return recv_internal (&wsamsg, false); } -inline ssize_t -fhandler_socket_inet::send_internal (struct _WSAMSG *wsamsg, int flags) +ssize_t +fhandler_socket_wsock::send_internal (struct _WSAMSG *wsamsg, int flags) { ssize_t res = 0; DWORD ret = 0, sum = 0; @@ -891,7 +1460,7 @@ fhandler_socket_inet::sendmsg (const struct msghdr *msg, int flags) } ssize_t -fhandler_socket_inet::write (const void *in_ptr, size_t len) +fhandler_socket_wsock::write (const void *in_ptr, size_t len) { char *ptr = (char *) in_ptr; @@ -917,8 +1486,8 @@ fhandler_socket_inet::write (const void *in_ptr, size_t len) } ssize_t -fhandler_socket_inet::writev (const struct iovec *const iov, const int iovcnt, - ssize_t tot) +fhandler_socket_wsock::writev (const struct iovec *const iov, const int iovcnt, + ssize_t tot) { WSABUF wsabuf[iovcnt]; WSABUF *wsaptr = wsabuf; @@ -1219,7 +1788,7 @@ fhandler_socket_inet::getsockopt (int level, int optname, const void *optval, } int -fhandler_socket_inet::ioctl (unsigned int cmd, void *p) +fhandler_socket_wsock::ioctl (unsigned int cmd, void *p) { int res; @@ -1287,7 +1856,7 @@ fhandler_socket_inet::ioctl (unsigned int cmd, void *p) } int -fhandler_socket_inet::fcntl (int cmd, intptr_t arg) +fhandler_socket_wsock::fcntl (int cmd, intptr_t arg) { int res = 0; diff --git a/winsup/cygwin/fhandler_socket_local.cc b/winsup/cygwin/fhandler_socket_local.cc index 298a378e3..ca3844291 100644 --- a/winsup/cygwin/fhandler_socket_local.cc +++ b/winsup/cygwin/fhandler_socket_local.cc @@ -221,9 +221,10 @@ get_ext_funcptr (SOCKET sock, void *funcptr) } fhandler_socket_local::fhandler_socket_local () : - fhandler_socket (), + fhandler_socket_wsock (), sun_path (NULL), - peer_sun_path (NULL) + peer_sun_path (NULL), + status () { } @@ -1044,73 +1045,7 @@ fhandler_socket_local::getpeername (struct sockaddr *name, int *namelen) return res; } -int -fhandler_socket_local::shutdown (int how) -{ - int res = ::shutdown (get_socket (), how); - - /* Linux allows to call shutdown for any socket, even if it's not connected. - This also disables to call accept on this socket, if shutdown has been - called with the SHUT_RD or SHUT_RDWR parameter. In contrast, WinSock - only allows to call shutdown on a connected socket. The accept function - is in no way affected. So, what we do here is to fake success, and to - change the event settings so that an FD_CLOSE event is triggered for the - calling Cygwin function. The evaluate_events method handles the call - from accept specially to generate a Linux-compatible behaviour. */ - if (res && WSAGetLastError () != WSAENOTCONN) - set_winsock_errno (); - else - { - res = 0; - switch (how) - { - case SHUT_RD: - saw_shutdown_read (true); - wsock_events->events |= FD_CLOSE; - SetEvent (wsock_evt); - break; - case SHUT_WR: - saw_shutdown_write (true); - break; - case SHUT_RDWR: - saw_shutdown_read (true); - saw_shutdown_write (true); - wsock_events->events |= FD_CLOSE; - SetEvent (wsock_evt); - break; - } - } - return res; -} - -int -fhandler_socket_local::close () -{ - int res = 0; - - release_events (); - while ((res = ::closesocket (get_socket ())) != 0) - { - if (WSAGetLastError () != WSAEWOULDBLOCK) - { - set_winsock_errno (); - res = -1; - break; - } - if (cygwait (10) == WAIT_SIGNALED) - { - set_errno (EINTR); - res = -1; - break; - } - WSASetLastError (0); - } - - debug_printf ("%d = fhandler_socket::close()", res); - return res; -} - -inline ssize_t +ssize_t fhandler_socket_local::recv_internal (LPWSAMSG wsamsg, bool use_recvmsg) { ssize_t res = 0; @@ -1279,235 +1214,6 @@ fhandler_socket_local::recv_internal (LPWSAMSG wsamsg, bool use_recvmsg) return ret; } -ssize_t -fhandler_socket_local::recvfrom (void *in_ptr, size_t len, int flags, - struct sockaddr *from, int *fromlen) -{ - char *ptr = (char *) in_ptr; - -#ifdef __x86_64__ - /* size_t is 64 bit, but the len member in WSABUF is 32 bit. - Split buffer if necessary. */ - DWORD bufcnt = len / UINT32_MAX + ((!len || (len % UINT32_MAX)) ? 1 : 0); - WSABUF wsabuf[bufcnt]; - WSAMSG wsamsg = { from, from && fromlen ? *fromlen : 0, - wsabuf, bufcnt, - { 0, NULL }, - (DWORD) flags }; - /* Don't use len as loop condition, it could be 0. */ - for (WSABUF *wsaptr = wsabuf; bufcnt--; ++wsaptr) - { - wsaptr->len = MIN (len, UINT32_MAX); - wsaptr->buf = ptr; - len -= wsaptr->len; - ptr += wsaptr->len; - } -#else - WSABUF wsabuf = { len, ptr }; - WSAMSG wsamsg = { from, from && fromlen ? *fromlen : 0, - &wsabuf, 1, - { 0, NULL}, - (DWORD) flags }; -#endif - ssize_t ret = recv_internal (&wsamsg, false); - if (fromlen) - *fromlen = wsamsg.namelen; - return ret; -} - -ssize_t -fhandler_socket_local::recvmsg (struct msghdr *msg, int flags) -{ - /* TODO: Descriptor passing on AF_LOCAL sockets. */ - - /* Disappointing but true: Even if WSARecvMsg is supported, it's only - supported for datagram and raw sockets. */ - bool use_recvmsg = true; - if (get_socket_type () == SOCK_STREAM || get_addr_family () == AF_LOCAL) - { - use_recvmsg = false; - msg->msg_controllen = 0; - } - - WSABUF wsabuf[msg->msg_iovlen]; - WSABUF *wsaptr = wsabuf + msg->msg_iovlen; - const struct iovec *iovptr = msg->msg_iov + msg->msg_iovlen; - while (--wsaptr >= wsabuf) - { - wsaptr->len = (--iovptr)->iov_len; - wsaptr->buf = (char *) iovptr->iov_base; - } - WSAMSG wsamsg = { (struct sockaddr *) msg->msg_name, msg->msg_namelen, - wsabuf, (DWORD) msg->msg_iovlen, - { (DWORD) msg->msg_controllen, (char *) msg->msg_control }, - (DWORD) flags }; - ssize_t ret = recv_internal (&wsamsg, use_recvmsg); - if (ret >= 0) - { - msg->msg_namelen = wsamsg.namelen; - msg->msg_controllen = wsamsg.Control.len; - if (!CYGWIN_VERSION_CHECK_FOR_USING_ANCIENT_MSGHDR) - msg->msg_flags = wsamsg.dwFlags; - } - return ret; -} - -void __reg3 -fhandler_socket_local::read (void *in_ptr, size_t& len) -{ - char *ptr = (char *) in_ptr; - -#ifdef __x86_64__ - /* size_t is 64 bit, but the len member in WSABUF is 32 bit. - Split buffer if necessary. */ - DWORD bufcnt = len / UINT32_MAX + ((!len || (len % UINT32_MAX)) ? 1 : 0); - WSABUF wsabuf[bufcnt]; - WSAMSG wsamsg = { NULL, 0, wsabuf, bufcnt, { 0, NULL }, 0 }; - /* Don't use len as loop condition, it could be 0. */ - for (WSABUF *wsaptr = wsabuf; bufcnt--; ++wsaptr) - { - wsaptr->len = MIN (len, UINT32_MAX); - wsaptr->buf = ptr; - len -= wsaptr->len; - ptr += wsaptr->len; - } -#else - WSABUF wsabuf = { len, ptr }; - WSAMSG wsamsg = { NULL, 0, &wsabuf, 1, { 0, NULL }, 0 }; -#endif - - len = recv_internal (&wsamsg, false); -} - -ssize_t -fhandler_socket_local::readv (const struct iovec *const iov, const int iovcnt, - ssize_t tot) -{ - WSABUF wsabuf[iovcnt]; - WSABUF *wsaptr = wsabuf + iovcnt; - const struct iovec *iovptr = iov + iovcnt; - while (--wsaptr >= wsabuf) - { - wsaptr->len = (--iovptr)->iov_len; - wsaptr->buf = (char *) iovptr->iov_base; - } - WSAMSG wsamsg = { NULL, 0, wsabuf, (DWORD) iovcnt, { 0, NULL}, 0 }; - return recv_internal (&wsamsg, false); -} - -inline ssize_t -fhandler_socket_local::send_internal (struct _WSAMSG *wsamsg, int flags) -{ - ssize_t res = 0; - DWORD ret = 0, sum = 0; - WSABUF out_buf[wsamsg->dwBufferCount]; - bool use_sendmsg = false; - DWORD wait_flags = flags & MSG_DONTWAIT; - bool nosignal = !!(flags & MSG_NOSIGNAL); - - flags &= (MSG_OOB | MSG_DONTROUTE); - if (wsamsg->Control.len > 0) - use_sendmsg = true; - /* Workaround for MSDN KB 823764: Split a message into chunks <= SO_SNDBUF. - in_idx is the index of the current lpBuffers from the input wsamsg buffer. - in_off is used to keep track of the next byte to write from a wsamsg - buffer which only gets partially written. */ - for (DWORD in_idx = 0, in_off = 0; - in_idx < wsamsg->dwBufferCount; - in_off >= wsamsg->lpBuffers[in_idx].len && (++in_idx, in_off = 0)) - { - /* Split a message into the least number of pieces to minimize the - number of WsaSendTo calls. Don't split datagram messages (bad idea). - out_idx is the index of the next buffer in the out_buf WSABUF, - also the number of buffers given to WSASendTo. - out_len is the number of bytes in the buffers given to WSASendTo. - Don't split datagram messages (very bad idea). */ - DWORD out_idx = 0; - DWORD out_len = 0; - if (get_socket_type () == SOCK_STREAM) - { - do - { - out_buf[out_idx].buf = wsamsg->lpBuffers[in_idx].buf + in_off; - out_buf[out_idx].len = wsamsg->lpBuffers[in_idx].len - in_off; - out_len += out_buf[out_idx].len; - out_idx++; - } - while (out_len < (unsigned) wmem () - && (in_off = 0, ++in_idx < wsamsg->dwBufferCount)); - /* Tweak len of the last out_buf buffer so the entire number of bytes - is (less than or) equal to wmem (). Fix out_len as well since it's - used in a subsequent test expression. */ - if (out_len > (unsigned) wmem ()) - { - out_buf[out_idx - 1].len -= out_len - (unsigned) wmem (); - out_len = (unsigned) wmem (); - } - /* Add the bytes written from the current last buffer to in_off, - so in_off points to the next byte to be written from that buffer, - or beyond which lets the outper loop skip to the next buffer. */ - in_off += out_buf[out_idx - 1].len; - } - - do - { - if (use_sendmsg) - res = WSASendMsg (get_socket (), wsamsg, flags, &ret, NULL, NULL); - else if (get_socket_type () == SOCK_STREAM) - res = WSASendTo (get_socket (), out_buf, out_idx, &ret, flags, - wsamsg->name, wsamsg->namelen, NULL, NULL); - else - res = WSASendTo (get_socket (), wsamsg->lpBuffers, - wsamsg->dwBufferCount, &ret, flags, - wsamsg->name, wsamsg->namelen, NULL, NULL); - if (res && (WSAGetLastError () == WSAEWOULDBLOCK)) - { - LOCK_EVENTS; - wsock_events->events &= ~FD_WRITE; - UNLOCK_EVENTS; - } - } - while (res && (WSAGetLastError () == WSAEWOULDBLOCK) - && !(res = wait_for_events (FD_WRITE | FD_CLOSE, wait_flags))); - - if (!res) - { - sum += ret; - /* For streams, return to application if the number of bytes written - is less than the number of bytes we intended to write in a single - call to WSASendTo. Otherwise we would have to add code to - backtrack in the input buffers, which is questionable. There was - probably a good reason we couldn't write more. */ - if (get_socket_type () != SOCK_STREAM || ret < out_len) - break; - } - else if (is_nonblocking () || WSAGetLastError() != WSAEWOULDBLOCK) - break; - } - - if (sum) - res = sum; - else if (res == SOCKET_ERROR) - { - set_winsock_errno (); - - /* Special handling for EPIPE and SIGPIPE. - - EPIPE is generated if the local end has been shut down on a connection - oriented socket. In this case the process will also receive a SIGPIPE - unless MSG_NOSIGNAL is set. */ - if ((get_errno () == ECONNABORTED || get_errno () == ESHUTDOWN) - && get_socket_type () == SOCK_STREAM) - { - set_errno (EPIPE); - if (!nosignal) - raise (SIGPIPE); - } - } - - return res; -} - ssize_t fhandler_socket_local::sendto (const void *in_ptr, size_t len, int flags, const struct sockaddr *to, int tolen) @@ -1578,48 +1284,6 @@ fhandler_socket_local::sendmsg (const struct msghdr *msg, int flags) return send_internal (&wsamsg, flags); } -ssize_t -fhandler_socket_local::write (const void *in_ptr, size_t len) -{ - char *ptr = (char *) in_ptr; - -#ifdef __x86_64__ - /* size_t is 64 bit, but the len member in WSABUF is 32 bit. - Split buffer if necessary. */ - DWORD bufcnt = len / UINT32_MAX + ((!len || (len % UINT32_MAX)) ? 1 : 0); - WSABUF wsabuf[bufcnt]; - WSAMSG wsamsg = { NULL, 0, wsabuf, bufcnt, { 0, NULL }, 0 }; - /* Don't use len as loop condition, it could be 0. */ - for (WSABUF *wsaptr = wsabuf; bufcnt--; ++wsaptr) - { - wsaptr->len = MIN (len, UINT32_MAX); - wsaptr->buf = ptr; - len -= wsaptr->len; - ptr += wsaptr->len; - } -#else - WSABUF wsabuf = { len, ptr }; - WSAMSG wsamsg = { NULL, 0, &wsabuf, 1, { 0, NULL }, 0 }; -#endif - return send_internal (&wsamsg, 0); -} - -ssize_t -fhandler_socket_local::writev (const struct iovec *const iov, const int iovcnt, - ssize_t tot) -{ - WSABUF wsabuf[iovcnt]; - WSABUF *wsaptr = wsabuf; - const struct iovec *iovptr = iov; - for (int i = 0; i < iovcnt; ++i) - { - wsaptr->len = iovptr->iov_len; - (wsaptr++)->buf = (char *) (iovptr++)->iov_base; - } - WSAMSG wsamsg = { NULL, 0, wsabuf, (DWORD) iovcnt, { 0, NULL}, 0 }; - return send_internal (&wsamsg, 0); -} - void fhandler_socket_local::set_sun_path (const char *path) { @@ -1907,86 +1571,3 @@ fhandler_socket_local::getsockopt (int level, int optname, const void *optval, return ret; } - -int -fhandler_socket_local::ioctl (unsigned int cmd, void *p) -{ - int res; - - switch (cmd) - { - /* FIXME: These have to be handled differently in future. */ - case FIOASYNC: -#ifdef __x86_64__ - case _IOW('f', 125, u_long): -#endif - res = WSAAsyncSelect (get_socket (), winmsg, WM_ASYNCIO, - *(int *) p ? ASYNC_MASK : 0); - syscall_printf ("Async I/O on socket %s", - *(int *) p ? "started" : "cancelled"); - async_io (*(int *) p != 0); - /* If async_io is switched off, revert the event handling. */ - if (*(int *) p == 0) - WSAEventSelect (get_socket (), wsock_evt, EVENT_MASK); - break; - case FIONREAD: -#ifdef __x86_64__ - case _IOR('f', 127, u_long): -#endif - /* Make sure to use the Winsock definition of FIONREAD. */ - res = ::ioctlsocket (get_socket (), _IOR('f', 127, u_long), (u_long *) p); - if (res == SOCKET_ERROR) - set_winsock_errno (); - break; - case FIONBIO: - case SIOCATMARK: - /* Sockets are always non-blocking internally. So we just note the - state here. */ -#ifdef __x86_64__ - /* Convert the different idea of u_long in the definition of cmd. */ - if (((cmd >> 16) & IOCPARM_MASK) == sizeof (unsigned long)) - cmd = (cmd & ~(IOCPARM_MASK << 16)) | (sizeof (u_long) << 16); -#endif - if (cmd == FIONBIO) - { - syscall_printf ("socket is now %sblocking", - *(int *) p ? "non" : ""); - set_nonblocking (*(int *) p); - res = 0; - } - else - res = ::ioctlsocket (get_socket (), cmd, (u_long *) p); - break; - default: - res = fhandler_socket::ioctl (cmd, p); - break; - } - syscall_printf ("%d = ioctl_socket(%x, %p)", res, cmd, p); - return res; -} - -int -fhandler_socket_local::fcntl (int cmd, intptr_t arg) -{ - int res = 0; - - switch (cmd) - { - case F_SETOWN: - { - pid_t pid = (pid_t) arg; - LOCK_EVENTS; - wsock_events->owner = pid; - UNLOCK_EVENTS; - debug_printf ("owner set to %d", pid); - } - break; - case F_GETOWN: - res = wsock_events->owner; - break; - default: - res = fhandler_socket::fcntl (cmd, arg); - break; - } - return res; -} diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc index 6b88f9105..fe6576dc9 100644 --- a/winsup/cygwin/net.cc +++ b/winsup/cygwin/net.cc @@ -1384,8 +1384,7 @@ cygwin_getpeername (int fd, struct sockaddr *name, socklen_t *len) } __except (EFAULT) {} __endtry - syscall_printf ("%R = getpeername(%d) %p", res, fd, - (fh ? fh->get_socket () : (SOCKET) -1)); + syscall_printf ("%R = getpeername(%d)", res, fd); return res; } diff --git a/winsup/cygwin/poll.cc b/winsup/cygwin/poll.cc index ea45b70ad..440413433 100644 --- a/winsup/cygwin/poll.cc +++ b/winsup/cygwin/poll.cc @@ -94,12 +94,12 @@ poll (struct pollfd *fds, nfds_t nfds, int timeout) { if (fds[i].fd >= 0 && fds[i].revents != POLLNVAL) { - fhandler_socket *sock; + fhandler_socket_wsock *sock; /* Check if the descriptor has been closed, or if shutdown for the read side has been called on a socket. */ if (cygheap->fdtab.not_open (fds[i].fd) - || ((sock = cygheap->fdtab[fds[i].fd]->is_socket ()) + || ((sock = cygheap->fdtab[fds[i].fd]->is_wsock_socket ()) && sock->saw_shutdown_read ())) fds[i].revents = POLLHUP; else @@ -117,7 +117,7 @@ poll (struct pollfd *fds, nfds_t nfds, int timeout) /* Handle failed connect. A failed connect implicitly sets POLLOUT, if requested, but it doesn't set POLLIN. */ if ((fds[i].events & POLLIN) - && (sock = cygheap->fdtab[fds[i].fd]->is_socket ()) + && (sock = cygheap->fdtab[fds[i].fd]->is_wsock_socket ()) && sock->connect_state () == connect_failed) fds[i].revents |= (POLLIN | POLLERR); else diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc index 86e7cd8fd..023bec048 100644 --- a/winsup/cygwin/select.cc +++ b/winsup/cygwin/select.cc @@ -501,7 +501,7 @@ set_bits (select_record *me, fd_set *readfds, fd_set *writefds, fd_set *exceptfds) { int ready = 0; - fhandler_socket *sock; + fhandler_socket_wsock *sock; select_printf ("me %p, testing fd %d (%s)", me, me->fd, me->fh->get_name ()); if (me->read_selected && me->read_ready) { @@ -511,7 +511,7 @@ set_bits (select_record *me, fd_set *readfds, fd_set *writefds, if (me->write_selected && me->write_ready) { UNIX_FD_SET (me->fd, writefds); - if (me->except_on_write && (sock = me->fh->is_socket ())) + if (me->except_on_write && (sock = me->fh->is_wsock_socket ())) { /* Set readfds entry in case of a failed connect. */ if (!me->read_ready && me->read_selected @@ -1364,7 +1364,7 @@ fhandler_base::select_except (select_stuff *ss) static int peek_socket (select_record *me, bool) { - fhandler_socket *fh = (fhandler_socket *) me->fh; + fhandler_socket_wsock *fh = (fhandler_socket_wsock *) me->fh; long events; /* Don't play with the settings again, unless having taken a deep look into Richard W. Stevens Network Programming book. Thank you. */ @@ -1488,7 +1488,7 @@ start_thread_socket (select_record *me, select_stuff *stuff) /* No event/socket should show up multiple times. Every socket is uniquely identified by its serial number in the global wsock_events record. */ - const LONG ser_num = ((fhandler_socket *) s->fh)->serial_number (); + const LONG ser_num = ((fhandler_socket_wsock *) s->fh)->serial_number (); for (int i = 1; i < si->num_w4; ++i) if (si->ser_num[i] == ser_num) goto continue_outer_loop; @@ -1517,7 +1517,7 @@ start_thread_socket (select_record *me, select_stuff *stuff) _my_tls.locals.select.max_w4 += MAXIMUM_WAIT_OBJECTS; } si->ser_num[si->num_w4] = ser_num; - si->w4[si->num_w4++] = ((fhandler_socket *) s->fh)->wsock_event (); + si->w4[si->num_w4++] = ((fhandler_socket_wsock *) s->fh)->wsock_event (); continue_outer_loop: ; } @@ -1549,7 +1549,7 @@ socket_cleanup (select_record *, select_stuff *stuff) } select_record * -fhandler_socket_inet::select_read (select_stuff *ss) +fhandler_socket_wsock::select_read (select_stuff *ss) { select_record *s = ss->start.next; if (!s->startup) @@ -1565,7 +1565,7 @@ fhandler_socket_inet::select_read (select_stuff *ss) } select_record * -fhandler_socket_inet::select_write (select_stuff *ss) +fhandler_socket_wsock::select_write (select_stuff *ss) { select_record *s = ss->start.next; if (!s->startup) @@ -1586,61 +1586,7 @@ fhandler_socket_inet::select_write (select_stuff *ss) } select_record * -fhandler_socket_inet::select_except (select_stuff *ss) -{ - select_record *s = ss->start.next; - if (!s->startup) - { - s->startup = start_thread_socket; - s->verify = verify_true; - s->cleanup = socket_cleanup; - } - s->peek = peek_socket; - /* FIXME: Is this right? Should these be used as criteria for except? */ - s->except_ready = saw_shutdown_write () || saw_shutdown_read (); - s->except_selected = true; - return s; -} - -select_record * -fhandler_socket_local::select_read (select_stuff *ss) -{ - select_record *s = ss->start.next; - if (!s->startup) - { - s->startup = start_thread_socket; - s->verify = verify_true; - s->cleanup = socket_cleanup; - } - s->peek = peek_socket; - s->read_ready = saw_shutdown_read (); - s->read_selected = true; - return s; -} - -select_record * -fhandler_socket_local::select_write (select_stuff *ss) -{ - select_record *s = ss->start.next; - if (!s->startup) - { - s->startup = start_thread_socket; - s->verify = verify_true; - s->cleanup = socket_cleanup; - } - s->peek = peek_socket; - s->write_ready = saw_shutdown_write () || connect_state () == unconnected; - s->write_selected = true; - if (connect_state () != unconnected) - { - s->except_ready = saw_shutdown_write () || saw_shutdown_read (); - s->except_on_write = true; - } - return s; -} - -select_record * -fhandler_socket_local::select_except (select_stuff *ss) +fhandler_socket_wsock::select_except (select_stuff *ss) { select_record *s = ss->start.next; if (!s->startup)