This is the mail archive of the cygwin-cvs@cygwin.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[newlib-cygwin] Cygwin: encapsulate Winsock based fhandler_socket classes


https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=b79018ee3a36140a82e2dfa2d7a71fc0bf15d892

commit b79018ee3a36140a82e2dfa2d7a71fc0bf15d892
Author: Corinna Vinschen <corinna@vinschen.de>
Date:   Fri Feb 23 15:24:18 2018 +0100

    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 <corinna@vinschen.de>

Diff:
---
 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 086be73..93bbdfe 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 4c7fea3..3816110 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;
@@ -500,18 +500,6 @@ class fhandler_socket: public fhandler_base
   }
 
  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;
  public:
@@ -528,55 +516,29 @@ class fhandler_socket: public fhandler_base
   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:
-  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);
+ public:
+  fhandler_socket ();
+  ~fhandler_socket ();
+  fhandler_socket *is_socket () { return this; }
+
   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 0cdf6fa..292e648 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 b2bc193..0668c10 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 298a378..ca38442 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;
@@ -1280,235 +1215,6 @@ fhandler_socket_local::recv_internal (LPWSAMSG wsamsg, bool use_recvmsg)
 }
 
 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 6b88f91..fe6576d 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 ea45b70..4404134 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 86e7cd8..023bec0 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)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]