Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Kitware
GitHub Repository: Kitware/CMake
Path: blob/master/Utilities/cmlibuv/src/win/winsock.c
3153 views
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
}
576
577