Blame src/win/winsock.c

Packit b5b901
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
Packit b5b901
 *
Packit b5b901
 * Permission is hereby granted, free of charge, to any person obtaining a copy
Packit b5b901
 * of this software and associated documentation files (the "Software"), to
Packit b5b901
 * deal in the Software without restriction, including without limitation the
Packit b5b901
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
Packit b5b901
 * sell copies of the Software, and to permit persons to whom the Software is
Packit b5b901
 * furnished to do so, subject to the following conditions:
Packit b5b901
 *
Packit b5b901
 * The above copyright notice and this permission notice shall be included in
Packit b5b901
 * all copies or substantial portions of the Software.
Packit b5b901
 *
Packit b5b901
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit b5b901
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit b5b901
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Packit b5b901
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Packit b5b901
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
Packit b5b901
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
Packit b5b901
 * IN THE SOFTWARE.
Packit b5b901
 */
Packit b5b901
Packit b5b901
#include <assert.h>
Packit b5b901
#include <stdlib.h>
Packit b5b901
Packit b5b901
#include "uv.h"
Packit b5b901
#include "internal.h"
Packit b5b901
Packit b5b901
Packit b5b901
/* Whether there are any non-IFS LSPs stacked on TCP */
Packit b5b901
int uv_tcp_non_ifs_lsp_ipv4;
Packit b5b901
int uv_tcp_non_ifs_lsp_ipv6;
Packit b5b901
Packit b5b901
/* Ip address used to bind to any port at any interface */
Packit b5b901
struct sockaddr_in uv_addr_ip4_any_;
Packit b5b901
struct sockaddr_in6 uv_addr_ip6_any_;
Packit b5b901
Packit b5b901
Packit b5b901
/*
Packit b5b901
 * Retrieves the pointer to a winsock extension function.
Packit b5b901
 */
Packit b5b901
static BOOL uv_get_extension_function(SOCKET socket, GUID guid,
Packit b5b901
    void **target) {
Packit b5b901
  int result;
Packit b5b901
  DWORD bytes;
Packit b5b901
Packit b5b901
  result = WSAIoctl(socket,
Packit b5b901
                    SIO_GET_EXTENSION_FUNCTION_POINTER,
Packit b5b901
                    &guid,
Packit b5b901
                    sizeof(guid),
Packit b5b901
                    (void*)target,
Packit b5b901
                    sizeof(*target),
Packit b5b901
                    &bytes,
Packit b5b901
                    NULL,
Packit b5b901
                    NULL);
Packit b5b901
Packit b5b901
  if (result == SOCKET_ERROR) {
Packit b5b901
    *target = NULL;
Packit b5b901
    return FALSE;
Packit b5b901
  } else {
Packit b5b901
    return TRUE;
Packit b5b901
  }
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target) {
Packit b5b901
  const GUID wsaid_acceptex = WSAID_ACCEPTEX;
Packit b5b901
  return uv_get_extension_function(socket, wsaid_acceptex, (void**)target);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target) {
Packit b5b901
  const GUID wsaid_connectex = WSAID_CONNECTEX;
Packit b5b901
  return uv_get_extension_function(socket, wsaid_connectex, (void**)target);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
Packit b5b901
void uv_winsock_init(void) {
Packit b5b901
  WSADATA wsa_data;
Packit b5b901
  int errorno;
Packit b5b901
  SOCKET dummy;
Packit b5b901
  WSAPROTOCOL_INFOW protocol_info;
Packit b5b901
  int opt_len;
Packit b5b901
Packit b5b901
  /* Set implicit binding address used by connectEx */
Packit b5b901
  if (uv_ip4_addr("0.0.0.0", 0, &uv_addr_ip4_any_)) {
Packit b5b901
    abort();
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (uv_ip6_addr("::", 0, &uv_addr_ip6_any_)) {
Packit b5b901
    abort();
Packit b5b901
  }
Packit b5b901
Packit Service e08953
  /* Skip initialization in safe mode without network support */
Packit Service e08953
  if (1 == GetSystemMetrics(SM_CLEANBOOT)) return;
Packit b5b901
Packit Service e08953
  /* Initialize winsock */
Packit Service e08953
  errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data);
Packit Service e08953
  if (errorno != 0) {
Packit Service e08953
    uv_fatal_error(errorno, "WSAStartup");
Packit Service e08953
  }
Packit Service e08953
Packit Service e08953
  /* Try to detect non-IFS LSPs */
Packit Service e08953
  uv_tcp_non_ifs_lsp_ipv4 = 1;
Packit Service e08953
  dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
Packit b5b901
  if (dummy != INVALID_SOCKET) {
Packit b5b901
    opt_len = (int) sizeof protocol_info;
Packit b5b901
    if (getsockopt(dummy,
Packit b5b901
                   SOL_SOCKET,
Packit b5b901
                   SO_PROTOCOL_INFOW,
Packit b5b901
                   (char*) &protocol_info,
Packit Service e08953
                   &opt_len) == 0) {
Packit Service e08953
      if (protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES)
Packit Service e08953
        uv_tcp_non_ifs_lsp_ipv4 = 0;
Packit Service e08953
    }
Packit Service e08953
    closesocket(dummy);
Packit b5b901
  }
Packit b5b901
Packit Service e08953
  /* Try to detect IPV6 support and non-IFS LSPs */
Packit Service e08953
  uv_tcp_non_ifs_lsp_ipv6 = 1;
Packit b5b901
  dummy = socket(AF_INET6, SOCK_STREAM, IPPROTO_IP);
Packit b5b901
  if (dummy != INVALID_SOCKET) {
Packit b5b901
    opt_len = (int) sizeof protocol_info;
Packit b5b901
    if (getsockopt(dummy,
Packit b5b901
                   SOL_SOCKET,
Packit b5b901
                   SO_PROTOCOL_INFOW,
Packit b5b901
                   (char*) &protocol_info,
Packit Service e08953
                   &opt_len) == 0) {
Packit Service e08953
      if (protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES)
Packit Service e08953
        uv_tcp_non_ifs_lsp_ipv6 = 0;
Packit Service e08953
    }
Packit Service e08953
    closesocket(dummy);
Packit b5b901
  }
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_ntstatus_to_winsock_error(NTSTATUS status) {
Packit b5b901
  switch (status) {
Packit b5b901
    case STATUS_SUCCESS:
Packit b5b901
      return ERROR_SUCCESS;
Packit b5b901
Packit b5b901
    case STATUS_PENDING:
Packit b5b901
      return ERROR_IO_PENDING;
Packit b5b901
Packit b5b901
    case STATUS_INVALID_HANDLE:
Packit b5b901
    case STATUS_OBJECT_TYPE_MISMATCH:
Packit b5b901
      return WSAENOTSOCK;
Packit b5b901
Packit b5b901
    case STATUS_INSUFFICIENT_RESOURCES:
Packit b5b901
    case STATUS_PAGEFILE_QUOTA:
Packit b5b901
    case STATUS_COMMITMENT_LIMIT:
Packit b5b901
    case STATUS_WORKING_SET_QUOTA:
Packit b5b901
    case STATUS_NO_MEMORY:
Packit b5b901
    case STATUS_QUOTA_EXCEEDED:
Packit b5b901
    case STATUS_TOO_MANY_PAGING_FILES:
Packit b5b901
    case STATUS_REMOTE_RESOURCES:
Packit b5b901
      return WSAENOBUFS;
Packit b5b901
Packit b5b901
    case STATUS_TOO_MANY_ADDRESSES:
Packit b5b901
    case STATUS_SHARING_VIOLATION:
Packit b5b901
    case STATUS_ADDRESS_ALREADY_EXISTS:
Packit b5b901
      return WSAEADDRINUSE;
Packit b5b901
Packit b5b901
    case STATUS_LINK_TIMEOUT:
Packit b5b901
    case STATUS_IO_TIMEOUT:
Packit b5b901
    case STATUS_TIMEOUT:
Packit b5b901
      return WSAETIMEDOUT;
Packit b5b901
Packit b5b901
    case STATUS_GRACEFUL_DISCONNECT:
Packit b5b901
      return WSAEDISCON;
Packit b5b901
Packit b5b901
    case STATUS_REMOTE_DISCONNECT:
Packit b5b901
    case STATUS_CONNECTION_RESET:
Packit b5b901
    case STATUS_LINK_FAILED:
Packit b5b901
    case STATUS_CONNECTION_DISCONNECTED:
Packit b5b901
    case STATUS_PORT_UNREACHABLE:
Packit b5b901
    case STATUS_HOPLIMIT_EXCEEDED:
Packit b5b901
      return WSAECONNRESET;
Packit b5b901
Packit b5b901
    case STATUS_LOCAL_DISCONNECT:
Packit b5b901
    case STATUS_TRANSACTION_ABORTED:
Packit b5b901
    case STATUS_CONNECTION_ABORTED:
Packit b5b901
      return WSAECONNABORTED;
Packit b5b901
Packit b5b901
    case STATUS_BAD_NETWORK_PATH:
Packit b5b901
    case STATUS_NETWORK_UNREACHABLE:
Packit b5b901
    case STATUS_PROTOCOL_UNREACHABLE:
Packit b5b901
      return WSAENETUNREACH;
Packit b5b901
Packit b5b901
    case STATUS_HOST_UNREACHABLE:
Packit b5b901
      return WSAEHOSTUNREACH;
Packit b5b901
Packit b5b901
    case STATUS_CANCELLED:
Packit b5b901
    case STATUS_REQUEST_ABORTED:
Packit b5b901
      return WSAEINTR;
Packit b5b901
Packit b5b901
    case STATUS_BUFFER_OVERFLOW:
Packit b5b901
    case STATUS_INVALID_BUFFER_SIZE:
Packit b5b901
      return WSAEMSGSIZE;
Packit b5b901
Packit b5b901
    case STATUS_BUFFER_TOO_SMALL:
Packit b5b901
    case STATUS_ACCESS_VIOLATION:
Packit b5b901
      return WSAEFAULT;
Packit b5b901
Packit b5b901
    case STATUS_DEVICE_NOT_READY:
Packit b5b901
    case STATUS_REQUEST_NOT_ACCEPTED:
Packit b5b901
      return WSAEWOULDBLOCK;
Packit b5b901
Packit b5b901
    case STATUS_INVALID_NETWORK_RESPONSE:
Packit b5b901
    case STATUS_NETWORK_BUSY:
Packit b5b901
    case STATUS_NO_SUCH_DEVICE:
Packit b5b901
    case STATUS_NO_SUCH_FILE:
Packit b5b901
    case STATUS_OBJECT_PATH_NOT_FOUND:
Packit b5b901
    case STATUS_OBJECT_NAME_NOT_FOUND:
Packit b5b901
    case STATUS_UNEXPECTED_NETWORK_ERROR:
Packit b5b901
      return WSAENETDOWN;
Packit b5b901
Packit b5b901
    case STATUS_INVALID_CONNECTION:
Packit b5b901
      return WSAENOTCONN;
Packit b5b901
Packit b5b901
    case STATUS_REMOTE_NOT_LISTENING:
Packit b5b901
    case STATUS_CONNECTION_REFUSED:
Packit b5b901
      return WSAECONNREFUSED;
Packit b5b901
Packit b5b901
    case STATUS_PIPE_DISCONNECTED:
Packit b5b901
      return WSAESHUTDOWN;
Packit b5b901
Packit b5b901
    case STATUS_CONFLICTING_ADDRESSES:
Packit b5b901
    case STATUS_INVALID_ADDRESS:
Packit b5b901
    case STATUS_INVALID_ADDRESS_COMPONENT:
Packit b5b901
      return WSAEADDRNOTAVAIL;
Packit b5b901
Packit b5b901
    case STATUS_NOT_SUPPORTED:
Packit b5b901
    case STATUS_NOT_IMPLEMENTED:
Packit b5b901
      return WSAEOPNOTSUPP;
Packit b5b901
Packit b5b901
    case STATUS_ACCESS_DENIED:
Packit b5b901
      return WSAEACCES;
Packit b5b901
Packit b5b901
    default:
Packit b5b901
      if ((status & (FACILITY_NTWIN32 << 16)) == (FACILITY_NTWIN32 << 16) &&
Packit b5b901
          (status & (ERROR_SEVERITY_ERROR | ERROR_SEVERITY_WARNING))) {
Packit b5b901
        /* It's a windows error that has been previously mapped to an ntstatus
Packit b5b901
         * code. */
Packit b5b901
        return (DWORD) (status & 0xffff);
Packit b5b901
      } else {
Packit b5b901
        /* The default fallback for unmappable ntstatus codes. */
Packit b5b901
        return WSAEINVAL;
Packit b5b901
      }
Packit b5b901
  }
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
/*
Packit b5b901
 * This function provides a workaround for a bug in the winsock implementation
Packit b5b901
 * of WSARecv. The problem is that when SetFileCompletionNotificationModes is
Packit b5b901
 * used to avoid IOCP notifications of completed reads, WSARecv does not
Packit b5b901
 * reliably indicate whether we can expect a completion package to be posted
Packit b5b901
 * when the receive buffer is smaller than the received datagram.
Packit b5b901
 *
Packit b5b901
 * However it is desirable to use SetFileCompletionNotificationModes because
Packit b5b901
 * it yields a massive performance increase.
Packit b5b901
 *
Packit b5b901
 * This function provides a workaround for that bug, but it only works for the
Packit b5b901
 * specific case that we need it for. E.g. it assumes that the "avoid iocp"
Packit b5b901
 * bit has been set, and supports only overlapped operation. It also requires
Packit b5b901
 * the user to use the default msafd driver, doesn't work when other LSPs are
Packit b5b901
 * stacked on top of it.
Packit b5b901
 */
Packit b5b901
int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers,
Packit b5b901
    DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped,
Packit b5b901
    LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) {
Packit b5b901
  NTSTATUS status;
Packit b5b901
  void* apc_context;
Packit b5b901
  IO_STATUS_BLOCK* iosb = (IO_STATUS_BLOCK*) &overlapped->Internal;
Packit b5b901
  AFD_RECV_INFO info;
Packit b5b901
  DWORD error;
Packit b5b901
Packit b5b901
  if (overlapped == NULL || completion_routine != NULL) {
Packit b5b901
    WSASetLastError(WSAEINVAL);
Packit b5b901
    return SOCKET_ERROR;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  info.BufferArray = buffers;
Packit b5b901
  info.BufferCount = buffer_count;
Packit b5b901
  info.AfdFlags = AFD_OVERLAPPED;
Packit b5b901
  info.TdiFlags = TDI_RECEIVE_NORMAL;
Packit b5b901
Packit b5b901
  if (*flags & MSG_PEEK) {
Packit b5b901
    info.TdiFlags |= TDI_RECEIVE_PEEK;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (*flags & MSG_PARTIAL) {
Packit b5b901
    info.TdiFlags |= TDI_RECEIVE_PARTIAL;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (!((intptr_t) overlapped->hEvent & 1)) {
Packit b5b901
    apc_context = (void*) overlapped;
Packit b5b901
  } else {
Packit b5b901
    apc_context = NULL;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  iosb->Status = STATUS_PENDING;
Packit b5b901
  iosb->Pointer = 0;
Packit b5b901
Packit b5b901
  status = pNtDeviceIoControlFile((HANDLE) socket,
Packit b5b901
                                  overlapped->hEvent,
Packit b5b901
                                  NULL,
Packit b5b901
                                  apc_context,
Packit b5b901
                                  iosb,
Packit b5b901
                                  IOCTL_AFD_RECEIVE,
Packit b5b901
                                  &info,
Packit b5b901
                                  sizeof(info),
Packit b5b901
                                  NULL,
Packit b5b901
                                  0);
Packit b5b901
Packit b5b901
  *flags = 0;
Packit b5b901
  *bytes = (DWORD) iosb->Information;
Packit b5b901
Packit b5b901
  switch (status) {
Packit b5b901
    case STATUS_SUCCESS:
Packit b5b901
      error = ERROR_SUCCESS;
Packit b5b901
      break;
Packit b5b901
Packit b5b901
    case STATUS_PENDING:
Packit b5b901
      error = WSA_IO_PENDING;
Packit b5b901
      break;
Packit b5b901
Packit b5b901
    case STATUS_BUFFER_OVERFLOW:
Packit b5b901
      error = WSAEMSGSIZE;
Packit b5b901
      break;
Packit b5b901
Packit b5b901
    case STATUS_RECEIVE_EXPEDITED:
Packit b5b901
      error = ERROR_SUCCESS;
Packit b5b901
      *flags = MSG_OOB;
Packit b5b901
      break;
Packit b5b901
Packit b5b901
    case STATUS_RECEIVE_PARTIAL_EXPEDITED:
Packit b5b901
      error = ERROR_SUCCESS;
Packit b5b901
      *flags = MSG_PARTIAL | MSG_OOB;
Packit b5b901
      break;
Packit b5b901
Packit b5b901
    case STATUS_RECEIVE_PARTIAL:
Packit b5b901
      error = ERROR_SUCCESS;
Packit b5b901
      *flags = MSG_PARTIAL;
Packit b5b901
      break;
Packit b5b901
Packit b5b901
    default:
Packit b5b901
      error = uv_ntstatus_to_winsock_error(status);
Packit b5b901
      break;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  WSASetLastError(error);
Packit b5b901
Packit b5b901
  if (error == ERROR_SUCCESS) {
Packit b5b901
    return 0;
Packit b5b901
  } else {
Packit b5b901
    return SOCKET_ERROR;
Packit b5b901
  }
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
/* See description of uv_wsarecv_workaround. */
Packit b5b901
int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
Packit b5b901
    DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr,
Packit b5b901
    int* addr_len, WSAOVERLAPPED *overlapped,
Packit b5b901
    LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) {
Packit b5b901
  NTSTATUS status;
Packit b5b901
  void* apc_context;
Packit b5b901
  IO_STATUS_BLOCK* iosb = (IO_STATUS_BLOCK*) &overlapped->Internal;
Packit b5b901
  AFD_RECV_DATAGRAM_INFO info;
Packit b5b901
  DWORD error;
Packit b5b901
Packit b5b901
  if (overlapped == NULL || addr == NULL || addr_len == NULL ||
Packit b5b901
      completion_routine != NULL) {
Packit b5b901
    WSASetLastError(WSAEINVAL);
Packit b5b901
    return SOCKET_ERROR;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  info.BufferArray = buffers;
Packit b5b901
  info.BufferCount = buffer_count;
Packit b5b901
  info.AfdFlags = AFD_OVERLAPPED;
Packit b5b901
  info.TdiFlags = TDI_RECEIVE_NORMAL;
Packit b5b901
  info.Address = addr;
Packit b5b901
  info.AddressLength = addr_len;
Packit b5b901
Packit b5b901
  if (*flags & MSG_PEEK) {
Packit b5b901
    info.TdiFlags |= TDI_RECEIVE_PEEK;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (*flags & MSG_PARTIAL) {
Packit b5b901
    info.TdiFlags |= TDI_RECEIVE_PARTIAL;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  if (!((intptr_t) overlapped->hEvent & 1)) {
Packit b5b901
    apc_context = (void*) overlapped;
Packit b5b901
  } else {
Packit b5b901
    apc_context = NULL;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  iosb->Status = STATUS_PENDING;
Packit b5b901
  iosb->Pointer = 0;
Packit b5b901
Packit b5b901
  status = pNtDeviceIoControlFile((HANDLE) socket,
Packit b5b901
                                  overlapped->hEvent,
Packit b5b901
                                  NULL,
Packit b5b901
                                  apc_context,
Packit b5b901
                                  iosb,
Packit b5b901
                                  IOCTL_AFD_RECEIVE_DATAGRAM,
Packit b5b901
                                  &info,
Packit b5b901
                                  sizeof(info),
Packit b5b901
                                  NULL,
Packit b5b901
                                  0);
Packit b5b901
Packit b5b901
  *flags = 0;
Packit b5b901
  *bytes = (DWORD) iosb->Information;
Packit b5b901
Packit b5b901
  switch (status) {
Packit b5b901
    case STATUS_SUCCESS:
Packit b5b901
      error = ERROR_SUCCESS;
Packit b5b901
      break;
Packit b5b901
Packit b5b901
    case STATUS_PENDING:
Packit b5b901
      error = WSA_IO_PENDING;
Packit b5b901
      break;
Packit b5b901
Packit b5b901
    case STATUS_BUFFER_OVERFLOW:
Packit b5b901
      error = WSAEMSGSIZE;
Packit b5b901
      break;
Packit b5b901
Packit b5b901
    case STATUS_RECEIVE_EXPEDITED:
Packit b5b901
      error = ERROR_SUCCESS;
Packit b5b901
      *flags = MSG_OOB;
Packit b5b901
      break;
Packit b5b901
Packit b5b901
    case STATUS_RECEIVE_PARTIAL_EXPEDITED:
Packit b5b901
      error = ERROR_SUCCESS;
Packit b5b901
      *flags = MSG_PARTIAL | MSG_OOB;
Packit b5b901
      break;
Packit b5b901
Packit b5b901
    case STATUS_RECEIVE_PARTIAL:
Packit b5b901
      error = ERROR_SUCCESS;
Packit b5b901
      *flags = MSG_PARTIAL;
Packit b5b901
      break;
Packit b5b901
Packit b5b901
    default:
Packit b5b901
      error = uv_ntstatus_to_winsock_error(status);
Packit b5b901
      break;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  WSASetLastError(error);
Packit b5b901
Packit b5b901
  if (error == ERROR_SUCCESS) {
Packit b5b901
    return 0;
Packit b5b901
  } else {
Packit b5b901
    return SOCKET_ERROR;
Packit b5b901
  }
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
Packit b5b901
    AFD_POLL_INFO* info_out, OVERLAPPED* overlapped) {
Packit b5b901
  IO_STATUS_BLOCK iosb;
Packit b5b901
  IO_STATUS_BLOCK* iosb_ptr;
Packit b5b901
  HANDLE event = NULL;
Packit b5b901
  void* apc_context;
Packit b5b901
  NTSTATUS status;
Packit b5b901
  DWORD error;
Packit b5b901
Packit b5b901
  if (overlapped != NULL) {
Packit b5b901
    /* Overlapped operation. */
Packit b5b901
    iosb_ptr = (IO_STATUS_BLOCK*) &overlapped->Internal;
Packit b5b901
    event = overlapped->hEvent;
Packit b5b901
Packit b5b901
    /* Do not report iocp completion if hEvent is tagged. */
Packit b5b901
    if ((uintptr_t) event & 1) {
Packit b5b901
      event = (HANDLE)((uintptr_t) event & ~(uintptr_t) 1);
Packit b5b901
      apc_context = NULL;
Packit b5b901
    } else {
Packit b5b901
      apc_context = overlapped;
Packit b5b901
    }
Packit b5b901
Packit b5b901
  } else {
Packit b5b901
    /* Blocking operation. */
Packit b5b901
    iosb_ptr = &ios;;
Packit b5b901
    event = CreateEvent(NULL, FALSE, FALSE, NULL);
Packit b5b901
    if (event == NULL) {
Packit b5b901
      return SOCKET_ERROR;
Packit b5b901
    }
Packit b5b901
    apc_context = NULL;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  iosb_ptr->Status = STATUS_PENDING;
Packit b5b901
  status = pNtDeviceIoControlFile((HANDLE) socket,
Packit b5b901
                                  event,
Packit b5b901
                                  NULL,
Packit b5b901
                                  apc_context,
Packit b5b901
                                  iosb_ptr,
Packit b5b901
                                  IOCTL_AFD_POLL,
Packit b5b901
                                  info_in,
Packit b5b901
                                  sizeof *info_in,
Packit b5b901
                                  info_out,
Packit b5b901
                                  sizeof *info_out);
Packit b5b901
Packit b5b901
  if (overlapped == NULL) {
Packit b5b901
    /* If this is a blocking operation, wait for the event to become signaled,
Packit b5b901
     * and then grab the real status from the io status block. */
Packit b5b901
    if (status == STATUS_PENDING) {
Packit b5b901
      DWORD r = WaitForSingleObject(event, INFINITE);
Packit b5b901
Packit b5b901
      if (r == WAIT_FAILED) {
Packit b5b901
        DWORD saved_error = GetLastError();
Packit b5b901
        CloseHandle(event);
Packit b5b901
        WSASetLastError(saved_error);
Packit b5b901
        return SOCKET_ERROR;
Packit b5b901
      }
Packit b5b901
Packit b5b901
      status = iosb.Status;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    CloseHandle(event);
Packit b5b901
  }
Packit b5b901
Packit b5b901
  switch (status) {
Packit b5b901
    case STATUS_SUCCESS:
Packit b5b901
      error = ERROR_SUCCESS;
Packit b5b901
      break;
Packit b5b901
Packit b5b901
    case STATUS_PENDING:
Packit b5b901
      error = WSA_IO_PENDING;
Packit b5b901
      break;
Packit b5b901
Packit b5b901
    default:
Packit b5b901
      error = uv_ntstatus_to_winsock_error(status);
Packit b5b901
      break;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  WSASetLastError(error);
Packit b5b901
Packit b5b901
  if (error == ERROR_SUCCESS) {
Packit b5b901
    return 0;
Packit b5b901
  } else {
Packit b5b901
    return SOCKET_ERROR;
Packit b5b901
  }
Packit b5b901
}
Packit b5b901
Packit b5b901
int uv__convert_to_localhost_if_unspecified(const struct sockaddr* addr,
Packit b5b901
                                            struct sockaddr_storage* storage) {
Packit b5b901
  struct sockaddr_in* dest4;
Packit b5b901
  struct sockaddr_in6* dest6;
Packit b5b901
Packit b5b901
  if (addr == NULL)
Packit b5b901
    return UV_EINVAL;
Packit b5b901
Packit b5b901
  switch (addr->sa_family) {
Packit b5b901
  case AF_INET:
Packit b5b901
    dest4 = (struct sockaddr_in*) storage;
Packit b5b901
    memcpy(dest4, addr, sizeof(*dest4));
Packit b5b901
    if (dest4->sin_addr.s_addr == 0)
Packit b5b901
      dest4->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
Packit b5b901
    return 0;
Packit b5b901
  case AF_INET6:
Packit b5b901
    dest6 = (struct sockaddr_in6*) storage;
Packit b5b901
    memcpy(dest6, addr, sizeof(*dest6));
Packit b5b901
    if (memcmp(&dest6->sin6_addr,
Packit b5b901
               &uv_addr_ip6_any_.sin6_addr,
Packit b5b901
               sizeof(uv_addr_ip6_any_.sin6_addr)) == 0) {
Packit b5b901
      struct in6_addr init_sin6_addr = IN6ADDR_LOOPBACK_INIT;
Packit b5b901
      dest6->sin6_addr = init_sin6_addr;
Packit b5b901
    }
Packit b5b901
    return 0;
Packit b5b901
  default:
Packit b5b901
    return UV_EINVAL;
Packit b5b901
  }
Packit b5b901
}