1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to
5 * deal in the Software without restriction, including without limitation the
6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 * sell copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
29 /* Whether there are any non-IFS LSPs stacked on TCP */
30 int uv_tcp_non_ifs_lsp_ipv4;
31 int uv_tcp_non_ifs_lsp_ipv6;
33 /* Ip address used to bind to any port at any interface */
34 struct sockaddr_in uv_addr_ip4_any_;
35 struct sockaddr_in6 uv_addr_ip6_any_;
39 * Retrieves the pointer to a winsock extension function.
41 static BOOL uv__get_extension_function(SOCKET socket, GUID guid,
46 result = WSAIoctl(socket,
47 SIO_GET_EXTENSION_FUNCTION_POINTER,
56 if (result == SOCKET_ERROR) {
65 BOOL uv__get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target) {
66 const GUID wsaid_acceptex = WSAID_ACCEPTEX;
67 return uv__get_extension_function(socket, wsaid_acceptex, (void**)target);
71 BOOL uv__get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target) {
72 const GUID wsaid_connectex = WSAID_CONNECTEX;
73 return uv__get_extension_function(socket, wsaid_connectex, (void**)target);
78 void uv__winsock_init(void) {
82 WSAPROTOCOL_INFOW protocol_info;
85 /* Set implicit binding address used by connectEx */
86 if (uv_ip4_addr("0.0.0.0", 0, &uv_addr_ip4_any_)) {
90 if (uv_ip6_addr("::", 0, &uv_addr_ip6_any_)) {
94 /* Skip initialization in safe mode without network support */
95 if (1 == GetSystemMetrics(SM_CLEANBOOT)) return;
97 /* Initialize winsock */
98 errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data);
100 uv_fatal_error(errorno, "WSAStartup");
103 /* Try to detect non-IFS LSPs */
104 uv_tcp_non_ifs_lsp_ipv4 = 1;
105 dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
106 if (dummy != INVALID_SOCKET) {
107 opt_len = (int) sizeof protocol_info;
108 if (getsockopt(dummy,
111 (char*) &protocol_info,
113 if (protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES)
114 uv_tcp_non_ifs_lsp_ipv4 = 0;
119 /* Try to detect IPV6 support and non-IFS LSPs */
120 uv_tcp_non_ifs_lsp_ipv6 = 1;
121 dummy = socket(AF_INET6, SOCK_STREAM, IPPROTO_IP);
122 if (dummy != INVALID_SOCKET) {
123 opt_len = (int) sizeof protocol_info;
124 if (getsockopt(dummy,
127 (char*) &protocol_info,
129 if (protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES)
130 uv_tcp_non_ifs_lsp_ipv6 = 0;
137 int uv__ntstatus_to_winsock_error(NTSTATUS status) {
140 return ERROR_SUCCESS;
143 return ERROR_IO_PENDING;
145 case STATUS_INVALID_HANDLE:
146 case STATUS_OBJECT_TYPE_MISMATCH:
149 case STATUS_INSUFFICIENT_RESOURCES:
150 case STATUS_PAGEFILE_QUOTA:
151 case STATUS_COMMITMENT_LIMIT:
152 case STATUS_WORKING_SET_QUOTA:
153 case STATUS_NO_MEMORY:
154 case STATUS_QUOTA_EXCEEDED:
155 case STATUS_TOO_MANY_PAGING_FILES:
156 case STATUS_REMOTE_RESOURCES:
159 case STATUS_TOO_MANY_ADDRESSES:
160 case STATUS_SHARING_VIOLATION:
161 case STATUS_ADDRESS_ALREADY_EXISTS:
162 return WSAEADDRINUSE;
164 case STATUS_LINK_TIMEOUT:
165 case STATUS_IO_TIMEOUT:
169 case STATUS_GRACEFUL_DISCONNECT:
172 case STATUS_REMOTE_DISCONNECT:
173 case STATUS_CONNECTION_RESET:
174 case STATUS_LINK_FAILED:
175 case STATUS_CONNECTION_DISCONNECTED:
176 case STATUS_PORT_UNREACHABLE:
177 case STATUS_HOPLIMIT_EXCEEDED:
178 return WSAECONNRESET;
180 case STATUS_LOCAL_DISCONNECT:
181 case STATUS_TRANSACTION_ABORTED:
182 case STATUS_CONNECTION_ABORTED:
183 return WSAECONNABORTED;
185 case STATUS_BAD_NETWORK_PATH:
186 case STATUS_NETWORK_UNREACHABLE:
187 case STATUS_PROTOCOL_UNREACHABLE:
188 return WSAENETUNREACH;
190 case STATUS_HOST_UNREACHABLE:
191 return WSAEHOSTUNREACH;
193 case STATUS_CANCELLED:
194 case STATUS_REQUEST_ABORTED:
197 case STATUS_BUFFER_OVERFLOW:
198 case STATUS_INVALID_BUFFER_SIZE:
201 case STATUS_BUFFER_TOO_SMALL:
202 case STATUS_ACCESS_VIOLATION:
205 case STATUS_DEVICE_NOT_READY:
206 case STATUS_REQUEST_NOT_ACCEPTED:
207 return WSAEWOULDBLOCK;
209 case STATUS_INVALID_NETWORK_RESPONSE:
210 case STATUS_NETWORK_BUSY:
211 case STATUS_NO_SUCH_DEVICE:
212 case STATUS_NO_SUCH_FILE:
213 case STATUS_OBJECT_PATH_NOT_FOUND:
214 case STATUS_OBJECT_NAME_NOT_FOUND:
215 case STATUS_UNEXPECTED_NETWORK_ERROR:
218 case STATUS_INVALID_CONNECTION:
221 case STATUS_REMOTE_NOT_LISTENING:
222 case STATUS_CONNECTION_REFUSED:
223 return WSAECONNREFUSED;
225 case STATUS_PIPE_DISCONNECTED:
228 case STATUS_CONFLICTING_ADDRESSES:
229 case STATUS_INVALID_ADDRESS:
230 case STATUS_INVALID_ADDRESS_COMPONENT:
231 return WSAEADDRNOTAVAIL;
233 case STATUS_NOT_SUPPORTED:
234 case STATUS_NOT_IMPLEMENTED:
235 return WSAEOPNOTSUPP;
237 case STATUS_ACCESS_DENIED:
241 if ((status & (FACILITY_NTWIN32 << 16)) == (FACILITY_NTWIN32 << 16) &&
242 (status & (ERROR_SEVERITY_ERROR | ERROR_SEVERITY_WARNING))) {
243 /* It's a windows error that has been previously mapped to an ntstatus
245 return (DWORD) (status & 0xffff);
247 /* The default fallback for unmappable ntstatus codes. */
255 * This function provides a workaround for a bug in the winsock implementation
256 * of WSARecv. The problem is that when SetFileCompletionNotificationModes is
257 * used to avoid IOCP notifications of completed reads, WSARecv does not
258 * reliably indicate whether we can expect a completion package to be posted
259 * when the receive buffer is smaller than the received datagram.
261 * However it is desirable to use SetFileCompletionNotificationModes because
262 * it yields a massive performance increase.
264 * This function provides a workaround for that bug, but it only works for the
265 * specific case that we need it for. E.g. it assumes that the "avoid iocp"
266 * bit has been set, and supports only overlapped operation. It also requires
267 * the user to use the default msafd driver, doesn't work when other LSPs are
268 * stacked on top of it.
270 int WSAAPI uv__wsarecv_workaround(SOCKET socket, WSABUF* buffers,
271 DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped,
272 LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) {
275 IO_STATUS_BLOCK* iosb = (IO_STATUS_BLOCK*) &overlapped->Internal;
279 if (overlapped == NULL || completion_routine != NULL) {
280 WSASetLastError(WSAEINVAL);
284 info.BufferArray = buffers;
285 info.BufferCount = buffer_count;
286 info.AfdFlags = AFD_OVERLAPPED;
287 info.TdiFlags = TDI_RECEIVE_NORMAL;
289 if (*flags & MSG_PEEK) {
290 info.TdiFlags |= TDI_RECEIVE_PEEK;
293 if (*flags & MSG_PARTIAL) {
294 info.TdiFlags |= TDI_RECEIVE_PARTIAL;
297 if (!((intptr_t) overlapped->hEvent & 1)) {
298 apc_context = (void*) overlapped;
303 iosb->Status = STATUS_PENDING;
306 status = pNtDeviceIoControlFile((HANDLE) socket,
318 *bytes = (DWORD) iosb->Information;
322 error = ERROR_SUCCESS;
326 error = WSA_IO_PENDING;
329 case STATUS_BUFFER_OVERFLOW:
333 case STATUS_RECEIVE_EXPEDITED:
334 error = ERROR_SUCCESS;
338 case STATUS_RECEIVE_PARTIAL_EXPEDITED:
339 error = ERROR_SUCCESS;
340 *flags = MSG_PARTIAL | MSG_OOB;
343 case STATUS_RECEIVE_PARTIAL:
344 error = ERROR_SUCCESS;
345 *flags = MSG_PARTIAL;
349 error = uv__ntstatus_to_winsock_error(status);
353 WSASetLastError(error);
355 if (error == ERROR_SUCCESS) {
363 /* See description of uv__wsarecv_workaround. */
364 int WSAAPI uv__wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
365 DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr,
366 int* addr_len, WSAOVERLAPPED *overlapped,
367 LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) {
370 IO_STATUS_BLOCK* iosb = (IO_STATUS_BLOCK*) &overlapped->Internal;
371 AFD_RECV_DATAGRAM_INFO info;
374 if (overlapped == NULL || addr == NULL || addr_len == NULL ||
375 completion_routine != NULL) {
376 WSASetLastError(WSAEINVAL);
380 info.BufferArray = buffers;
381 info.BufferCount = buffer_count;
382 info.AfdFlags = AFD_OVERLAPPED;
383 info.TdiFlags = TDI_RECEIVE_NORMAL;
385 info.AddressLength = addr_len;
387 if (*flags & MSG_PEEK) {
388 info.TdiFlags |= TDI_RECEIVE_PEEK;
391 if (*flags & MSG_PARTIAL) {
392 info.TdiFlags |= TDI_RECEIVE_PARTIAL;
395 if (!((intptr_t) overlapped->hEvent & 1)) {
396 apc_context = (void*) overlapped;
401 iosb->Status = STATUS_PENDING;
404 status = pNtDeviceIoControlFile((HANDLE) socket,
409 IOCTL_AFD_RECEIVE_DATAGRAM,
416 *bytes = (DWORD) iosb->Information;
420 error = ERROR_SUCCESS;
424 error = WSA_IO_PENDING;
427 case STATUS_BUFFER_OVERFLOW:
431 case STATUS_RECEIVE_EXPEDITED:
432 error = ERROR_SUCCESS;
436 case STATUS_RECEIVE_PARTIAL_EXPEDITED:
437 error = ERROR_SUCCESS;
438 *flags = MSG_PARTIAL | MSG_OOB;
441 case STATUS_RECEIVE_PARTIAL:
442 error = ERROR_SUCCESS;
443 *flags = MSG_PARTIAL;
447 error = uv__ntstatus_to_winsock_error(status);
451 WSASetLastError(error);
453 if (error == ERROR_SUCCESS) {
461 int WSAAPI uv__msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
462 AFD_POLL_INFO* info_out, OVERLAPPED* overlapped) {
463 IO_STATUS_BLOCK iosb;
464 IO_STATUS_BLOCK* iosb_ptr;
470 if (overlapped != NULL) {
471 /* Overlapped operation. */
472 iosb_ptr = (IO_STATUS_BLOCK*) &overlapped->Internal;
473 event = overlapped->hEvent;
475 /* Do not report iocp completion if hEvent is tagged. */
476 if ((uintptr_t) event & 1) {
477 event = (HANDLE)((uintptr_t) event & ~(uintptr_t) 1);
480 apc_context = overlapped;
484 /* Blocking operation. */
486 event = CreateEvent(NULL, FALSE, FALSE, NULL);
493 iosb_ptr->Status = STATUS_PENDING;
494 status = pNtDeviceIoControlFile((HANDLE) socket,
505 if (overlapped == NULL) {
506 /* If this is a blocking operation, wait for the event to become signaled,
507 * and then grab the real status from the io status block. */
508 if (status == STATUS_PENDING) {
509 DWORD r = WaitForSingleObject(event, INFINITE);
511 if (r == WAIT_FAILED) {
512 DWORD saved_error = GetLastError();
514 WSASetLastError(saved_error);
518 status = iosb.Status;
526 error = ERROR_SUCCESS;
530 error = WSA_IO_PENDING;
534 error = uv__ntstatus_to_winsock_error(status);
538 WSASetLastError(error);
540 if (error == ERROR_SUCCESS) {
547 int uv__convert_to_localhost_if_unspecified(const struct sockaddr* addr,
548 struct sockaddr_storage* storage) {
549 struct sockaddr_in* dest4;
550 struct sockaddr_in6* dest6;
555 switch (addr->sa_family) {
557 dest4 = (struct sockaddr_in*) storage;
558 memcpy(dest4, addr, sizeof(*dest4));
559 if (dest4->sin_addr.s_addr == 0)
560 dest4->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
563 dest6 = (struct sockaddr_in6*) storage;
564 memcpy(dest6, addr, sizeof(*dest6));
565 if (memcmp(&dest6->sin6_addr,
566 &uv_addr_ip6_any_.sin6_addr,
567 sizeof(uv_addr_ip6_any_.sin6_addr)) == 0) {
568 struct in6_addr init_sin6_addr = IN6ADDR_LOOPBACK_INIT;
569 dest6->sin6_addr = init_sin6_addr;