|
160
|
1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
|
|
2 *
|
|
|
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:
|
|
|
9 *
|
|
|
10 * The above copyright notice and this permission notice shall be included in
|
|
|
11 * all copies or substantial portions of the Software.
|
|
|
12 *
|
|
|
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
|
|
|
19 * IN THE SOFTWARE.
|
|
|
20 */
|
|
|
21
|
|
|
22 #include <assert.h>
|
|
|
23 #include <stdlib.h>
|
|
|
24
|
|
|
25 #include "uv.h"
|
|
|
26 #include "internal.h"
|
|
|
27
|
|
|
28
|
|
|
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;
|
|
|
32
|
|
|
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_;
|
|
|
36
|
|
|
37
|
|
|
38 /*
|
|
|
39 * Retrieves the pointer to a winsock extension function.
|
|
|
40 */
|
|
|
41 static BOOL uv__get_extension_function(SOCKET socket, GUID guid,
|
|
|
42 void **target) {
|
|
|
43 int result;
|
|
|
44 DWORD bytes;
|
|
|
45
|
|
|
46 result = WSAIoctl(socket,
|
|
|
47 SIO_GET_EXTENSION_FUNCTION_POINTER,
|
|
|
48 &guid,
|
|
|
49 sizeof(guid),
|
|
|
50 (void*)target,
|
|
|
51 sizeof(*target),
|
|
|
52 &bytes,
|
|
|
53 NULL,
|
|
|
54 NULL);
|
|
|
55
|
|
|
56 if (result == SOCKET_ERROR) {
|
|
|
57 *target = NULL;
|
|
|
58 return FALSE;
|
|
|
59 } else {
|
|
|
60 return TRUE;
|
|
|
61 }
|
|
|
62 }
|
|
|
63
|
|
|
64
|
|
|
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);
|
|
|
68 }
|
|
|
69
|
|
|
70
|
|
|
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);
|
|
|
74 }
|
|
|
75
|
|
|
76
|
|
|
77
|
|
|
78 void uv__winsock_init(void) {
|
|
|
79 WSADATA wsa_data;
|
|
|
80 int errorno;
|
|
|
81 SOCKET dummy;
|
|
|
82 WSAPROTOCOL_INFOW protocol_info;
|
|
|
83 int opt_len;
|
|
|
84
|
|
|
85 /* Set implicit binding address used by connectEx */
|
|
|
86 if (uv_ip4_addr("0.0.0.0", 0, &uv_addr_ip4_any_)) {
|
|
|
87 abort();
|
|
|
88 }
|
|
|
89
|
|
|
90 if (uv_ip6_addr("::", 0, &uv_addr_ip6_any_)) {
|
|
|
91 abort();
|
|
|
92 }
|
|
|
93
|
|
|
94 /* Skip initialization in safe mode without network support */
|
|
|
95 if (1 == GetSystemMetrics(SM_CLEANBOOT)) return;
|
|
|
96
|
|
|
97 /* Initialize winsock */
|
|
|
98 errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data);
|
|
|
99 if (errorno != 0) {
|
|
|
100 uv_fatal_error(errorno, "WSAStartup");
|
|
|
101 }
|
|
|
102
|
|
|
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,
|
|
|
109 SOL_SOCKET,
|
|
|
110 SO_PROTOCOL_INFOW,
|
|
|
111 (char*) &protocol_info,
|
|
|
112 &opt_len) == 0) {
|
|
|
113 if (protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES)
|
|
|
114 uv_tcp_non_ifs_lsp_ipv4 = 0;
|
|
|
115 }
|
|
|
116 closesocket(dummy);
|
|
|
117 }
|
|
|
118
|
|
|
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,
|
|
|
125 SOL_SOCKET,
|
|
|
126 SO_PROTOCOL_INFOW,
|
|
|
127 (char*) &protocol_info,
|
|
|
128 &opt_len) == 0) {
|
|
|
129 if (protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES)
|
|
|
130 uv_tcp_non_ifs_lsp_ipv6 = 0;
|
|
|
131 }
|
|
|
132 closesocket(dummy);
|
|
|
133 }
|
|
|
134 }
|
|
|
135
|
|
|
136
|
|
|
137 int uv__ntstatus_to_winsock_error(NTSTATUS status) {
|
|
|
138 switch (status) {
|
|
|
139 case STATUS_SUCCESS:
|
|
|
140 return ERROR_SUCCESS;
|
|
|
141
|
|
|
142 case STATUS_PENDING:
|
|
|
143 return ERROR_IO_PENDING;
|
|
|
144
|
|
|
145 case STATUS_INVALID_HANDLE:
|
|
|
146 case STATUS_OBJECT_TYPE_MISMATCH:
|
|
|
147 return WSAENOTSOCK;
|
|
|
148
|
|
|
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:
|
|
|
157 return WSAENOBUFS;
|
|
|
158
|
|
|
159 case STATUS_TOO_MANY_ADDRESSES:
|
|
|
160 case STATUS_SHARING_VIOLATION:
|
|
|
161 case STATUS_ADDRESS_ALREADY_EXISTS:
|
|
|
162 return WSAEADDRINUSE;
|
|
|
163
|
|
|
164 case STATUS_LINK_TIMEOUT:
|
|
|
165 case STATUS_IO_TIMEOUT:
|
|
|
166 case STATUS_TIMEOUT:
|
|
|
167 return WSAETIMEDOUT;
|
|
|
168
|
|
|
169 case STATUS_GRACEFUL_DISCONNECT:
|
|
|
170 return WSAEDISCON;
|
|
|
171
|
|
|
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;
|
|
|
179
|
|
|
180 case STATUS_LOCAL_DISCONNECT:
|
|
|
181 case STATUS_TRANSACTION_ABORTED:
|
|
|
182 case STATUS_CONNECTION_ABORTED:
|
|
|
183 return WSAECONNABORTED;
|
|
|
184
|
|
|
185 case STATUS_BAD_NETWORK_PATH:
|
|
|
186 case STATUS_NETWORK_UNREACHABLE:
|
|
|
187 case STATUS_PROTOCOL_UNREACHABLE:
|
|
|
188 return WSAENETUNREACH;
|
|
|
189
|
|
|
190 case STATUS_HOST_UNREACHABLE:
|
|
|
191 return WSAEHOSTUNREACH;
|
|
|
192
|
|
|
193 case STATUS_CANCELLED:
|
|
|
194 case STATUS_REQUEST_ABORTED:
|
|
|
195 return WSAEINTR;
|
|
|
196
|
|
|
197 case STATUS_BUFFER_OVERFLOW:
|
|
|
198 case STATUS_INVALID_BUFFER_SIZE:
|
|
|
199 return WSAEMSGSIZE;
|
|
|
200
|
|
|
201 case STATUS_BUFFER_TOO_SMALL:
|
|
|
202 case STATUS_ACCESS_VIOLATION:
|
|
|
203 return WSAEFAULT;
|
|
|
204
|
|
|
205 case STATUS_DEVICE_NOT_READY:
|
|
|
206 case STATUS_REQUEST_NOT_ACCEPTED:
|
|
|
207 return WSAEWOULDBLOCK;
|
|
|
208
|
|
|
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:
|
|
|
216 return WSAENETDOWN;
|
|
|
217
|
|
|
218 case STATUS_INVALID_CONNECTION:
|
|
|
219 return WSAENOTCONN;
|
|
|
220
|
|
|
221 case STATUS_REMOTE_NOT_LISTENING:
|
|
|
222 case STATUS_CONNECTION_REFUSED:
|
|
|
223 return WSAECONNREFUSED;
|
|
|
224
|
|
|
225 case STATUS_PIPE_DISCONNECTED:
|
|
|
226 return WSAESHUTDOWN;
|
|
|
227
|
|
|
228 case STATUS_CONFLICTING_ADDRESSES:
|
|
|
229 case STATUS_INVALID_ADDRESS:
|
|
|
230 case STATUS_INVALID_ADDRESS_COMPONENT:
|
|
|
231 return WSAEADDRNOTAVAIL;
|
|
|
232
|
|
|
233 case STATUS_NOT_SUPPORTED:
|
|
|
234 case STATUS_NOT_IMPLEMENTED:
|
|
|
235 return WSAEOPNOTSUPP;
|
|
|
236
|
|
|
237 case STATUS_ACCESS_DENIED:
|
|
|
238 return WSAEACCES;
|
|
|
239
|
|
|
240 default:
|
|
|
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
|
|
|
244 * code. */
|
|
|
245 return (DWORD) (status & 0xffff);
|
|
|
246 } else {
|
|
|
247 /* The default fallback for unmappable ntstatus codes. */
|
|
|
248 return WSAEINVAL;
|
|
|
249 }
|
|
|
250 }
|
|
|
251 }
|
|
|
252
|
|
|
253
|
|
|
254 /*
|
|
|
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.
|
|
|
260 *
|
|
|
261 * However it is desirable to use SetFileCompletionNotificationModes because
|
|
|
262 * it yields a massive performance increase.
|
|
|
263 *
|
|
|
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.
|
|
|
269 */
|
|
|
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) {
|
|
|
273 NTSTATUS status;
|
|
|
274 void* apc_context;
|
|
|
275 IO_STATUS_BLOCK* iosb = (IO_STATUS_BLOCK*) &overlapped->Internal;
|
|
|
276 AFD_RECV_INFO info;
|
|
|
277 DWORD error;
|
|
|
278
|
|
|
279 if (overlapped == NULL || completion_routine != NULL) {
|
|
|
280 WSASetLastError(WSAEINVAL);
|
|
|
281 return SOCKET_ERROR;
|
|
|
282 }
|
|
|
283
|
|
|
284 info.BufferArray = buffers;
|
|
|
285 info.BufferCount = buffer_count;
|
|
|
286 info.AfdFlags = AFD_OVERLAPPED;
|
|
|
287 info.TdiFlags = TDI_RECEIVE_NORMAL;
|
|
|
288
|
|
|
289 if (*flags & MSG_PEEK) {
|
|
|
290 info.TdiFlags |= TDI_RECEIVE_PEEK;
|
|
|
291 }
|
|
|
292
|
|
|
293 if (*flags & MSG_PARTIAL) {
|
|
|
294 info.TdiFlags |= TDI_RECEIVE_PARTIAL;
|
|
|
295 }
|
|
|
296
|
|
|
297 if (!((intptr_t) overlapped->hEvent & 1)) {
|
|
|
298 apc_context = (void*) overlapped;
|
|
|
299 } else {
|
|
|
300 apc_context = NULL;
|
|
|
301 }
|
|
|
302
|
|
|
303 iosb->Status = STATUS_PENDING;
|
|
|
304 iosb->Pointer = 0;
|
|
|
305
|
|
|
306 status = pNtDeviceIoControlFile((HANDLE) socket,
|
|
|
307 overlapped->hEvent,
|
|
|
308 NULL,
|
|
|
309 apc_context,
|
|
|
310 iosb,
|
|
|
311 IOCTL_AFD_RECEIVE,
|
|
|
312 &info,
|
|
|
313 sizeof(info),
|
|
|
314 NULL,
|
|
|
315 0);
|
|
|
316
|
|
|
317 *flags = 0;
|
|
|
318 *bytes = (DWORD) iosb->Information;
|
|
|
319
|
|
|
320 switch (status) {
|
|
|
321 case STATUS_SUCCESS:
|
|
|
322 error = ERROR_SUCCESS;
|
|
|
323 break;
|
|
|
324
|
|
|
325 case STATUS_PENDING:
|
|
|
326 error = WSA_IO_PENDING;
|
|
|
327 break;
|
|
|
328
|
|
|
329 case STATUS_BUFFER_OVERFLOW:
|
|
|
330 error = WSAEMSGSIZE;
|
|
|
331 break;
|
|
|
332
|
|
|
333 case STATUS_RECEIVE_EXPEDITED:
|
|
|
334 error = ERROR_SUCCESS;
|
|
|
335 *flags = MSG_OOB;
|
|
|
336 break;
|
|
|
337
|
|
|
338 case STATUS_RECEIVE_PARTIAL_EXPEDITED:
|
|
|
339 error = ERROR_SUCCESS;
|
|
|
340 *flags = MSG_PARTIAL | MSG_OOB;
|
|
|
341 break;
|
|
|
342
|
|
|
343 case STATUS_RECEIVE_PARTIAL:
|
|
|
344 error = ERROR_SUCCESS;
|
|
|
345 *flags = MSG_PARTIAL;
|
|
|
346 break;
|
|
|
347
|
|
|
348 default:
|
|
|
349 error = uv__ntstatus_to_winsock_error(status);
|
|
|
350 break;
|
|
|
351 }
|
|
|
352
|
|
|
353 WSASetLastError(error);
|
|
|
354
|
|
|
355 if (error == ERROR_SUCCESS) {
|
|
|
356 return 0;
|
|
|
357 } else {
|
|
|
358 return SOCKET_ERROR;
|
|
|
359 }
|
|
|
360 }
|
|
|
361
|
|
|
362
|
|
|
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) {
|
|
|
368 NTSTATUS status;
|
|
|
369 void* apc_context;
|
|
|
370 IO_STATUS_BLOCK* iosb = (IO_STATUS_BLOCK*) &overlapped->Internal;
|
|
|
371 AFD_RECV_DATAGRAM_INFO info;
|
|
|
372 DWORD error;
|
|
|
373
|
|
|
374 if (overlapped == NULL || addr == NULL || addr_len == NULL ||
|
|
|
375 completion_routine != NULL) {
|
|
|
376 WSASetLastError(WSAEINVAL);
|
|
|
377 return SOCKET_ERROR;
|
|
|
378 }
|
|
|
379
|
|
|
380 info.BufferArray = buffers;
|
|
|
381 info.BufferCount = buffer_count;
|
|
|
382 info.AfdFlags = AFD_OVERLAPPED;
|
|
|
383 info.TdiFlags = TDI_RECEIVE_NORMAL;
|
|
|
384 info.Address = addr;
|
|
|
385 info.AddressLength = addr_len;
|
|
|
386
|
|
|
387 if (*flags & MSG_PEEK) {
|
|
|
388 info.TdiFlags |= TDI_RECEIVE_PEEK;
|
|
|
389 }
|
|
|
390
|
|
|
391 if (*flags & MSG_PARTIAL) {
|
|
|
392 info.TdiFlags |= TDI_RECEIVE_PARTIAL;
|
|
|
393 }
|
|
|
394
|
|
|
395 if (!((intptr_t) overlapped->hEvent & 1)) {
|
|
|
396 apc_context = (void*) overlapped;
|
|
|
397 } else {
|
|
|
398 apc_context = NULL;
|
|
|
399 }
|
|
|
400
|
|
|
401 iosb->Status = STATUS_PENDING;
|
|
|
402 iosb->Pointer = 0;
|
|
|
403
|
|
|
404 status = pNtDeviceIoControlFile((HANDLE) socket,
|
|
|
405 overlapped->hEvent,
|
|
|
406 NULL,
|
|
|
407 apc_context,
|
|
|
408 iosb,
|
|
|
409 IOCTL_AFD_RECEIVE_DATAGRAM,
|
|
|
410 &info,
|
|
|
411 sizeof(info),
|
|
|
412 NULL,
|
|
|
413 0);
|
|
|
414
|
|
|
415 *flags = 0;
|
|
|
416 *bytes = (DWORD) iosb->Information;
|
|
|
417
|
|
|
418 switch (status) {
|
|
|
419 case STATUS_SUCCESS:
|
|
|
420 error = ERROR_SUCCESS;
|
|
|
421 break;
|
|
|
422
|
|
|
423 case STATUS_PENDING:
|
|
|
424 error = WSA_IO_PENDING;
|
|
|
425 break;
|
|
|
426
|
|
|
427 case STATUS_BUFFER_OVERFLOW:
|
|
|
428 error = WSAEMSGSIZE;
|
|
|
429 break;
|
|
|
430
|
|
|
431 case STATUS_RECEIVE_EXPEDITED:
|
|
|
432 error = ERROR_SUCCESS;
|
|
|
433 *flags = MSG_OOB;
|
|
|
434 break;
|
|
|
435
|
|
|
436 case STATUS_RECEIVE_PARTIAL_EXPEDITED:
|
|
|
437 error = ERROR_SUCCESS;
|
|
|
438 *flags = MSG_PARTIAL | MSG_OOB;
|
|
|
439 break;
|
|
|
440
|
|
|
441 case STATUS_RECEIVE_PARTIAL:
|
|
|
442 error = ERROR_SUCCESS;
|
|
|
443 *flags = MSG_PARTIAL;
|
|
|
444 break;
|
|
|
445
|
|
|
446 default:
|
|
|
447 error = uv__ntstatus_to_winsock_error(status);
|
|
|
448 break;
|
|
|
449 }
|
|
|
450
|
|
|
451 WSASetLastError(error);
|
|
|
452
|
|
|
453 if (error == ERROR_SUCCESS) {
|
|
|
454 return 0;
|
|
|
455 } else {
|
|
|
456 return SOCKET_ERROR;
|
|
|
457 }
|
|
|
458 }
|
|
|
459
|
|
|
460
|
|
|
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;
|
|
|
465 HANDLE event = NULL;
|
|
|
466 void* apc_context;
|
|
|
467 NTSTATUS status;
|
|
|
468 DWORD error;
|
|
|
469
|
|
|
470 if (overlapped != NULL) {
|
|
|
471 /* Overlapped operation. */
|
|
|
472 iosb_ptr = (IO_STATUS_BLOCK*) &overlapped->Internal;
|
|
|
473 event = overlapped->hEvent;
|
|
|
474
|
|
|
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);
|
|
|
478 apc_context = NULL;
|
|
|
479 } else {
|
|
|
480 apc_context = overlapped;
|
|
|
481 }
|
|
|
482
|
|
|
483 } else {
|
|
|
484 /* Blocking operation. */
|
|
|
485 iosb_ptr = &iosb;
|
|
|
486 event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
|
487 if (event == NULL) {
|
|
|
488 return SOCKET_ERROR;
|
|
|
489 }
|
|
|
490 apc_context = NULL;
|
|
|
491 }
|
|
|
492
|
|
|
493 iosb_ptr->Status = STATUS_PENDING;
|
|
|
494 status = pNtDeviceIoControlFile((HANDLE) socket,
|
|
|
495 event,
|
|
|
496 NULL,
|
|
|
497 apc_context,
|
|
|
498 iosb_ptr,
|
|
|
499 IOCTL_AFD_POLL,
|
|
|
500 info_in,
|
|
|
501 sizeof *info_in,
|
|
|
502 info_out,
|
|
|
503 sizeof *info_out);
|
|
|
504
|
|
|
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);
|
|
|
510
|
|
|
511 if (r == WAIT_FAILED) {
|
|
|
512 DWORD saved_error = GetLastError();
|
|
|
513 CloseHandle(event);
|
|
|
514 WSASetLastError(saved_error);
|
|
|
515 return SOCKET_ERROR;
|
|
|
516 }
|
|
|
517
|
|
|
518 status = iosb.Status;
|
|
|
519 }
|
|
|
520
|
|
|
521 CloseHandle(event);
|
|
|
522 }
|
|
|
523
|
|
|
524 switch (status) {
|
|
|
525 case STATUS_SUCCESS:
|
|
|
526 error = ERROR_SUCCESS;
|
|
|
527 break;
|
|
|
528
|
|
|
529 case STATUS_PENDING:
|
|
|
530 error = WSA_IO_PENDING;
|
|
|
531 break;
|
|
|
532
|
|
|
533 default:
|
|
|
534 error = uv__ntstatus_to_winsock_error(status);
|
|
|
535 break;
|
|
|
536 }
|
|
|
537
|
|
|
538 WSASetLastError(error);
|
|
|
539
|
|
|
540 if (error == ERROR_SUCCESS) {
|
|
|
541 return 0;
|
|
|
542 } else {
|
|
|
543 return SOCKET_ERROR;
|
|
|
544 }
|
|
|
545 }
|
|
|
546
|
|
|
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;
|
|
|
551
|
|
|
552 if (addr == NULL)
|
|
|
553 return UV_EINVAL;
|
|
|
554
|
|
|
555 switch (addr->sa_family) {
|
|
|
556 case AF_INET:
|
|
|
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);
|
|
|
561 return 0;
|
|
|
562 case AF_INET6:
|
|
|
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;
|
|
|
570 }
|
|
|
571 return 0;
|
|
|
572 default:
|
|
|
573 return UV_EINVAL;
|
|
|
574 }
|
|
|
575 }
|