|
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 |
}
|