libuv-svace-build

Форк
0
575 строк · 15.4 Кб
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

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.