Mercurial
comparison third_party/libuv/src/win/winsock.c @ 160:948de3f54cea
[ThirdParty] Added libuv
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Wed, 14 Jan 2026 19:39:52 -0800 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 159:05cf9467a1c3 | 160:948de3f54cea |
|---|---|
| 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 } |