/* fhandler_socket_inet.cc.

   See fhandler.h for a description of the fhandler classes.

   This file is part of Cygwin.

   This software is a copyrighted work licensed under the terms of the
   Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
   details. */

#define  __INSIDE_CYGWIN_NET__
#define USE_SYS_TYPES_FD_SET

#include "winsup.h"
#ifdef __x86_64__
/* 2014-04-24: Current Mingw headers define sockaddr_in6 using u_long (8 byte)
   because a redefinition for LP64 systems is missing.  This leads to a wrong
   definition and size of sockaddr_in6 when building with winsock headers.
   This definition is also required to use the right u_long type in subsequent
   function calls. */
#undef u_long
#define u_long __ms_u_long
#endif
#include <w32api/ws2tcpip.h>
#include <w32api/mswsock.h>
#include <unistd.h>
#include <asm/byteorder.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/statvfs.h>
#include <cygwin/acl.h>
#include "cygerrno.h"
#include "path.h"
#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
#include "shared_info.h"
#include "wininfo.h"

#define ASYNC_MASK (FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT)
#define EVENT_MASK (FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT|FD_CLOSE)

#define LOCK_EVENTS	\
  if (wsock_mtx && \
      WaitForSingleObject (wsock_mtx, INFINITE) != WAIT_FAILED) \
    {

#define UNLOCK_EVENTS \
      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,
		    struct sockaddr_storage *out, int *outlen)
{
  switch (in->sa_family)
    {
    case AF_INET:
      memcpy (out, in, inlen);
      *outlen = inlen;
      /* If the peer address given in connect or sendto is the ANY address,
	 Winsock fails with WSAEADDRNOTAVAIL, while Linux converts that into
	 a connection/send attempt to LOOPBACK.  We're doing the same here. */
      if (((struct sockaddr_in *) out)->sin_addr.s_addr == htonl (INADDR_ANY))
	((struct sockaddr_in *) out)->sin_addr.s_addr = htonl (INADDR_LOOPBACK);
      return 0;
    case AF_INET6:
      memcpy (out, in, inlen);
      *outlen = inlen;
      /* See comment in AF_INET case. */
      if (IN6_IS_ADDR_UNSPECIFIED (&((struct sockaddr_in6 *) out)->sin6_addr))
	((struct sockaddr_in6 *) out)->sin6_addr = in6addr_loopback;
      return 0;
    default:
      set_errno (EAFNOSUPPORT);
      return SOCKET_ERROR;
    }
}

/* There's no DLL which exports the symbol WSARecvMsg.  One has to call
   WSAIoctl as below to fetch the function pointer.  Why on earth did the
   MS developers decide not to export a normal symbol for these extension
   functions? */
inline int
get_ext_funcptr (SOCKET sock, void *funcptr)
{
  DWORD bret;
  const GUID guid = WSAID_WSARECVMSG;
  return WSAIoctl (sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
		   (void *) &guid, sizeof (GUID), funcptr, sizeof (void *),
		   &bret, NULL, NULL);
}

static int
convert_ws1_ip_optname (int optname)
{
  static int ws2_optname[] =
  {
    0,
    IP_OPTIONS,
    IP_MULTICAST_IF,
    IP_MULTICAST_TTL,
    IP_MULTICAST_LOOP,
    IP_ADD_MEMBERSHIP,
    IP_DROP_MEMBERSHIP,
    IP_TTL,
    IP_TOS,
    IP_DONTFRAGMENT
  };
  return (optname < 1 || optname > _WS1_IP_DONTFRAGMENT)
	 ? optname
	 : ws2_optname[optname];
}

fhandler_socket_wsock::fhandler_socket_wsock () :
  fhandler_socket (),
  wsock_events (NULL),
  wsock_mtx (NULL),
  wsock_evt (NULL),
  status (),
  prot_info_ptr (NULL)
{
  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_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_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_handle (get_handle ());
  int ret = fhs->fixup_before_fork_exec (GetCurrentProcessId ());
  cygheap->user.reimpersonate ();
  if (!ret)
    {
      fhs->fixup_after_fork (GetCurrentProcess ());
      if (fhs->get_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;
  int file_flags = O_RDWR | O_BINARY;

  /* 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_handle ((HANDLE) sock);
  set_addr_family (af);
  set_socket_type (type);
  if (!init_events ())
    return -1;
  if (flags & SOCK_NONBLOCK)
    file_flags |= O_NONBLOCK;
  if (flags & SOCK_CLOEXEC)
    {
      set_close_on_exec (true);
      file_flags |= O_CLOEXEC;
    }
  set_flags (file_flags);
  if (lsp_fixup)
    init_fixup_before ();
  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_wsock (),
  oobinline (false)
{
}

fhandler_socket_inet::~fhandler_socket_inet ()
{
}

int
fhandler_socket_inet::socket (int af, int type, int protocol, int flags)
{
  SOCKET sock;
  int ret;

  /* This test should be covered by ::socket, but make sure we don't
     accidentally try anything else. */
  if (type != SOCK_STREAM && type != SOCK_DGRAM && type != SOCK_RAW)
        {
          set_errno (EINVAL);
          return -1;
        }
  sock = ::socket (af, type, protocol);
  if (sock == INVALID_SOCKET)
    {
      set_winsock_errno ();
      return -1;
    }
  ret = set_socket_handle (sock, af, type, flags);
  if (ret < 0)
    ::closesocket (sock);
  return ret;
}

int
fhandler_socket_inet::socketpair (int af, int type, int protocol, int flags,
				  fhandler_socket *fh_out)
{
  set_errno (EAFNOSUPPORT);
  return -1;
}

int
fhandler_socket_inet::bind (const struct sockaddr *name, int namelen)
{
  int res = -1;

  if (!saw_reuseaddr ())
    {
      /* If the application didn't explicitely request SO_REUSEADDR,
	 enforce POSIX standard socket binding behaviour by setting the
	 SO_EXCLUSIVEADDRUSE socket option.  See cygwin_setsockopt()
	 for a more detailed description. */
      int on = 1;
      int ret = ::setsockopt (get_socket (), SOL_SOCKET,
			      SO_EXCLUSIVEADDRUSE,
			      (const char *) &on, sizeof on);
      debug_printf ("%d = setsockopt(SO_EXCLUSIVEADDRUSE), %E", ret);
    }
  if (::bind (get_socket (), name, namelen))
    set_winsock_errno ();
  else
    res = 0;

  return res;
}

int
fhandler_socket_inet::connect (const struct sockaddr *name, int namelen)
{
  struct sockaddr_storage sst;

  if (get_inet_addr_inet (name, namelen, &sst, &namelen) == SOCKET_ERROR)
    return SOCKET_ERROR;

  /* Initialize connect state to "connect_pending".  State is ultimately set
     to "connected" or "connect_failed" in wait_for_events when the FD_CONNECT
     event occurs.  Note that the underlying OS sockets are always non-blocking
     and a successfully initiated non-blocking Winsock connect always returns
     WSAEWOULDBLOCK.  Thus it's safe to rely on event handling.

     Check for either unconnected or connect_failed since in both cases it's
     allowed to retry connecting the socket.  It's also ok (albeit ugly) to
     call connect to check if a previous non-blocking connect finished.

     Set connect_state before calling connect, otherwise a race condition with
     an already running select or poll might occur. */
  if (connect_state () == unconnected || connect_state () == connect_failed)
    connect_state (connect_pending);

  int res = ::connect (get_socket (), (struct sockaddr *) &sst, namelen);
  if (!is_nonblocking ()
      && res == SOCKET_ERROR
      && WSAGetLastError () == WSAEWOULDBLOCK)
    res = wait_for_events (FD_CONNECT | FD_CLOSE, 0);

  if (res)
    {
      DWORD err = WSAGetLastError ();

      /* Some applications use the ugly technique to check if a non-blocking
         connect succeeded by calling connect again, until it returns EISCONN.
	 This circumvents the event handling and connect_state is never set.
	 Thus we check for this situation here. */
      if (err == WSAEISCONN)
	connect_state (connected);
      /* Winsock returns WSAEWOULDBLOCK if the non-blocking socket cannot be
         conected immediately.  Convert to POSIX/Linux compliant EINPROGRESS. */
      else if (is_nonblocking () && err == WSAEWOULDBLOCK)
	WSASetLastError (WSAEINPROGRESS);
      /* Winsock returns WSAEINVAL if the socket is already a listener.
	 Convert to POSIX/Linux compliant EISCONN. */
      else if (err == WSAEINVAL && connect_state () == listener)
	WSASetLastError (WSAEISCONN);
      /* Any other error except WSAEALREADY during connect_pending means the
         connect failed. */
      else if (connect_state () == connect_pending && err != WSAEALREADY)
	connect_state (connect_failed);
      set_winsock_errno ();
    }

  return res;
}

int
fhandler_socket_inet::listen (int backlog)
{
  int res = ::listen (get_socket (), backlog);
  if (res && WSAGetLastError () == WSAEINVAL)
    {
      /* It's perfectly valid to call listen on an unbound INET socket.
	 In this case the socket is automatically bound to an unused
	 port number, listening on all interfaces.  On WinSock, listen
	 fails with WSAEINVAL when it's called on an unbound socket.
	 So we have to bind manually here to have POSIX semantics. */
      if (get_addr_family () == AF_INET)
	{
	  struct sockaddr_in sin;
	  sin.sin_family = AF_INET;
	  sin.sin_port = 0;
	  sin.sin_addr.s_addr = INADDR_ANY;
	  if (!::bind (get_socket (), (struct sockaddr *) &sin, sizeof sin))
	    res = ::listen (get_socket (), backlog);
	}
      else if (get_addr_family () == AF_INET6)
	{
	  struct sockaddr_in6 sin6;
	  memset (&sin6, 0, sizeof sin6);
	  sin6.sin6_family = AF_INET6;
	  if (!::bind (get_socket (), (struct sockaddr *) &sin6, sizeof sin6))
	    res = ::listen (get_socket (), backlog);
	}
    }
  if (!res)
    connect_state (listener);	/* gets set to connected on accepted socket. */
  else
    set_winsock_errno ();
  return res;
}

int
fhandler_socket_inet::accept4 (struct sockaddr *peer, int *len, int flags)
{
  int ret = -1;
  /* Allows NULL peer and len parameters. */
  struct sockaddr_storage lpeer;
  int llen = sizeof (struct sockaddr_storage);

  /* Windows event handling does not check for the validity of the desired
     flags so we have to do it here. */
  if (connect_state () != listener)
    {
      WSASetLastError (WSAEINVAL);
      set_winsock_errno ();
      return -1;
    }

  SOCKET res = INVALID_SOCKET;
  while (!(res = wait_for_events (FD_ACCEPT | FD_CLOSE, 0))
	 && (res = ::accept (get_socket (), (struct sockaddr *) &lpeer, &llen))
	    == INVALID_SOCKET
	 && WSAGetLastError () == WSAEWOULDBLOCK)
    ;
  if (res == INVALID_SOCKET)
    set_winsock_errno ();
  else
    {
      cygheap_fdnew fd;

      if (fd >= 0)
	{
	  fhandler_socket_inet *sock = (fhandler_socket_inet *)
				       build_fh_dev (dev ());
	  if (sock && sock->set_socket_handle (res, get_addr_family (),
					       get_socket_type (),
					       get_socket_flags ()) == 0)
	    {
	      sock->async_io (false); /* set_socket_handle disables async. */
	      /* No locking necessary at this point. */
	      sock->wsock_events->events = wsock_events->events | FD_WRITE;
	      sock->wsock_events->owner = wsock_events->owner;
	      sock->connect_state (connected);
	      fd = sock;
	      if (fd <= 2)
		set_std_handle (fd);
	      ret = fd;
	      if (peer)
		{
		  memcpy (peer, &lpeer, MIN (*len, llen));
		  *len = llen;
		}
	    }
	  else
	    delete sock;
	}
      if (ret == -1)
	::closesocket (res);
    }
  return ret;
}

int
fhandler_socket_inet::getsockname (struct sockaddr *name, int *namelen)
{
  int res = -1;

  /* WinSock just returns WSAEFAULT if the buffer is too small.  Use a
     big enough local buffer and truncate later as necessary, per POSIX. */
  struct sockaddr_storage sock;
  int len = sizeof sock;
  res = ::getsockname (get_socket (), (struct sockaddr *) &sock, &len);
  if (!res)
    {
      memcpy (name, &sock, MIN (*namelen, len));
      *namelen = len;
    }
  else
    {
      if (WSAGetLastError () == WSAEINVAL)
	{
	  /* WinSock returns WSAEINVAL if the socket is locally
	     unbound.  Per SUSv3 this is not an error condition.
	     We're faking a valid return value here by creating the
	     same content in the sockaddr structure as on Linux. */
	  memset (&sock, 0, sizeof sock);
	  sock.ss_family = get_addr_family ();
	  switch (get_addr_family ())
	    {
	    case AF_INET:
	      res = 0;
	      len = (int) sizeof (struct sockaddr_in);
	      break;
	    case AF_INET6:
	      res = 0;
	      len = (int) sizeof (struct sockaddr_in6);
	      break;
	    default:
	      WSASetLastError (WSAEOPNOTSUPP);
	      break;
	    }
	  if (!res)
	    {
	      memcpy (name, &sock, MIN (*namelen, len));
	      *namelen = len;
	    }
	}
      if (res)
	set_winsock_errno ();
    }
  return res;
}

int
fhandler_socket_inet::getpeername (struct sockaddr *name, int *namelen)
{
  /* Always use a local big enough buffer and truncate later as necessary
     per POSIX.  WinSock unfortunately only returns WSAEFAULT if the buffer
     is too small. */
  struct sockaddr_storage sock;
  int len = sizeof sock;
  int res = ::getpeername (get_socket (), (struct sockaddr *) &sock, &len);
  if (res)
    set_winsock_errno ();
  else
    {
      memcpy (name, &sock, MIN (*namelen, len));
      *namelen = len;
    }
  return res;
}

int
fhandler_socket_wsock::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_wsock::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);
    }
  return res;
}

ssize_t
fhandler_socket_inet::recv_internal (LPWSAMSG wsamsg, bool use_recvmsg)
{
  ssize_t res = 0;
  DWORD ret = 0, wret;
  int evt_mask = (wsamsg->dwFlags & MSG_OOB) ? FD_OOB : FD_READ;
  LPWSABUF &wsabuf = wsamsg->lpBuffers;
  ULONG &wsacnt = wsamsg->dwBufferCount;
  static NO_COPY LPFN_WSARECVMSG WSARecvMsg;
  bool read_oob = false;

  /* CV 2014-10-26: Do not check for the connect_state at this point.  In
     certain scenarios there's no way to check the connect state reliably.
     Example (hexchat): Parent process creates socket, forks, child process
     calls connect, parent process calls read.  Even if the event handling
     allows to check for FD_CONNECT in the parent, there is always yet another
     scenario we can easily break. */

  DWORD wait_flags = wsamsg->dwFlags;
  bool waitall = !!(wait_flags & MSG_WAITALL);
  wsamsg->dwFlags &= (MSG_OOB | MSG_PEEK | MSG_DONTROUTE);
  if (use_recvmsg)
    {
      if (!WSARecvMsg
	  && get_ext_funcptr (get_socket (), &WSARecvMsg) == SOCKET_ERROR)
	{
	  if (wsamsg->Control.len > 0)
	    {
	      set_winsock_errno ();
	      return SOCKET_ERROR;
	    }
	  use_recvmsg = false;
	}
      else /* Only MSG_PEEK is supported by WSARecvMsg. */
	wsamsg->dwFlags &= MSG_PEEK;
    }
  if (waitall)
    {
      if (get_socket_type () != SOCK_STREAM)
	{
	  WSASetLastError (WSAEOPNOTSUPP);
	  set_winsock_errno ();
	  return SOCKET_ERROR;
	}
      if (is_nonblocking () || (wsamsg->dwFlags & (MSG_OOB | MSG_PEEK)))
	waitall = false;
    }

  /* recv() returns EINVAL if MSG_OOB flag is set in inline mode. */
  if (oobinline && (wsamsg->dwFlags & MSG_OOB))
    {
      set_errno (EINVAL);
      return SOCKET_ERROR;
    }

  /* Check whether OOB data is ready or not */
  if (get_socket_type () == SOCK_STREAM)
    if ((wsamsg->dwFlags & MSG_OOB) || oobinline)
      {
	u_long atmark = 0;
#ifdef __x86_64__
	/* SIOCATMARK = _IOR('s',7,u_long) */
	int err = ::ioctlsocket (get_socket (), _IOR('s',7,u_long), &atmark);
#else
	int err = ::ioctlsocket (get_socket (), SIOCATMARK, &atmark);
#endif
	if (err)
	  {
	    set_winsock_errno ();
	    return SOCKET_ERROR;
	  }
	/* If there is no OOB data, recv() with MSG_OOB returns EINVAL.
	   Note: The return value of SIOCATMARK in non-inline mode of
	   winsock is FALSE if OOB data exists, TRUE otherwise. */
	if (atmark && (wsamsg->dwFlags & MSG_OOB))
	  {
	    /* No OOB data */
	    set_errno (EINVAL);
	    return SOCKET_ERROR;
	  }
	/* Inline mode for out-of-band (OOB) data of winsock is
	   completely broken. That is, SIOCATMARK always returns
	   TRUE in inline mode. Due to this problem, application
	   cannot determine OOB data at all. Therefore the behavior
	   of a socket with SO_OOBINLINE set is simulated using
	   a socket with SO_OOBINLINE not set. In this fake inline
	   mode, the order of the OOB and non-OOB data is not
	   preserved. OOB data is read before non-OOB data sent
	   prior to the OOB data.  However, this most likely is
	   not a problem in most cases. */
	/* If there is OOB data, read OOB data using MSG_OOB in
	   fake inline mode. */
	if (!atmark && oobinline)
	  {
	    read_oob = true;
	    evt_mask = FD_OOB;
	  }
      }

  /* Note: Don't call WSARecvFrom(MSG_PEEK) without actually having data
     waiting in the buffers, otherwise the event handling gets messed up
     for some reason. */
  while (!(res = wait_for_events (evt_mask | FD_CLOSE, wait_flags))
	 || saw_shutdown_read ())
    {
      DWORD dwFlags = wsamsg->dwFlags | (read_oob ? MSG_OOB : 0);
      if (use_recvmsg)
	res = WSARecvMsg (get_socket (), wsamsg, &wret, NULL, NULL);
      /* This is working around a really weird problem in WinSock.

	 Assume you create a socket, fork the process (thus duplicating
	 the socket), connect the socket in the child, then call recv
	 on the original socket handle in the parent process.
	 In this scenario, calls to WinSock's recvfrom and WSARecvFrom
	 in the parent will fail with WSAEINVAL, regardless whether both
	 address parameters, name and namelen, are NULL or point to valid
	 storage.  However, calls to recv and WSARecv succeed as expected.
	 Per MSDN, WSAEINVAL in the context of recv means  "The socket has not
	 been bound".  It is as if the recvfrom functions test if the socket
	 is bound locally, but in the parent process, WinSock doesn't know
	 about that and fails, while the same test is omitted in the recv
	 functions.

	 This also covers another weird case: WinSock returns WSAEFAULT if
	 namelen is a valid pointer while name is NULL.  Both parameters are
	 ignored for TCP sockets, so this only occurs when using UDP socket. */
      else if (!wsamsg->name || get_socket_type () == SOCK_STREAM)
	res = WSARecv (get_socket (), wsabuf, wsacnt, &wret, &dwFlags,
		       NULL, NULL);
      else
	res = WSARecvFrom (get_socket (), wsabuf, wsacnt, &wret,
			   &dwFlags, wsamsg->name, &wsamsg->namelen,
			   NULL, NULL);
      if (!res)
	{
	  ret += wret;
	  if (!waitall)
	    break;
	  while (wret && wsacnt)
	    {
	      if (wsabuf->len > wret)
		{
		  wsabuf->len -= wret;
		  wsabuf->buf += wret;
		  wret = 0;
		}
	      else
		{
		  wret -= wsabuf->len;
		  ++wsabuf;
		  --wsacnt;
		}
	    }
	  if (!wret)
	    break;
	}
      else if (WSAGetLastError () != WSAEWOULDBLOCK)
	break;
    }

  if (res)
    {
      /* According to SUSv3, errno isn't set in that case and no error
	 condition is returned. */
      if (WSAGetLastError () == WSAEMSGSIZE)
	ret += wret;
      else if (!ret)
	{
	  /* ESHUTDOWN isn't defined for recv in SUSv3.  Simply EOF is returned
	     in this case. */
	  if (WSAGetLastError () == WSAESHUTDOWN)
	    ret = 0;
	  else
	    {
	      set_winsock_errno ();
	      return SOCKET_ERROR;
	    }
	}
    }

  return ret;
}

ssize_t
fhandler_socket_wsock::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_wsock::recvmsg (struct msghdr *msg, int flags)
{
  /* 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_wsock::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_wsock::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);
}

ssize_t
fhandler_socket_wsock::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);

  /* MSG_EOR not supported by any protocol */
  if (flags & MSG_EOR)
    {
      set_errno (EOPNOTSUPP);
      return SOCKET_ERROR;
    }

  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_inet::sendto (const void *in_ptr, size_t len, int flags,
			      const struct sockaddr *to, int tolen)
{
  char *ptr = (char *) in_ptr;
  struct sockaddr_storage sst;

  if (to && get_inet_addr_inet (to, tolen, &sst, &tolen) == SOCKET_ERROR)
    return SOCKET_ERROR;

#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 = { to ? (struct sockaddr *) &sst : NULL, tolen,
		    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 = { to ? (struct sockaddr *) &sst : NULL, tolen,
		    &wsabuf, 1,
		    { 0, NULL},
		    0 };
#endif
  return send_internal (&wsamsg, flags);
}

ssize_t
fhandler_socket_inet::sendmsg (const struct msghdr *msg, int flags)
{
  struct sockaddr_storage sst;
  int len = 0;

  if (msg->msg_name
      && get_inet_addr_inet ((struct sockaddr *) msg->msg_name,
			     msg->msg_namelen, &sst, &len) == SOCKET_ERROR)
    return SOCKET_ERROR;

  WSABUF wsabuf[msg->msg_iovlen];
  WSABUF *wsaptr = wsabuf;
  const struct iovec *iovptr = msg->msg_iov;
  for (int i = 0; i < msg->msg_iovlen; ++i)
    {
      wsaptr->len = iovptr->iov_len;
      (wsaptr++)->buf = (char *) (iovptr++)->iov_base;
    }
  /* Disappointing but true:  Even if WSASendMsg is supported, it's only
     supported for datagram and raw sockets. */
  DWORD controllen = (DWORD) ((get_socket_type () == SOCK_STREAM)
			      ? 0 : msg->msg_controllen);
  WSAMSG wsamsg = { msg->msg_name ? (struct sockaddr *) &sst : NULL, len,
		    wsabuf, (DWORD) msg->msg_iovlen,
		    { controllen, (char *) msg->msg_control },
		    0 };
  return send_internal (&wsamsg, flags);
}

ssize_t
fhandler_socket_wsock::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_wsock::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);
}

int
fhandler_socket_inet::setsockopt (int level, int optname, const void *optval,
				  socklen_t optlen)
{
  bool ignore = false;
  int ret = -1;

  /* Preprocessing setsockopt.  Set ignore to true if setsockopt call should
     get skipped entirely. */
  switch (level)
    {
    case SOL_SOCKET:
      switch (optname)
	{
	case SO_PEERCRED:
	  set_errno (ENOPROTOOPT);
	  return -1;

	case SO_REUSEADDR:
	  /* Per POSIX we must not be able to reuse a complete duplicate of a
	     local TCP address (same IP, same port), even if SO_REUSEADDR has
	     been set.  This behaviour is maintained in WinSock for backward
	     compatibility, while the WinSock standard behaviour of stream
	     socket binding is equivalent to the POSIX behaviour as if
	     SO_REUSEADDR has been set.  The SO_EXCLUSIVEADDRUSE option has
	     been added to allow an application to request POSIX standard
	     behaviour in the non-SO_REUSEADDR case.

	     To emulate POSIX socket binding behaviour, note that SO_REUSEADDR
	     has been set but don't call setsockopt.  Instead
	     fhandler_socket::bind sets SO_EXCLUSIVEADDRUSE if the application
	     did not set SO_REUSEADDR. */
	  if (optlen < (socklen_t) sizeof (int))
	    {
	      set_errno (EINVAL);
	      return ret;
	    }
	  if (get_socket_type () == SOCK_STREAM)
	    ignore = true;
	  break;

	case SO_RCVTIMEO:
	case SO_SNDTIMEO:
	  if (optlen < (socklen_t) sizeof (struct timeval))
	    {
	      set_errno (EINVAL);
	      return ret;
	    }
	  if (timeval_to_ms ((struct timeval *) optval,
			     (optname == SO_RCVTIMEO) ? rcvtimeo ()
						      : sndtimeo ()))
	    ret = 0;
	  else
	    set_errno (EDOM);
	  return ret;

	case SO_OOBINLINE:
	  /* Inline mode for out-of-band (OOB) data of winsock is
	     completely broken. That is, SIOCATMARK always returns
	     TRUE in inline mode. Due to this problem, application
	     cannot determine OOB data at all. Therefore the behavior
	     of a socket with SO_OOBINLINE set is simulated using
	     a socket with SO_OOBINLINE not set. In this fake inline
	     mode, the order of the OOB and non-OOB data is not
	     preserved. OOB data is read before non-OOB data sent
	     prior to the OOB data.  However, this most likely is
	     not a problem in most cases. */
	  /* Here, instead of actually setting inline mode, simply
	     set the variable oobinline. */
	  oobinline = *(int *) optval ? true : false;
	  ignore = true;
	  break;

	default:
	  break;
	}
      break;

    case IPPROTO_IP:
      /* Old applications still use the old WinSock1 IPPROTO_IP values. */
      if (CYGWIN_VERSION_CHECK_FOR_USING_WINSOCK1_VALUES)
	optname = convert_ws1_ip_optname (optname);
      switch (optname)
	{
	case IP_TOS:
	  /* Winsock doesn't support setting the IP_TOS field with setsockopt
	     and TOS was never implemented for TCP anyway.  setsockopt returns
	     WinSock error 10022, WSAEINVAL when trying to set the IP_TOS
	     field.  We just return 0 instead. */
	  ignore = true;
	  break;

	default:
	  break;
	}
      break;

    case IPPROTO_IPV6:
      {
      switch (optname)
	{
	case IPV6_TCLASS:
	  /* Unsupported */
	  ignore = true;
	  break;

	default:
	  break;
	}
      }
    default:
      break;
    }

  /* Call Winsock setsockopt (or not) */
  if (ignore)
    ret = 0;
  else
    {
      ret = ::setsockopt (get_socket (), level, optname, (const char *) optval,
			  optlen);
      if (ret == SOCKET_ERROR)
	{
	  set_winsock_errno ();
	  return ret;
	}
    }

  if (optlen == (socklen_t) sizeof (int))
    debug_printf ("setsockopt optval=%x", *(int *) optval);

  /* Postprocessing setsockopt, setting fhandler_socket members, etc. */
  switch (level)
    {
    case SOL_SOCKET:
      switch (optname)
	{
	case SO_REUSEADDR:
	  saw_reuseaddr (*(int *) optval);
	  break;

	case SO_RCVBUF:
	  rmem (*(int *) optval);
	  break;

	case SO_SNDBUF:
	  wmem (*(int *) optval);
	  break;

	default:
	  break;
	}
      break;

    default:
      break;
    }

  return ret;
}

int
fhandler_socket_inet::getsockopt (int level, int optname, const void *optval,
				  socklen_t *optlen)
{
  bool onebyte = false;
  int ret = -1;

  /* Preprocessing getsockopt. */
  switch (level)
    {
    case SOL_SOCKET:
      switch (optname)
	{
	case SO_PEERCRED:
	  set_errno (ENOPROTOOPT);
	  return -1;

	case SO_REUSEADDR:
	  {
	    unsigned int *reuseaddr = (unsigned int *) optval;

	    if (*optlen < (socklen_t) sizeof *reuseaddr)
	      {
		set_errno (EINVAL);
		return -1;
	      }
	    *reuseaddr = saw_reuseaddr();
	    *optlen = (socklen_t) sizeof *reuseaddr;
	    return 0;
	  }

	case SO_RCVTIMEO:
	case SO_SNDTIMEO:
	  {
	    struct timeval *time_out = (struct timeval *) optval;

	    if (*optlen < (socklen_t) sizeof *time_out)
	      {
		set_errno (EINVAL);
		return -1;
	      }
	    DWORD ms = (optname == SO_RCVTIMEO) ? rcvtimeo () : sndtimeo ();
	    if (ms == 0 || ms == INFINITE)
	      {
		time_out->tv_sec = 0;
		time_out->tv_usec = 0;
	      }
	    else
	      {
		time_out->tv_sec = ms / MSPERSEC;
		time_out->tv_usec = ((ms % MSPERSEC) * USPERSEC) / MSPERSEC;
	      }
	    *optlen = (socklen_t) sizeof *time_out;
	    return 0;
	  }

	case SO_TYPE:
	  {
	    unsigned int *type = (unsigned int *) optval;
	    *type = get_socket_type ();
	    *optlen = (socklen_t) sizeof *type;
	    return 0;
	  }

	case SO_OOBINLINE:
	  *(int *) optval = oobinline ? 1 : 0;
	  return 0;

	default:
	  break;
	}
      break;

    case IPPROTO_IP:
      /* Old applications still use the old WinSock1 IPPROTO_IP values. */
      if (CYGWIN_VERSION_CHECK_FOR_USING_WINSOCK1_VALUES)
	optname = convert_ws1_ip_optname (optname);
      break;

    default:
      break;
    }

  /* Call Winsock getsockopt */
  ret = ::getsockopt (get_socket (), level, optname, (char *) optval,
		      (int *) optlen);
  if (ret == SOCKET_ERROR)
    {
      set_winsock_errno ();
      return ret;
    }

  /* Postprocessing getsockopt, setting fhandler_socket members, etc.  Set
     onebyte true for options returning BOOLEAN instead of a boolean DWORD. */
  switch (level)
    {
    case SOL_SOCKET:
      switch (optname)
	{
	case SO_ERROR:
	  {
	    int *e = (int *) optval;
	    debug_printf ("WinSock SO_ERROR = %d", *e);
	    *e = find_winsock_errno (*e);
	  }
	  break;

	case SO_KEEPALIVE:
	case SO_DONTROUTE:
	  onebyte = true;
	  break;

	default:
	  break;
	}
      break;
    case IPPROTO_TCP:
      switch (optname)
	{
	case TCP_NODELAY:
	  onebyte = true;
	  break;

	default:
	  break;
	}
    default:
      break;
    }

  if (onebyte)
    {
      /* Regression in Vista and later: instead of a 4 byte BOOL value, a
	 1 byte BOOLEAN value is returned, in contrast to older systems and
	 the documentation.  Since an int type is expected by the calling
	 application, we convert the result here.  For some reason only three
	 BSD-compatible socket options seem to be affected. */
      BOOLEAN *in = (BOOLEAN *) optval;
      int *out = (int *) optval;
      *out = *in;
      *optlen = 4;
    }

  return ret;
}

int
fhandler_socket_wsock::ioctl (unsigned int cmd, void *p)
{
  int res;

  switch (cmd)
    {
    /* Here we handle only ioctl commands which are understood by Winsock.
       However, we have a problem, which is, the different size of u_long
       in Windows and 64 bit Cygwin.  This affects the definitions of
       FIOASYNC, etc, because they are defined in terms of sizeof(u_long).
       So we have to use case labels which are independent of the sizeof
       u_long.  Since we're redefining u_long at the start of this file to
       matching Winsock's idea of u_long, we can use the real definitions in
       calls to Windows.  In theory we also have to make sure to convert the
       different ideas of u_long between the application and Winsock, but
       fortunately, the parameters defined as u_long pointers are on Linux
       and BSD systems defined as int pointer, so the applications will
       use a type of the expected size.  Hopefully. */
    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);
      /* In winsock, the return value of SIOCATMARK is FALSE if
	 OOB data exists, TRUE otherwise. This is almost opposite
	 to expectation. */
#ifdef __x86_64__
      /* SIOCATMARK = _IOR('s',7,u_long) */
      if (cmd == _IOR('s',7,u_long) && !res)
	*(u_long *)p = !*(u_long *)p;
#else
      if (cmd == SIOCATMARK && !res)
	*(u_long *)p = !*(u_long *)p;
#endif
      break;
    default:
      res = fhandler_socket::ioctl (cmd, p);
      break;
    }
  syscall_printf ("%d = ioctl_socket(%x, %p)", res, cmd, p);
  return res;
}

int
fhandler_socket_wsock::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;
}