Mercurial
comparison third_party/libuv/src/win/tcp.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 #include "handle-inl.h" | |
| 28 #include "stream-inl.h" | |
| 29 #include "req-inl.h" | |
| 30 | |
| 31 | |
| 32 /* | |
| 33 * Number of simultaneous pending AcceptEx calls. | |
| 34 */ | |
| 35 const unsigned int uv_simultaneous_server_accepts = 32; | |
| 36 | |
| 37 /* A zero-size buffer for use by uv_tcp_read */ | |
| 38 static char uv_zero_[] = ""; | |
| 39 | |
| 40 static int uv__tcp_nodelay(uv_tcp_t* handle, SOCKET socket, int enable) { | |
| 41 if (setsockopt(socket, | |
| 42 IPPROTO_TCP, | |
| 43 TCP_NODELAY, | |
| 44 (const char*)&enable, | |
| 45 sizeof enable) == -1) { | |
| 46 return WSAGetLastError(); | |
| 47 } | |
| 48 return 0; | |
| 49 } | |
| 50 | |
| 51 | |
| 52 static int uv__tcp_keepalive(uv_tcp_t* handle, SOCKET socket, int enable, unsigned int delay) { | |
| 53 if (setsockopt(socket, | |
| 54 SOL_SOCKET, | |
| 55 SO_KEEPALIVE, | |
| 56 (const char*)&enable, | |
| 57 sizeof enable) == -1) { | |
| 58 return WSAGetLastError(); | |
| 59 } | |
| 60 | |
| 61 if (!enable) | |
| 62 return 0; | |
| 63 | |
| 64 if (delay < 1) | |
| 65 return UV_EINVAL; | |
| 66 | |
| 67 if (setsockopt(socket, | |
| 68 IPPROTO_TCP, | |
| 69 TCP_KEEPALIVE, | |
| 70 (const char*)&delay, | |
| 71 sizeof delay) == -1) { | |
| 72 return WSAGetLastError(); | |
| 73 } | |
| 74 | |
| 75 return 0; | |
| 76 } | |
| 77 | |
| 78 | |
| 79 static int uv__tcp_set_socket(uv_loop_t* loop, | |
| 80 uv_tcp_t* handle, | |
| 81 SOCKET socket, | |
| 82 int family, | |
| 83 int imported) { | |
| 84 DWORD yes = 1; | |
| 85 int non_ifs_lsp; | |
| 86 int err; | |
| 87 | |
| 88 if (handle->socket != INVALID_SOCKET) | |
| 89 return UV_EBUSY; | |
| 90 | |
| 91 /* Set the socket to nonblocking mode */ | |
| 92 if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) { | |
| 93 return WSAGetLastError(); | |
| 94 } | |
| 95 | |
| 96 /* Make the socket non-inheritable */ | |
| 97 if (!SetHandleInformation((HANDLE) socket, HANDLE_FLAG_INHERIT, 0)) | |
| 98 return GetLastError(); | |
| 99 | |
| 100 /* Associate it with the I/O completion port. Use uv_handle_t pointer as | |
| 101 * completion key. */ | |
| 102 if (CreateIoCompletionPort((HANDLE)socket, | |
| 103 loop->iocp, | |
| 104 (ULONG_PTR)socket, | |
| 105 0) == NULL) { | |
| 106 if (imported) { | |
| 107 handle->flags |= UV_HANDLE_EMULATE_IOCP; | |
| 108 } else { | |
| 109 return GetLastError(); | |
| 110 } | |
| 111 } | |
| 112 | |
| 113 if (family == AF_INET6) { | |
| 114 non_ifs_lsp = uv_tcp_non_ifs_lsp_ipv6; | |
| 115 } else { | |
| 116 non_ifs_lsp = uv_tcp_non_ifs_lsp_ipv4; | |
| 117 } | |
| 118 | |
| 119 if (!(handle->flags & UV_HANDLE_EMULATE_IOCP) && !non_ifs_lsp) { | |
| 120 UCHAR sfcnm_flags = | |
| 121 FILE_SKIP_SET_EVENT_ON_HANDLE | FILE_SKIP_COMPLETION_PORT_ON_SUCCESS; | |
| 122 if (!SetFileCompletionNotificationModes((HANDLE) socket, sfcnm_flags)) | |
| 123 return GetLastError(); | |
| 124 handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP; | |
| 125 } | |
| 126 | |
| 127 if (handle->flags & UV_HANDLE_TCP_NODELAY) { | |
| 128 err = uv__tcp_nodelay(handle, socket, 1); | |
| 129 if (err) | |
| 130 return err; | |
| 131 } | |
| 132 | |
| 133 /* TODO: Use stored delay. */ | |
| 134 if (handle->flags & UV_HANDLE_TCP_KEEPALIVE) { | |
| 135 err = uv__tcp_keepalive(handle, socket, 1, 60); | |
| 136 if (err) | |
| 137 return err; | |
| 138 } | |
| 139 | |
| 140 handle->socket = socket; | |
| 141 | |
| 142 if (family == AF_INET6) { | |
| 143 handle->flags |= UV_HANDLE_IPV6; | |
| 144 } else { | |
| 145 assert(!(handle->flags & UV_HANDLE_IPV6)); | |
| 146 } | |
| 147 | |
| 148 return 0; | |
| 149 } | |
| 150 | |
| 151 | |
| 152 int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags) { | |
| 153 int domain; | |
| 154 | |
| 155 /* Use the lower 8 bits for the domain */ | |
| 156 domain = flags & 0xFF; | |
| 157 if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC) | |
| 158 return UV_EINVAL; | |
| 159 | |
| 160 if (flags & ~0xFF) | |
| 161 return UV_EINVAL; | |
| 162 | |
| 163 uv__stream_init(loop, (uv_stream_t*) handle, UV_TCP); | |
| 164 handle->tcp.serv.accept_reqs = NULL; | |
| 165 handle->tcp.serv.pending_accepts = NULL; | |
| 166 handle->socket = INVALID_SOCKET; | |
| 167 handle->reqs_pending = 0; | |
| 168 handle->tcp.serv.func_acceptex = NULL; | |
| 169 handle->tcp.conn.func_connectex = NULL; | |
| 170 handle->tcp.serv.processed_accepts = 0; | |
| 171 handle->delayed_error = 0; | |
| 172 | |
| 173 /* If anything fails beyond this point we need to remove the handle from | |
| 174 * the handle queue, since it was added by uv__handle_init in uv__stream_init. | |
| 175 */ | |
| 176 | |
| 177 if (domain != AF_UNSPEC) { | |
| 178 SOCKET sock; | |
| 179 DWORD err; | |
| 180 | |
| 181 sock = socket(domain, SOCK_STREAM, 0); | |
| 182 if (sock == INVALID_SOCKET) { | |
| 183 err = WSAGetLastError(); | |
| 184 uv__queue_remove(&handle->handle_queue); | |
| 185 return uv_translate_sys_error(err); | |
| 186 } | |
| 187 | |
| 188 err = uv__tcp_set_socket(handle->loop, handle, sock, domain, 0); | |
| 189 if (err) { | |
| 190 closesocket(sock); | |
| 191 uv__queue_remove(&handle->handle_queue); | |
| 192 return uv_translate_sys_error(err); | |
| 193 } | |
| 194 | |
| 195 } | |
| 196 | |
| 197 return 0; | |
| 198 } | |
| 199 | |
| 200 | |
| 201 int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) { | |
| 202 return uv_tcp_init_ex(loop, handle, AF_UNSPEC); | |
| 203 } | |
| 204 | |
| 205 | |
| 206 void uv__process_tcp_shutdown_req(uv_loop_t* loop, uv_tcp_t* stream, uv_shutdown_t *req) { | |
| 207 int err; | |
| 208 | |
| 209 assert(req); | |
| 210 assert(stream->stream.conn.write_reqs_pending == 0); | |
| 211 assert(!(stream->flags & UV_HANDLE_SHUT)); | |
| 212 assert(stream->flags & UV_HANDLE_CONNECTION); | |
| 213 | |
| 214 stream->stream.conn.shutdown_req = NULL; | |
| 215 UNREGISTER_HANDLE_REQ(loop, stream); | |
| 216 | |
| 217 err = 0; | |
| 218 if (stream->flags & UV_HANDLE_CLOSING) | |
| 219 /* The user destroyed the stream before we got to do the shutdown. */ | |
| 220 err = UV_ECANCELED; | |
| 221 else if (shutdown(stream->socket, SD_SEND) == SOCKET_ERROR) | |
| 222 err = uv_translate_sys_error(WSAGetLastError()); | |
| 223 else /* Success. */ | |
| 224 stream->flags |= UV_HANDLE_SHUT; | |
| 225 | |
| 226 if (req->cb) | |
| 227 req->cb(req, err); | |
| 228 | |
| 229 DECREASE_PENDING_REQ_COUNT(stream); | |
| 230 } | |
| 231 | |
| 232 | |
| 233 void uv__tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { | |
| 234 unsigned int i; | |
| 235 uv_tcp_accept_t* req; | |
| 236 | |
| 237 assert(handle->flags & UV_HANDLE_CLOSING); | |
| 238 assert(handle->reqs_pending == 0); | |
| 239 assert(!(handle->flags & UV_HANDLE_CLOSED)); | |
| 240 assert(handle->socket == INVALID_SOCKET); | |
| 241 | |
| 242 if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->tcp.serv.accept_reqs) { | |
| 243 if (handle->flags & UV_HANDLE_EMULATE_IOCP) { | |
| 244 for (i = 0; i < uv_simultaneous_server_accepts; i++) { | |
| 245 req = &handle->tcp.serv.accept_reqs[i]; | |
| 246 if (req->wait_handle != INVALID_HANDLE_VALUE) { | |
| 247 UnregisterWait(req->wait_handle); | |
| 248 req->wait_handle = INVALID_HANDLE_VALUE; | |
| 249 } | |
| 250 if (req->event_handle != NULL) { | |
| 251 CloseHandle(req->event_handle); | |
| 252 req->event_handle = NULL; | |
| 253 } | |
| 254 } | |
| 255 } | |
| 256 | |
| 257 uv__free(handle->tcp.serv.accept_reqs); | |
| 258 handle->tcp.serv.accept_reqs = NULL; | |
| 259 } | |
| 260 | |
| 261 if (handle->flags & UV_HANDLE_CONNECTION && | |
| 262 handle->flags & UV_HANDLE_EMULATE_IOCP) { | |
| 263 if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) { | |
| 264 UnregisterWait(handle->read_req.wait_handle); | |
| 265 handle->read_req.wait_handle = INVALID_HANDLE_VALUE; | |
| 266 } | |
| 267 if (handle->read_req.event_handle != NULL) { | |
| 268 CloseHandle(handle->read_req.event_handle); | |
| 269 handle->read_req.event_handle = NULL; | |
| 270 } | |
| 271 } | |
| 272 | |
| 273 uv__handle_close(handle); | |
| 274 } | |
| 275 | |
| 276 | |
| 277 /* Unlike on Unix, here we don't set SO_REUSEADDR, because it doesn't just | |
| 278 * allow binding to addresses that are in use by sockets in TIME_WAIT, it | |
| 279 * effectively allows 'stealing' a port which is in use by another application. | |
| 280 * | |
| 281 * SO_EXCLUSIVEADDRUSE is also not good here because it does check all sockets, | |
| 282 * regardless of state, so we'd get an error even if the port is in use by a | |
| 283 * socket in TIME_WAIT state. | |
| 284 * | |
| 285 * See issue #1360. | |
| 286 * | |
| 287 */ | |
| 288 static int uv__tcp_try_bind(uv_tcp_t* handle, | |
| 289 const struct sockaddr* addr, | |
| 290 unsigned int addrlen, | |
| 291 unsigned int flags) { | |
| 292 DWORD err; | |
| 293 int r; | |
| 294 | |
| 295 /* There is no SO_REUSEPORT on Windows, Windows only knows SO_REUSEADDR. | |
| 296 * so we just return an error directly when UV_TCP_REUSEPORT is requested | |
| 297 * for binding the socket. */ | |
| 298 if (flags & UV_TCP_REUSEPORT) | |
| 299 return ERROR_NOT_SUPPORTED; | |
| 300 | |
| 301 if (handle->socket == INVALID_SOCKET) { | |
| 302 SOCKET sock; | |
| 303 | |
| 304 /* Cannot set IPv6-only mode on non-IPv6 socket. */ | |
| 305 if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6) | |
| 306 return ERROR_INVALID_PARAMETER; | |
| 307 | |
| 308 sock = socket(addr->sa_family, SOCK_STREAM, 0); | |
| 309 if (sock == INVALID_SOCKET) { | |
| 310 return WSAGetLastError(); | |
| 311 } | |
| 312 | |
| 313 err = uv__tcp_set_socket(handle->loop, handle, sock, addr->sa_family, 0); | |
| 314 if (err) { | |
| 315 closesocket(sock); | |
| 316 return err; | |
| 317 } | |
| 318 } | |
| 319 | |
| 320 #ifdef IPV6_V6ONLY | |
| 321 if (addr->sa_family == AF_INET6) { | |
| 322 int on; | |
| 323 | |
| 324 on = (flags & UV_TCP_IPV6ONLY) != 0; | |
| 325 | |
| 326 /* TODO: how to handle errors? This may fail if there is no ipv4 stack | |
| 327 * available, or when run on XP/2003 which have no support for dualstack | |
| 328 * sockets. For now we're silently ignoring the error. */ | |
| 329 setsockopt(handle->socket, | |
| 330 IPPROTO_IPV6, | |
| 331 IPV6_V6ONLY, | |
| 332 (const char*)&on, | |
| 333 sizeof on); | |
| 334 } | |
| 335 #endif | |
| 336 | |
| 337 r = bind(handle->socket, addr, addrlen); | |
| 338 | |
| 339 if (r == SOCKET_ERROR) { | |
| 340 err = WSAGetLastError(); | |
| 341 if (err == WSAEADDRINUSE) { | |
| 342 /* Some errors are not to be reported until connect() or listen() */ | |
| 343 handle->delayed_error = err; | |
| 344 } else { | |
| 345 return err; | |
| 346 } | |
| 347 } | |
| 348 | |
| 349 handle->flags |= UV_HANDLE_BOUND; | |
| 350 | |
| 351 return 0; | |
| 352 } | |
| 353 | |
| 354 | |
| 355 static void CALLBACK post_completion(void* context, BOOLEAN timed_out) { | |
| 356 uv_req_t* req; | |
| 357 uv_tcp_t* handle; | |
| 358 | |
| 359 req = (uv_req_t*) context; | |
| 360 assert(req != NULL); | |
| 361 handle = (uv_tcp_t*)req->data; | |
| 362 assert(handle != NULL); | |
| 363 assert(!timed_out); | |
| 364 | |
| 365 if (!PostQueuedCompletionStatus(handle->loop->iocp, | |
| 366 req->u.io.overlapped.InternalHigh, | |
| 367 0, | |
| 368 &req->u.io.overlapped)) { | |
| 369 uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); | |
| 370 } | |
| 371 } | |
| 372 | |
| 373 | |
| 374 static void CALLBACK post_write_completion(void* context, BOOLEAN timed_out) { | |
| 375 uv_write_t* req; | |
| 376 uv_tcp_t* handle; | |
| 377 | |
| 378 req = (uv_write_t*) context; | |
| 379 assert(req != NULL); | |
| 380 handle = (uv_tcp_t*)req->handle; | |
| 381 assert(handle != NULL); | |
| 382 assert(!timed_out); | |
| 383 | |
| 384 if (!PostQueuedCompletionStatus(handle->loop->iocp, | |
| 385 req->u.io.overlapped.InternalHigh, | |
| 386 0, | |
| 387 &req->u.io.overlapped)) { | |
| 388 uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); | |
| 389 } | |
| 390 } | |
| 391 | |
| 392 | |
| 393 static void uv__tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) { | |
| 394 uv_loop_t* loop = handle->loop; | |
| 395 BOOL success; | |
| 396 DWORD bytes; | |
| 397 SOCKET accept_socket; | |
| 398 short family; | |
| 399 | |
| 400 assert(handle->flags & UV_HANDLE_LISTENING); | |
| 401 assert(req->accept_socket == INVALID_SOCKET); | |
| 402 | |
| 403 /* choose family and extension function */ | |
| 404 if (handle->flags & UV_HANDLE_IPV6) { | |
| 405 family = AF_INET6; | |
| 406 } else { | |
| 407 family = AF_INET; | |
| 408 } | |
| 409 | |
| 410 /* Open a socket for the accepted connection. */ | |
| 411 accept_socket = socket(family, SOCK_STREAM, 0); | |
| 412 if (accept_socket == INVALID_SOCKET) { | |
| 413 SET_REQ_ERROR(req, WSAGetLastError()); | |
| 414 uv__insert_pending_req(loop, (uv_req_t*)req); | |
| 415 handle->reqs_pending++; | |
| 416 return; | |
| 417 } | |
| 418 | |
| 419 /* Make the socket non-inheritable */ | |
| 420 if (!SetHandleInformation((HANDLE) accept_socket, HANDLE_FLAG_INHERIT, 0)) { | |
| 421 SET_REQ_ERROR(req, GetLastError()); | |
| 422 uv__insert_pending_req(loop, (uv_req_t*)req); | |
| 423 handle->reqs_pending++; | |
| 424 closesocket(accept_socket); | |
| 425 return; | |
| 426 } | |
| 427 | |
| 428 /* Prepare the overlapped structure. */ | |
| 429 memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped)); | |
| 430 if (handle->flags & UV_HANDLE_EMULATE_IOCP) { | |
| 431 assert(req->event_handle != NULL); | |
| 432 req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1); | |
| 433 } | |
| 434 | |
| 435 success = handle->tcp.serv.func_acceptex(handle->socket, | |
| 436 accept_socket, | |
| 437 (void*)req->accept_buffer, | |
| 438 0, | |
| 439 sizeof(struct sockaddr_storage), | |
| 440 sizeof(struct sockaddr_storage), | |
| 441 &bytes, | |
| 442 &req->u.io.overlapped); | |
| 443 | |
| 444 if (UV_SUCCEEDED_WITHOUT_IOCP(success)) { | |
| 445 /* Process the req without IOCP. */ | |
| 446 req->accept_socket = accept_socket; | |
| 447 handle->reqs_pending++; | |
| 448 uv__insert_pending_req(loop, (uv_req_t*)req); | |
| 449 } else if (UV_SUCCEEDED_WITH_IOCP(success)) { | |
| 450 /* The req will be processed with IOCP. */ | |
| 451 req->accept_socket = accept_socket; | |
| 452 handle->reqs_pending++; | |
| 453 if (handle->flags & UV_HANDLE_EMULATE_IOCP && | |
| 454 req->wait_handle == INVALID_HANDLE_VALUE && | |
| 455 !RegisterWaitForSingleObject(&req->wait_handle, | |
| 456 req->event_handle, post_completion, (void*) req, | |
| 457 INFINITE, WT_EXECUTEINWAITTHREAD)) { | |
| 458 SET_REQ_ERROR(req, GetLastError()); | |
| 459 uv__insert_pending_req(loop, (uv_req_t*)req); | |
| 460 } | |
| 461 } else { | |
| 462 /* Make this req pending reporting an error. */ | |
| 463 SET_REQ_ERROR(req, WSAGetLastError()); | |
| 464 uv__insert_pending_req(loop, (uv_req_t*)req); | |
| 465 handle->reqs_pending++; | |
| 466 /* Destroy the preallocated client socket. */ | |
| 467 closesocket(accept_socket); | |
| 468 /* Destroy the event handle */ | |
| 469 if (handle->flags & UV_HANDLE_EMULATE_IOCP) { | |
| 470 CloseHandle(req->event_handle); | |
| 471 req->event_handle = NULL; | |
| 472 } | |
| 473 } | |
| 474 } | |
| 475 | |
| 476 | |
| 477 static void uv__tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) { | |
| 478 uv_read_t* req; | |
| 479 uv_buf_t buf; | |
| 480 int result; | |
| 481 DWORD bytes, flags; | |
| 482 | |
| 483 assert(handle->flags & UV_HANDLE_READING); | |
| 484 assert(!(handle->flags & UV_HANDLE_READ_PENDING)); | |
| 485 | |
| 486 req = &handle->read_req; | |
| 487 memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); | |
| 488 | |
| 489 handle->flags |= UV_HANDLE_ZERO_READ; | |
| 490 buf.base = (char*) &uv_zero_; | |
| 491 buf.len = 0; | |
| 492 | |
| 493 /* Prepare the overlapped structure. */ | |
| 494 memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped)); | |
| 495 if (handle->flags & UV_HANDLE_EMULATE_IOCP) { | |
| 496 assert(req->event_handle != NULL); | |
| 497 req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1); | |
| 498 } | |
| 499 | |
| 500 flags = 0; | |
| 501 result = WSARecv(handle->socket, | |
| 502 (WSABUF*)&buf, | |
| 503 1, | |
| 504 &bytes, | |
| 505 &flags, | |
| 506 &req->u.io.overlapped, | |
| 507 NULL); | |
| 508 | |
| 509 handle->flags |= UV_HANDLE_READ_PENDING; | |
| 510 handle->reqs_pending++; | |
| 511 | |
| 512 if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { | |
| 513 /* Process the req without IOCP. */ | |
| 514 req->u.io.overlapped.InternalHigh = bytes; | |
| 515 uv__insert_pending_req(loop, (uv_req_t*)req); | |
| 516 } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { | |
| 517 /* The req will be processed with IOCP. */ | |
| 518 if (handle->flags & UV_HANDLE_EMULATE_IOCP && | |
| 519 req->wait_handle == INVALID_HANDLE_VALUE && | |
| 520 !RegisterWaitForSingleObject(&req->wait_handle, | |
| 521 req->event_handle, post_completion, (void*) req, | |
| 522 INFINITE, WT_EXECUTEINWAITTHREAD)) { | |
| 523 SET_REQ_ERROR(req, GetLastError()); | |
| 524 uv__insert_pending_req(loop, (uv_req_t*)req); | |
| 525 } | |
| 526 } else { | |
| 527 /* Make this req pending reporting an error. */ | |
| 528 SET_REQ_ERROR(req, WSAGetLastError()); | |
| 529 uv__insert_pending_req(loop, (uv_req_t*)req); | |
| 530 } | |
| 531 } | |
| 532 | |
| 533 | |
| 534 int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) { | |
| 535 struct linger l = { 1, 0 }; | |
| 536 | |
| 537 /* Disallow setting SO_LINGER to zero due to some platform inconsistencies */ | |
| 538 if (uv__is_stream_shutting(handle)) | |
| 539 return UV_EINVAL; | |
| 540 | |
| 541 if (0 != setsockopt(handle->socket, SOL_SOCKET, SO_LINGER, (const char*)&l, sizeof(l))) | |
| 542 return uv_translate_sys_error(WSAGetLastError()); | |
| 543 | |
| 544 uv_close((uv_handle_t*) handle, close_cb); | |
| 545 return 0; | |
| 546 } | |
| 547 | |
| 548 | |
| 549 int uv__tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { | |
| 550 unsigned int i, simultaneous_accepts; | |
| 551 uv_tcp_accept_t* req; | |
| 552 int err; | |
| 553 | |
| 554 assert(backlog > 0); | |
| 555 | |
| 556 if (handle->flags & UV_HANDLE_LISTENING) { | |
| 557 handle->stream.serv.connection_cb = cb; | |
| 558 } | |
| 559 | |
| 560 if (handle->flags & UV_HANDLE_READING) { | |
| 561 return WSAEISCONN; | |
| 562 } | |
| 563 | |
| 564 if (handle->delayed_error) { | |
| 565 return handle->delayed_error; | |
| 566 } | |
| 567 | |
| 568 if (!(handle->flags & UV_HANDLE_BOUND)) { | |
| 569 err = uv__tcp_try_bind(handle, | |
| 570 (const struct sockaddr*) &uv_addr_ip4_any_, | |
| 571 sizeof(uv_addr_ip4_any_), | |
| 572 0); | |
| 573 if (err) | |
| 574 return err; | |
| 575 if (handle->delayed_error) | |
| 576 return handle->delayed_error; | |
| 577 } | |
| 578 | |
| 579 if (!handle->tcp.serv.func_acceptex) { | |
| 580 if (!uv__get_acceptex_function(handle->socket, &handle->tcp.serv.func_acceptex)) { | |
| 581 return WSAEAFNOSUPPORT; | |
| 582 } | |
| 583 } | |
| 584 | |
| 585 /* If this flag is set, we already made this listen call in xfer. */ | |
| 586 if (!(handle->flags & UV_HANDLE_SHARED_TCP_SOCKET) && | |
| 587 listen(handle->socket, backlog) == SOCKET_ERROR) { | |
| 588 return WSAGetLastError(); | |
| 589 } | |
| 590 | |
| 591 handle->flags |= UV_HANDLE_LISTENING; | |
| 592 handle->stream.serv.connection_cb = cb; | |
| 593 INCREASE_ACTIVE_COUNT(loop, handle); | |
| 594 | |
| 595 simultaneous_accepts = handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT ? 1 | |
| 596 : uv_simultaneous_server_accepts; | |
| 597 | |
| 598 if (handle->tcp.serv.accept_reqs == NULL) { | |
| 599 handle->tcp.serv.accept_reqs = | |
| 600 uv__malloc(uv_simultaneous_server_accepts * sizeof(uv_tcp_accept_t)); | |
| 601 if (!handle->tcp.serv.accept_reqs) { | |
| 602 uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); | |
| 603 } | |
| 604 | |
| 605 for (i = 0; i < simultaneous_accepts; i++) { | |
| 606 req = &handle->tcp.serv.accept_reqs[i]; | |
| 607 UV_REQ_INIT(req, UV_ACCEPT); | |
| 608 req->accept_socket = INVALID_SOCKET; | |
| 609 req->data = handle; | |
| 610 | |
| 611 req->wait_handle = INVALID_HANDLE_VALUE; | |
| 612 if (handle->flags & UV_HANDLE_EMULATE_IOCP) { | |
| 613 req->event_handle = CreateEvent(NULL, 0, 0, NULL); | |
| 614 if (req->event_handle == NULL) { | |
| 615 uv_fatal_error(GetLastError(), "CreateEvent"); | |
| 616 } | |
| 617 } else { | |
| 618 req->event_handle = NULL; | |
| 619 } | |
| 620 | |
| 621 uv__tcp_queue_accept(handle, req); | |
| 622 } | |
| 623 | |
| 624 /* Initialize other unused requests too, because uv_tcp_endgame doesn't | |
| 625 * know how many requests were initialized, so it will try to clean up | |
| 626 * {uv_simultaneous_server_accepts} requests. */ | |
| 627 for (i = simultaneous_accepts; i < uv_simultaneous_server_accepts; i++) { | |
| 628 req = &handle->tcp.serv.accept_reqs[i]; | |
| 629 UV_REQ_INIT(req, UV_ACCEPT); | |
| 630 req->accept_socket = INVALID_SOCKET; | |
| 631 req->data = handle; | |
| 632 req->wait_handle = INVALID_HANDLE_VALUE; | |
| 633 req->event_handle = NULL; | |
| 634 } | |
| 635 } | |
| 636 | |
| 637 return 0; | |
| 638 } | |
| 639 | |
| 640 | |
| 641 int uv__tcp_accept(uv_tcp_t* server, uv_tcp_t* client) { | |
| 642 int err = 0; | |
| 643 int family; | |
| 644 | |
| 645 uv_tcp_accept_t* req = server->tcp.serv.pending_accepts; | |
| 646 | |
| 647 if (!req) { | |
| 648 /* No valid connections found, so we error out. */ | |
| 649 return WSAEWOULDBLOCK; | |
| 650 } | |
| 651 | |
| 652 if (req->accept_socket == INVALID_SOCKET) { | |
| 653 return WSAENOTCONN; | |
| 654 } | |
| 655 | |
| 656 if (server->flags & UV_HANDLE_IPV6) { | |
| 657 family = AF_INET6; | |
| 658 } else { | |
| 659 family = AF_INET; | |
| 660 } | |
| 661 | |
| 662 err = uv__tcp_set_socket(client->loop, | |
| 663 client, | |
| 664 req->accept_socket, | |
| 665 family, | |
| 666 0); | |
| 667 if (err) { | |
| 668 closesocket(req->accept_socket); | |
| 669 } else { | |
| 670 uv__connection_init((uv_stream_t*) client); | |
| 671 /* AcceptEx() implicitly binds the accepted socket. */ | |
| 672 client->flags |= UV_HANDLE_BOUND | UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; | |
| 673 } | |
| 674 | |
| 675 /* Prepare the req to pick up a new connection */ | |
| 676 server->tcp.serv.pending_accepts = req->next_pending; | |
| 677 req->next_pending = NULL; | |
| 678 req->accept_socket = INVALID_SOCKET; | |
| 679 | |
| 680 if (!(server->flags & UV_HANDLE_CLOSING)) { | |
| 681 /* Check if we're in a middle of changing the number of pending accepts. */ | |
| 682 if (!(server->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING)) { | |
| 683 uv__tcp_queue_accept(server, req); | |
| 684 } else { | |
| 685 /* We better be switching to a single pending accept. */ | |
| 686 assert(server->flags & UV_HANDLE_TCP_SINGLE_ACCEPT); | |
| 687 | |
| 688 server->tcp.serv.processed_accepts++; | |
| 689 | |
| 690 if (server->tcp.serv.processed_accepts >= uv_simultaneous_server_accepts) { | |
| 691 server->tcp.serv.processed_accepts = 0; | |
| 692 /* | |
| 693 * All previously queued accept requests are now processed. | |
| 694 * We now switch to queueing just a single accept. | |
| 695 */ | |
| 696 uv__tcp_queue_accept(server, &server->tcp.serv.accept_reqs[0]); | |
| 697 server->flags &= ~UV_HANDLE_TCP_ACCEPT_STATE_CHANGING; | |
| 698 server->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT; | |
| 699 } | |
| 700 } | |
| 701 } | |
| 702 | |
| 703 return err; | |
| 704 } | |
| 705 | |
| 706 | |
| 707 int uv__tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb, | |
| 708 uv_read_cb read_cb) { | |
| 709 uv_loop_t* loop = handle->loop; | |
| 710 | |
| 711 handle->flags |= UV_HANDLE_READING; | |
| 712 handle->read_cb = read_cb; | |
| 713 handle->alloc_cb = alloc_cb; | |
| 714 INCREASE_ACTIVE_COUNT(loop, handle); | |
| 715 | |
| 716 /* If reading was stopped and then started again, there could still be a read | |
| 717 * request pending. */ | |
| 718 if (!(handle->flags & UV_HANDLE_READ_PENDING)) { | |
| 719 if (handle->flags & UV_HANDLE_EMULATE_IOCP && | |
| 720 handle->read_req.event_handle == NULL) { | |
| 721 handle->read_req.event_handle = CreateEvent(NULL, 0, 0, NULL); | |
| 722 if (handle->read_req.event_handle == NULL) { | |
| 723 uv_fatal_error(GetLastError(), "CreateEvent"); | |
| 724 } | |
| 725 } | |
| 726 uv__tcp_queue_read(loop, handle); | |
| 727 } | |
| 728 | |
| 729 return 0; | |
| 730 } | |
| 731 | |
| 732 static int uv__is_loopback(const struct sockaddr_storage* storage) { | |
| 733 const struct sockaddr_in* in4; | |
| 734 const struct sockaddr_in6* in6; | |
| 735 int i; | |
| 736 | |
| 737 if (storage->ss_family == AF_INET) { | |
| 738 in4 = (const struct sockaddr_in*) storage; | |
| 739 return in4->sin_addr.S_un.S_un_b.s_b1 == 127; | |
| 740 } | |
| 741 if (storage->ss_family == AF_INET6) { | |
| 742 in6 = (const struct sockaddr_in6*) storage; | |
| 743 for (i = 0; i < 7; ++i) { | |
| 744 if (in6->sin6_addr.u.Word[i] != 0) | |
| 745 return 0; | |
| 746 } | |
| 747 return in6->sin6_addr.u.Word[7] == htons(1); | |
| 748 } | |
| 749 return 0; | |
| 750 } | |
| 751 | |
| 752 // Check if Windows version is 10.0.16299 or later | |
| 753 static int uv__is_fast_loopback_fail_supported(void) { | |
| 754 OSVERSIONINFOW os_info; | |
| 755 if (!pRtlGetVersion) | |
| 756 return 0; | |
| 757 pRtlGetVersion(&os_info); | |
| 758 if (os_info.dwMajorVersion < 10) | |
| 759 return 0; | |
| 760 if (os_info.dwMajorVersion > 10) | |
| 761 return 1; | |
| 762 if (os_info.dwMinorVersion > 0) | |
| 763 return 1; | |
| 764 return os_info.dwBuildNumber >= 16299; | |
| 765 } | |
| 766 | |
| 767 static int uv__tcp_try_connect(uv_connect_t* req, | |
| 768 uv_tcp_t* handle, | |
| 769 const struct sockaddr* addr, | |
| 770 unsigned int addrlen, | |
| 771 uv_connect_cb cb) { | |
| 772 uv_loop_t* loop = handle->loop; | |
| 773 TCP_INITIAL_RTO_PARAMETERS retransmit_ioctl; | |
| 774 const struct sockaddr* bind_addr; | |
| 775 struct sockaddr_storage converted; | |
| 776 BOOL success; | |
| 777 DWORD bytes; | |
| 778 int err; | |
| 779 | |
| 780 err = uv__convert_to_localhost_if_unspecified(addr, &converted); | |
| 781 if (err) | |
| 782 return err; | |
| 783 | |
| 784 if (handle->delayed_error != 0) | |
| 785 goto out; | |
| 786 | |
| 787 if (!(handle->flags & UV_HANDLE_BOUND)) { | |
| 788 if (addrlen == sizeof(uv_addr_ip4_any_)) { | |
| 789 bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_; | |
| 790 } else if (addrlen == sizeof(uv_addr_ip6_any_)) { | |
| 791 bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_; | |
| 792 } else { | |
| 793 abort(); | |
| 794 } | |
| 795 err = uv__tcp_try_bind(handle, bind_addr, addrlen, 0); | |
| 796 if (err) | |
| 797 return err; | |
| 798 if (handle->delayed_error != 0) | |
| 799 goto out; | |
| 800 } | |
| 801 | |
| 802 if (!handle->tcp.conn.func_connectex) { | |
| 803 if (!uv__get_connectex_function(handle->socket, &handle->tcp.conn.func_connectex)) { | |
| 804 return WSAEAFNOSUPPORT; | |
| 805 } | |
| 806 } | |
| 807 | |
| 808 /* This makes connect() fail instantly if the target port on the localhost | |
| 809 * is not reachable, instead of waiting for 2s. We do not care if this fails. | |
| 810 * This only works on Windows version 10.0.16299 and later. | |
| 811 */ | |
| 812 if (uv__is_fast_loopback_fail_supported() && uv__is_loopback(&converted)) { | |
| 813 memset(&retransmit_ioctl, 0, sizeof(retransmit_ioctl)); | |
| 814 retransmit_ioctl.Rtt = TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS; | |
| 815 retransmit_ioctl.MaxSynRetransmissions = TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS; | |
| 816 WSAIoctl(handle->socket, | |
| 817 SIO_TCP_INITIAL_RTO, | |
| 818 &retransmit_ioctl, | |
| 819 sizeof(retransmit_ioctl), | |
| 820 NULL, | |
| 821 0, | |
| 822 &bytes, | |
| 823 NULL, | |
| 824 NULL); | |
| 825 } | |
| 826 | |
| 827 out: | |
| 828 | |
| 829 UV_REQ_INIT(req, UV_CONNECT); | |
| 830 req->handle = (uv_stream_t*) handle; | |
| 831 req->cb = cb; | |
| 832 memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); | |
| 833 | |
| 834 if (handle->delayed_error != 0) { | |
| 835 /* Process the req without IOCP. */ | |
| 836 handle->reqs_pending++; | |
| 837 REGISTER_HANDLE_REQ(loop, handle); | |
| 838 uv__insert_pending_req(loop, (uv_req_t*)req); | |
| 839 return 0; | |
| 840 } | |
| 841 | |
| 842 success = handle->tcp.conn.func_connectex(handle->socket, | |
| 843 (const struct sockaddr*) &converted, | |
| 844 addrlen, | |
| 845 NULL, | |
| 846 0, | |
| 847 &bytes, | |
| 848 &req->u.io.overlapped); | |
| 849 | |
| 850 if (UV_SUCCEEDED_WITHOUT_IOCP(success)) { | |
| 851 /* Process the req without IOCP. */ | |
| 852 handle->reqs_pending++; | |
| 853 REGISTER_HANDLE_REQ(loop, handle); | |
| 854 uv__insert_pending_req(loop, (uv_req_t*)req); | |
| 855 } else if (UV_SUCCEEDED_WITH_IOCP(success)) { | |
| 856 /* The req will be processed with IOCP. */ | |
| 857 handle->reqs_pending++; | |
| 858 REGISTER_HANDLE_REQ(loop, handle); | |
| 859 } else { | |
| 860 return WSAGetLastError(); | |
| 861 } | |
| 862 | |
| 863 return 0; | |
| 864 } | |
| 865 | |
| 866 | |
| 867 int uv_tcp_getsockname(const uv_tcp_t* handle, | |
| 868 struct sockaddr* name, | |
| 869 int* namelen) { | |
| 870 | |
| 871 return uv__getsockpeername((const uv_handle_t*) handle, | |
| 872 getsockname, | |
| 873 name, | |
| 874 namelen, | |
| 875 handle->delayed_error); | |
| 876 } | |
| 877 | |
| 878 | |
| 879 int uv_tcp_getpeername(const uv_tcp_t* handle, | |
| 880 struct sockaddr* name, | |
| 881 int* namelen) { | |
| 882 | |
| 883 return uv__getsockpeername((const uv_handle_t*) handle, | |
| 884 getpeername, | |
| 885 name, | |
| 886 namelen, | |
| 887 handle->delayed_error); | |
| 888 } | |
| 889 | |
| 890 | |
| 891 int uv__tcp_write(uv_loop_t* loop, | |
| 892 uv_write_t* req, | |
| 893 uv_tcp_t* handle, | |
| 894 const uv_buf_t bufs[], | |
| 895 unsigned int nbufs, | |
| 896 uv_write_cb cb) { | |
| 897 int result; | |
| 898 DWORD bytes; | |
| 899 | |
| 900 UV_REQ_INIT(req, UV_WRITE); | |
| 901 req->handle = (uv_stream_t*) handle; | |
| 902 req->cb = cb; | |
| 903 | |
| 904 /* Prepare the overlapped structure. */ | |
| 905 memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped)); | |
| 906 if (handle->flags & UV_HANDLE_EMULATE_IOCP) { | |
| 907 req->event_handle = CreateEvent(NULL, 0, 0, NULL); | |
| 908 if (req->event_handle == NULL) { | |
| 909 uv_fatal_error(GetLastError(), "CreateEvent"); | |
| 910 } | |
| 911 req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1); | |
| 912 req->wait_handle = INVALID_HANDLE_VALUE; | |
| 913 } | |
| 914 | |
| 915 result = WSASend(handle->socket, | |
| 916 (WSABUF*) bufs, | |
| 917 nbufs, | |
| 918 &bytes, | |
| 919 0, | |
| 920 &req->u.io.overlapped, | |
| 921 NULL); | |
| 922 | |
| 923 if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { | |
| 924 /* Request completed immediately. */ | |
| 925 req->u.io.queued_bytes = 0; | |
| 926 handle->reqs_pending++; | |
| 927 handle->stream.conn.write_reqs_pending++; | |
| 928 REGISTER_HANDLE_REQ(loop, handle); | |
| 929 uv__insert_pending_req(loop, (uv_req_t*) req); | |
| 930 } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { | |
| 931 /* Request queued by the kernel. */ | |
| 932 req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs); | |
| 933 handle->reqs_pending++; | |
| 934 handle->stream.conn.write_reqs_pending++; | |
| 935 REGISTER_HANDLE_REQ(loop, handle); | |
| 936 handle->write_queue_size += req->u.io.queued_bytes; | |
| 937 if (handle->flags & UV_HANDLE_EMULATE_IOCP && | |
| 938 !RegisterWaitForSingleObject(&req->wait_handle, | |
| 939 req->event_handle, post_write_completion, (void*) req, | |
| 940 INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE)) { | |
| 941 SET_REQ_ERROR(req, GetLastError()); | |
| 942 uv__insert_pending_req(loop, (uv_req_t*)req); | |
| 943 } | |
| 944 } else { | |
| 945 /* Send failed due to an error, report it later */ | |
| 946 req->u.io.queued_bytes = 0; | |
| 947 handle->reqs_pending++; | |
| 948 handle->stream.conn.write_reqs_pending++; | |
| 949 REGISTER_HANDLE_REQ(loop, handle); | |
| 950 SET_REQ_ERROR(req, WSAGetLastError()); | |
| 951 uv__insert_pending_req(loop, (uv_req_t*) req); | |
| 952 } | |
| 953 | |
| 954 return 0; | |
| 955 } | |
| 956 | |
| 957 | |
| 958 int uv__tcp_try_write(uv_tcp_t* handle, | |
| 959 const uv_buf_t bufs[], | |
| 960 unsigned int nbufs) { | |
| 961 int result; | |
| 962 DWORD bytes; | |
| 963 | |
| 964 if (handle->stream.conn.write_reqs_pending > 0) | |
| 965 return UV_EAGAIN; | |
| 966 | |
| 967 result = WSASend(handle->socket, | |
| 968 (WSABUF*) bufs, | |
| 969 nbufs, | |
| 970 &bytes, | |
| 971 0, | |
| 972 NULL, | |
| 973 NULL); | |
| 974 | |
| 975 if (result == SOCKET_ERROR) | |
| 976 return uv_translate_sys_error(WSAGetLastError()); | |
| 977 else | |
| 978 return bytes; | |
| 979 } | |
| 980 | |
| 981 | |
| 982 void uv__process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, | |
| 983 uv_req_t* req) { | |
| 984 DWORD bytes, flags, err; | |
| 985 uv_buf_t buf; | |
| 986 int count; | |
| 987 | |
| 988 assert(handle->type == UV_TCP); | |
| 989 | |
| 990 handle->flags &= ~UV_HANDLE_READ_PENDING; | |
| 991 | |
| 992 if (!REQ_SUCCESS(req)) { | |
| 993 /* An error occurred doing the read. */ | |
| 994 if ((handle->flags & UV_HANDLE_READING) || | |
| 995 !(handle->flags & UV_HANDLE_ZERO_READ)) { | |
| 996 handle->flags &= ~UV_HANDLE_READING; | |
| 997 DECREASE_ACTIVE_COUNT(loop, handle); | |
| 998 buf = (handle->flags & UV_HANDLE_ZERO_READ) ? | |
| 999 uv_buf_init(NULL, 0) : handle->tcp.conn.read_buffer; | |
| 1000 | |
| 1001 err = GET_REQ_SOCK_ERROR(req); | |
| 1002 | |
| 1003 if (err == WSAECONNABORTED) { | |
| 1004 /* Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with Unix. | |
| 1005 */ | |
| 1006 err = WSAECONNRESET; | |
| 1007 } | |
| 1008 handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); | |
| 1009 | |
| 1010 handle->read_cb((uv_stream_t*)handle, | |
| 1011 uv_translate_sys_error(err), | |
| 1012 &buf); | |
| 1013 } | |
| 1014 } else { | |
| 1015 if (!(handle->flags & UV_HANDLE_ZERO_READ)) { | |
| 1016 /* The read was done with a non-zero buffer length. */ | |
| 1017 if (req->u.io.overlapped.InternalHigh > 0) { | |
| 1018 /* Successful read */ | |
| 1019 handle->read_cb((uv_stream_t*)handle, | |
| 1020 req->u.io.overlapped.InternalHigh, | |
| 1021 &handle->tcp.conn.read_buffer); | |
| 1022 /* Read again only if bytes == buf.len */ | |
| 1023 if (req->u.io.overlapped.InternalHigh < handle->tcp.conn.read_buffer.len) { | |
| 1024 goto done; | |
| 1025 } | |
| 1026 } else { | |
| 1027 /* Connection closed */ | |
| 1028 if (handle->flags & UV_HANDLE_READING) { | |
| 1029 handle->flags &= ~UV_HANDLE_READING; | |
| 1030 DECREASE_ACTIVE_COUNT(loop, handle); | |
| 1031 } | |
| 1032 | |
| 1033 buf.base = 0; | |
| 1034 buf.len = 0; | |
| 1035 handle->read_cb((uv_stream_t*)handle, UV_EOF, &handle->tcp.conn.read_buffer); | |
| 1036 goto done; | |
| 1037 } | |
| 1038 } | |
| 1039 | |
| 1040 /* Do nonblocking reads until the buffer is empty */ | |
| 1041 count = 32; | |
| 1042 while ((handle->flags & UV_HANDLE_READING) && (count-- > 0)) { | |
| 1043 buf = uv_buf_init(NULL, 0); | |
| 1044 handle->alloc_cb((uv_handle_t*) handle, 65536, &buf); | |
| 1045 if (buf.base == NULL || buf.len == 0) { | |
| 1046 handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf); | |
| 1047 break; | |
| 1048 } | |
| 1049 assert(buf.base != NULL); | |
| 1050 | |
| 1051 flags = 0; | |
| 1052 if (WSARecv(handle->socket, | |
| 1053 (WSABUF*)&buf, | |
| 1054 1, | |
| 1055 &bytes, | |
| 1056 &flags, | |
| 1057 NULL, | |
| 1058 NULL) != SOCKET_ERROR) { | |
| 1059 if (bytes > 0) { | |
| 1060 /* Successful read */ | |
| 1061 handle->read_cb((uv_stream_t*)handle, bytes, &buf); | |
| 1062 /* Read again only if bytes == buf.len */ | |
| 1063 if (bytes < buf.len) { | |
| 1064 break; | |
| 1065 } | |
| 1066 } else { | |
| 1067 /* Connection closed */ | |
| 1068 handle->flags &= ~UV_HANDLE_READING; | |
| 1069 DECREASE_ACTIVE_COUNT(loop, handle); | |
| 1070 | |
| 1071 handle->read_cb((uv_stream_t*)handle, UV_EOF, &buf); | |
| 1072 break; | |
| 1073 } | |
| 1074 } else { | |
| 1075 err = WSAGetLastError(); | |
| 1076 if (err == WSAEWOULDBLOCK) { | |
| 1077 /* Read buffer was completely empty, report a 0-byte read. */ | |
| 1078 handle->read_cb((uv_stream_t*)handle, 0, &buf); | |
| 1079 } else { | |
| 1080 /* Ouch! serious error. */ | |
| 1081 handle->flags &= ~UV_HANDLE_READING; | |
| 1082 DECREASE_ACTIVE_COUNT(loop, handle); | |
| 1083 | |
| 1084 if (err == WSAECONNABORTED) { | |
| 1085 /* Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with | |
| 1086 * Unix. */ | |
| 1087 err = WSAECONNRESET; | |
| 1088 } | |
| 1089 handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); | |
| 1090 | |
| 1091 handle->read_cb((uv_stream_t*)handle, | |
| 1092 uv_translate_sys_error(err), | |
| 1093 &buf); | |
| 1094 } | |
| 1095 break; | |
| 1096 } | |
| 1097 } | |
| 1098 | |
| 1099 done: | |
| 1100 /* Post another read if still reading and not closing. */ | |
| 1101 if ((handle->flags & UV_HANDLE_READING) && | |
| 1102 !(handle->flags & UV_HANDLE_READ_PENDING)) { | |
| 1103 uv__tcp_queue_read(loop, handle); | |
| 1104 } | |
| 1105 } | |
| 1106 | |
| 1107 DECREASE_PENDING_REQ_COUNT(handle); | |
| 1108 } | |
| 1109 | |
| 1110 | |
| 1111 void uv__process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, | |
| 1112 uv_write_t* req) { | |
| 1113 int err; | |
| 1114 | |
| 1115 assert(handle->type == UV_TCP); | |
| 1116 | |
| 1117 assert(handle->write_queue_size >= req->u.io.queued_bytes); | |
| 1118 handle->write_queue_size -= req->u.io.queued_bytes; | |
| 1119 | |
| 1120 UNREGISTER_HANDLE_REQ(loop, handle); | |
| 1121 | |
| 1122 if (handle->flags & UV_HANDLE_EMULATE_IOCP) { | |
| 1123 if (req->wait_handle != INVALID_HANDLE_VALUE) { | |
| 1124 UnregisterWait(req->wait_handle); | |
| 1125 req->wait_handle = INVALID_HANDLE_VALUE; | |
| 1126 } | |
| 1127 if (req->event_handle != NULL) { | |
| 1128 CloseHandle(req->event_handle); | |
| 1129 req->event_handle = NULL; | |
| 1130 } | |
| 1131 } | |
| 1132 | |
| 1133 if (req->cb) { | |
| 1134 err = uv_translate_sys_error(GET_REQ_SOCK_ERROR(req)); | |
| 1135 if (err == UV_ECONNABORTED) { | |
| 1136 /* use UV_ECANCELED for consistency with Unix */ | |
| 1137 err = UV_ECANCELED; | |
| 1138 } | |
| 1139 req->cb(req, err); | |
| 1140 } | |
| 1141 | |
| 1142 handle->stream.conn.write_reqs_pending--; | |
| 1143 if (handle->stream.conn.write_reqs_pending == 0) { | |
| 1144 if (handle->flags & UV_HANDLE_CLOSING) { | |
| 1145 closesocket(handle->socket); | |
| 1146 handle->socket = INVALID_SOCKET; | |
| 1147 } | |
| 1148 if (uv__is_stream_shutting(handle)) | |
| 1149 uv__process_tcp_shutdown_req(loop, | |
| 1150 handle, | |
| 1151 handle->stream.conn.shutdown_req); | |
| 1152 } | |
| 1153 | |
| 1154 DECREASE_PENDING_REQ_COUNT(handle); | |
| 1155 } | |
| 1156 | |
| 1157 | |
| 1158 void uv__process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle, | |
| 1159 uv_req_t* raw_req) { | |
| 1160 uv_tcp_accept_t* req = (uv_tcp_accept_t*) raw_req; | |
| 1161 int err; | |
| 1162 | |
| 1163 assert(handle->type == UV_TCP); | |
| 1164 | |
| 1165 /* If handle->accepted_socket is not a valid socket, then uv_queue_accept | |
| 1166 * must have failed. This is a serious error. We stop accepting connections | |
| 1167 * and report this error to the connection callback. */ | |
| 1168 if (req->accept_socket == INVALID_SOCKET) { | |
| 1169 if (handle->flags & UV_HANDLE_LISTENING) { | |
| 1170 handle->flags &= ~UV_HANDLE_LISTENING; | |
| 1171 DECREASE_ACTIVE_COUNT(loop, handle); | |
| 1172 if (handle->stream.serv.connection_cb) { | |
| 1173 err = GET_REQ_SOCK_ERROR(req); | |
| 1174 handle->stream.serv.connection_cb((uv_stream_t*)handle, | |
| 1175 uv_translate_sys_error(err)); | |
| 1176 } | |
| 1177 } | |
| 1178 } else if (REQ_SUCCESS(req) && | |
| 1179 setsockopt(req->accept_socket, | |
| 1180 SOL_SOCKET, | |
| 1181 SO_UPDATE_ACCEPT_CONTEXT, | |
| 1182 (char*)&handle->socket, | |
| 1183 sizeof(handle->socket)) == 0) { | |
| 1184 req->next_pending = handle->tcp.serv.pending_accepts; | |
| 1185 handle->tcp.serv.pending_accepts = req; | |
| 1186 | |
| 1187 /* Accept and SO_UPDATE_ACCEPT_CONTEXT were successful. */ | |
| 1188 if (handle->stream.serv.connection_cb) { | |
| 1189 handle->stream.serv.connection_cb((uv_stream_t*)handle, 0); | |
| 1190 } | |
| 1191 } else { | |
| 1192 /* Error related to accepted socket is ignored because the server socket | |
| 1193 * may still be healthy. If the server socket is broken uv_queue_accept | |
| 1194 * will detect it. */ | |
| 1195 closesocket(req->accept_socket); | |
| 1196 req->accept_socket = INVALID_SOCKET; | |
| 1197 if (handle->flags & UV_HANDLE_LISTENING) { | |
| 1198 uv__tcp_queue_accept(handle, req); | |
| 1199 } | |
| 1200 } | |
| 1201 | |
| 1202 DECREASE_PENDING_REQ_COUNT(handle); | |
| 1203 } | |
| 1204 | |
| 1205 | |
| 1206 void uv__process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, | |
| 1207 uv_connect_t* req) { | |
| 1208 int err; | |
| 1209 | |
| 1210 assert(handle->type == UV_TCP); | |
| 1211 | |
| 1212 UNREGISTER_HANDLE_REQ(loop, handle); | |
| 1213 | |
| 1214 err = 0; | |
| 1215 if (handle->delayed_error) { | |
| 1216 /* To smooth over the differences between unixes errors that | |
| 1217 * were reported synchronously on the first connect can be delayed | |
| 1218 * until the next tick--which is now. | |
| 1219 */ | |
| 1220 err = handle->delayed_error; | |
| 1221 handle->delayed_error = 0; | |
| 1222 } else if (REQ_SUCCESS(req)) { | |
| 1223 if (handle->flags & UV_HANDLE_CLOSING) { | |
| 1224 /* use UV_ECANCELED for consistency with Unix */ | |
| 1225 err = ERROR_OPERATION_ABORTED; | |
| 1226 } else if (setsockopt(handle->socket, | |
| 1227 SOL_SOCKET, | |
| 1228 SO_UPDATE_CONNECT_CONTEXT, | |
| 1229 NULL, | |
| 1230 0) == 0) { | |
| 1231 uv__connection_init((uv_stream_t*)handle); | |
| 1232 handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; | |
| 1233 } else { | |
| 1234 err = WSAGetLastError(); | |
| 1235 } | |
| 1236 } else { | |
| 1237 err = GET_REQ_SOCK_ERROR(req); | |
| 1238 } | |
| 1239 req->cb(req, uv_translate_sys_error(err)); | |
| 1240 | |
| 1241 DECREASE_PENDING_REQ_COUNT(handle); | |
| 1242 } | |
| 1243 | |
| 1244 | |
| 1245 int uv__tcp_xfer_export(uv_tcp_t* handle, | |
| 1246 int target_pid, | |
| 1247 uv__ipc_socket_xfer_type_t* xfer_type, | |
| 1248 uv__ipc_socket_xfer_info_t* xfer_info) { | |
| 1249 if (handle->flags & UV_HANDLE_CONNECTION) { | |
| 1250 *xfer_type = UV__IPC_SOCKET_XFER_TCP_CONNECTION; | |
| 1251 } else { | |
| 1252 *xfer_type = UV__IPC_SOCKET_XFER_TCP_SERVER; | |
| 1253 /* We're about to share the socket with another process. Because this is a | |
| 1254 * listening socket, we assume that the other process will be accepting | |
| 1255 * connections on it. Thus, before sharing the socket with another process, | |
| 1256 * we call listen here in the parent process. */ | |
| 1257 if (!(handle->flags & UV_HANDLE_LISTENING)) { | |
| 1258 if (!(handle->flags & UV_HANDLE_BOUND)) { | |
| 1259 return ERROR_NOT_SUPPORTED; | |
| 1260 } | |
| 1261 if (handle->delayed_error == 0 && | |
| 1262 listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) { | |
| 1263 handle->delayed_error = WSAGetLastError(); | |
| 1264 } | |
| 1265 } | |
| 1266 } | |
| 1267 | |
| 1268 if (WSADuplicateSocketW(handle->socket, target_pid, &xfer_info->socket_info)) | |
| 1269 return WSAGetLastError(); | |
| 1270 xfer_info->delayed_error = handle->delayed_error; | |
| 1271 | |
| 1272 /* Mark the local copy of the handle as 'shared' so we behave in a way that's | |
| 1273 * friendly to the process(es) that we share the socket with. */ | |
| 1274 handle->flags |= UV_HANDLE_SHARED_TCP_SOCKET; | |
| 1275 | |
| 1276 return 0; | |
| 1277 } | |
| 1278 | |
| 1279 | |
| 1280 int uv__tcp_xfer_import(uv_tcp_t* tcp, | |
| 1281 uv__ipc_socket_xfer_type_t xfer_type, | |
| 1282 uv__ipc_socket_xfer_info_t* xfer_info) { | |
| 1283 int err; | |
| 1284 SOCKET socket; | |
| 1285 | |
| 1286 assert(xfer_type == UV__IPC_SOCKET_XFER_TCP_SERVER || | |
| 1287 xfer_type == UV__IPC_SOCKET_XFER_TCP_CONNECTION); | |
| 1288 | |
| 1289 socket = WSASocketW(FROM_PROTOCOL_INFO, | |
| 1290 FROM_PROTOCOL_INFO, | |
| 1291 FROM_PROTOCOL_INFO, | |
| 1292 &xfer_info->socket_info, | |
| 1293 0, | |
| 1294 WSA_FLAG_OVERLAPPED); | |
| 1295 | |
| 1296 if (socket == INVALID_SOCKET) { | |
| 1297 return WSAGetLastError(); | |
| 1298 } | |
| 1299 | |
| 1300 err = uv__tcp_set_socket( | |
| 1301 tcp->loop, tcp, socket, xfer_info->socket_info.iAddressFamily, 1); | |
| 1302 if (err) { | |
| 1303 closesocket(socket); | |
| 1304 return err; | |
| 1305 } | |
| 1306 | |
| 1307 tcp->delayed_error = xfer_info->delayed_error; | |
| 1308 tcp->flags |= UV_HANDLE_BOUND | UV_HANDLE_SHARED_TCP_SOCKET; | |
| 1309 | |
| 1310 if (xfer_type == UV__IPC_SOCKET_XFER_TCP_CONNECTION) { | |
| 1311 uv__connection_init((uv_stream_t*)tcp); | |
| 1312 tcp->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; | |
| 1313 } | |
| 1314 | |
| 1315 return 0; | |
| 1316 } | |
| 1317 | |
| 1318 | |
| 1319 int uv_tcp_nodelay(uv_tcp_t* handle, int enable) { | |
| 1320 int err; | |
| 1321 | |
| 1322 if (handle->socket != INVALID_SOCKET) { | |
| 1323 err = uv__tcp_nodelay(handle, handle->socket, enable); | |
| 1324 if (err) | |
| 1325 return uv_translate_sys_error(err); | |
| 1326 } | |
| 1327 | |
| 1328 if (enable) { | |
| 1329 handle->flags |= UV_HANDLE_TCP_NODELAY; | |
| 1330 } else { | |
| 1331 handle->flags &= ~UV_HANDLE_TCP_NODELAY; | |
| 1332 } | |
| 1333 | |
| 1334 return 0; | |
| 1335 } | |
| 1336 | |
| 1337 | |
| 1338 int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) { | |
| 1339 int err; | |
| 1340 | |
| 1341 if (handle->socket != INVALID_SOCKET) { | |
| 1342 err = uv__tcp_keepalive(handle, handle->socket, enable, delay); | |
| 1343 if (err) | |
| 1344 return uv_translate_sys_error(err); | |
| 1345 } | |
| 1346 | |
| 1347 if (enable) { | |
| 1348 handle->flags |= UV_HANDLE_TCP_KEEPALIVE; | |
| 1349 } else { | |
| 1350 handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE; | |
| 1351 } | |
| 1352 | |
| 1353 /* TODO: Store delay if handle->socket isn't created yet. */ | |
| 1354 | |
| 1355 return 0; | |
| 1356 } | |
| 1357 | |
| 1358 | |
| 1359 int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) { | |
| 1360 if (handle->flags & UV_HANDLE_CONNECTION) { | |
| 1361 return UV_EINVAL; | |
| 1362 } | |
| 1363 | |
| 1364 /* Check if we're already in the desired mode. */ | |
| 1365 if ((enable && !(handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) || | |
| 1366 (!enable && handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) { | |
| 1367 return 0; | |
| 1368 } | |
| 1369 | |
| 1370 /* Don't allow switching from single pending accept to many. */ | |
| 1371 if (enable) { | |
| 1372 return UV_ENOTSUP; | |
| 1373 } | |
| 1374 | |
| 1375 /* Check if we're in a middle of changing the number of pending accepts. */ | |
| 1376 if (handle->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING) { | |
| 1377 return 0; | |
| 1378 } | |
| 1379 | |
| 1380 handle->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT; | |
| 1381 | |
| 1382 /* Flip the changing flag if we have already queued multiple accepts. */ | |
| 1383 if (handle->flags & UV_HANDLE_LISTENING) { | |
| 1384 handle->flags |= UV_HANDLE_TCP_ACCEPT_STATE_CHANGING; | |
| 1385 } | |
| 1386 | |
| 1387 return 0; | |
| 1388 } | |
| 1389 | |
| 1390 | |
| 1391 static void uv__tcp_try_cancel_reqs(uv_tcp_t* tcp) { | |
| 1392 SOCKET socket; | |
| 1393 int non_ifs_lsp; | |
| 1394 int reading; | |
| 1395 int writing; | |
| 1396 | |
| 1397 socket = tcp->socket; | |
| 1398 reading = tcp->flags & UV_HANDLE_READ_PENDING; | |
| 1399 writing = tcp->stream.conn.write_reqs_pending > 0; | |
| 1400 if (!reading && !writing) | |
| 1401 return; | |
| 1402 | |
| 1403 /* TODO: in libuv v2, keep explicit track of write_reqs, so we can cancel | |
| 1404 * them each explicitly with CancelIoEx (like unix). */ | |
| 1405 if (reading) | |
| 1406 CancelIoEx((HANDLE) socket, &tcp->read_req.u.io.overlapped); | |
| 1407 if (writing) | |
| 1408 CancelIo((HANDLE) socket); | |
| 1409 | |
| 1410 /* Check if we have any non-IFS LSPs stacked on top of TCP */ | |
| 1411 non_ifs_lsp = (tcp->flags & UV_HANDLE_IPV6) ? uv_tcp_non_ifs_lsp_ipv6 : | |
| 1412 uv_tcp_non_ifs_lsp_ipv4; | |
| 1413 | |
| 1414 /* If there are non-ifs LSPs then try to obtain a base handle for the socket. | |
| 1415 */ | |
| 1416 if (non_ifs_lsp) { | |
| 1417 DWORD bytes; | |
| 1418 if (WSAIoctl(socket, | |
| 1419 SIO_BASE_HANDLE, | |
| 1420 NULL, | |
| 1421 0, | |
| 1422 &socket, | |
| 1423 sizeof socket, | |
| 1424 &bytes, | |
| 1425 NULL, | |
| 1426 NULL) != 0) { | |
| 1427 /* Failed. We can't do CancelIo. */ | |
| 1428 return; | |
| 1429 } | |
| 1430 } | |
| 1431 | |
| 1432 assert(socket != 0 && socket != INVALID_SOCKET); | |
| 1433 | |
| 1434 if (socket != tcp->socket) { | |
| 1435 if (reading) | |
| 1436 CancelIoEx((HANDLE) socket, &tcp->read_req.u.io.overlapped); | |
| 1437 if (writing) | |
| 1438 CancelIo((HANDLE) socket); | |
| 1439 } | |
| 1440 } | |
| 1441 | |
| 1442 | |
| 1443 void uv__tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) { | |
| 1444 if (tcp->flags & UV_HANDLE_CONNECTION) { | |
| 1445 if (tcp->flags & UV_HANDLE_READING) { | |
| 1446 uv_read_stop((uv_stream_t*) tcp); | |
| 1447 } | |
| 1448 uv__tcp_try_cancel_reqs(tcp); | |
| 1449 } else { | |
| 1450 if (tcp->tcp.serv.accept_reqs != NULL) { | |
| 1451 /* First close the incoming sockets to cancel the accept operations before | |
| 1452 * we free their resources. */ | |
| 1453 unsigned int i; | |
| 1454 for (i = 0; i < uv_simultaneous_server_accepts; i++) { | |
| 1455 uv_tcp_accept_t* req = &tcp->tcp.serv.accept_reqs[i]; | |
| 1456 if (req->accept_socket != INVALID_SOCKET) { | |
| 1457 closesocket(req->accept_socket); | |
| 1458 req->accept_socket = INVALID_SOCKET; | |
| 1459 } | |
| 1460 } | |
| 1461 } | |
| 1462 assert(!(tcp->flags & UV_HANDLE_READING)); | |
| 1463 } | |
| 1464 | |
| 1465 if (tcp->flags & UV_HANDLE_LISTENING) { | |
| 1466 tcp->flags &= ~UV_HANDLE_LISTENING; | |
| 1467 DECREASE_ACTIVE_COUNT(loop, tcp); | |
| 1468 } | |
| 1469 | |
| 1470 tcp->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); | |
| 1471 uv__handle_closing(tcp); | |
| 1472 | |
| 1473 /* If any overlapped req failed to cancel, calling `closesocket` now would | |
| 1474 * cause Win32 to send an RST packet. Try to avoid that for writes, if | |
| 1475 * possibly applicable, by waiting to process the completion notifications | |
| 1476 * first (which typically should be cancellations). There's not much we can | |
| 1477 * do about canceled reads, which also will generate an RST packet. */ | |
| 1478 if (!(tcp->flags & UV_HANDLE_CONNECTION) || | |
| 1479 tcp->stream.conn.write_reqs_pending == 0) { | |
| 1480 closesocket(tcp->socket); | |
| 1481 tcp->socket = INVALID_SOCKET; | |
| 1482 } | |
| 1483 | |
| 1484 if (tcp->reqs_pending == 0) | |
| 1485 uv__want_endgame(loop, (uv_handle_t*) tcp); | |
| 1486 } | |
| 1487 | |
| 1488 | |
| 1489 int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) { | |
| 1490 WSAPROTOCOL_INFOW protocol_info; | |
| 1491 int opt_len; | |
| 1492 int err; | |
| 1493 struct sockaddr_storage saddr; | |
| 1494 int saddr_len; | |
| 1495 | |
| 1496 /* Detect the address family of the socket. */ | |
| 1497 opt_len = (int) sizeof protocol_info; | |
| 1498 if (getsockopt(sock, | |
| 1499 SOL_SOCKET, | |
| 1500 SO_PROTOCOL_INFOW, | |
| 1501 (char*) &protocol_info, | |
| 1502 &opt_len) == SOCKET_ERROR) { | |
| 1503 return uv_translate_sys_error(GetLastError()); | |
| 1504 } | |
| 1505 | |
| 1506 err = uv__tcp_set_socket(handle->loop, | |
| 1507 handle, | |
| 1508 sock, | |
| 1509 protocol_info.iAddressFamily, | |
| 1510 1); | |
| 1511 if (err) { | |
| 1512 return uv_translate_sys_error(err); | |
| 1513 } | |
| 1514 | |
| 1515 /* Support already active socket. */ | |
| 1516 saddr_len = sizeof(saddr); | |
| 1517 if (!uv_tcp_getsockname(handle, (struct sockaddr*) &saddr, &saddr_len)) { | |
| 1518 /* Socket is already bound. */ | |
| 1519 handle->flags |= UV_HANDLE_BOUND; | |
| 1520 saddr_len = sizeof(saddr); | |
| 1521 if (!uv_tcp_getpeername(handle, (struct sockaddr*) &saddr, &saddr_len)) { | |
| 1522 /* Socket is already connected. */ | |
| 1523 uv__connection_init((uv_stream_t*) handle); | |
| 1524 handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; | |
| 1525 } | |
| 1526 } | |
| 1527 | |
| 1528 return 0; | |
| 1529 } | |
| 1530 | |
| 1531 | |
| 1532 /* This function is an egress point, i.e. it returns libuv errors rather than | |
| 1533 * system errors. | |
| 1534 */ | |
| 1535 int uv__tcp_bind(uv_tcp_t* handle, | |
| 1536 const struct sockaddr* addr, | |
| 1537 unsigned int addrlen, | |
| 1538 unsigned int flags) { | |
| 1539 int err; | |
| 1540 | |
| 1541 err = uv__tcp_try_bind(handle, addr, addrlen, flags); | |
| 1542 if (err) | |
| 1543 return uv_translate_sys_error(err); | |
| 1544 | |
| 1545 return 0; | |
| 1546 } | |
| 1547 | |
| 1548 | |
| 1549 /* This function is an egress point, i.e. it returns libuv errors rather than | |
| 1550 * system errors. | |
| 1551 */ | |
| 1552 int uv__tcp_connect(uv_connect_t* req, | |
| 1553 uv_tcp_t* handle, | |
| 1554 const struct sockaddr* addr, | |
| 1555 unsigned int addrlen, | |
| 1556 uv_connect_cb cb) { | |
| 1557 int err; | |
| 1558 | |
| 1559 err = uv__tcp_try_connect(req, handle, addr, addrlen, cb); | |
| 1560 if (err) | |
| 1561 return uv_translate_sys_error(err); | |
| 1562 | |
| 1563 return 0; | |
| 1564 } | |
| 1565 | |
| 1566 | |
| 1567 int uv_socketpair(int type, int protocol, uv_os_sock_t fds[2], int flags0, int flags1) { | |
| 1568 SOCKET server = INVALID_SOCKET; | |
| 1569 SOCKET client0 = INVALID_SOCKET; | |
| 1570 SOCKET client1 = INVALID_SOCKET; | |
| 1571 SOCKADDR_IN name; | |
| 1572 LPFN_ACCEPTEX func_acceptex; | |
| 1573 WSAOVERLAPPED overlap; | |
| 1574 char accept_buffer[sizeof(struct sockaddr_storage) * 2 + 32]; | |
| 1575 int namelen; | |
| 1576 int err; | |
| 1577 DWORD bytes; | |
| 1578 DWORD flags; | |
| 1579 DWORD client0_flags = WSA_FLAG_NO_HANDLE_INHERIT; | |
| 1580 DWORD client1_flags = WSA_FLAG_NO_HANDLE_INHERIT; | |
| 1581 | |
| 1582 if (flags0 & UV_NONBLOCK_PIPE) | |
| 1583 client0_flags |= WSA_FLAG_OVERLAPPED; | |
| 1584 if (flags1 & UV_NONBLOCK_PIPE) | |
| 1585 client1_flags |= WSA_FLAG_OVERLAPPED; | |
| 1586 | |
| 1587 server = WSASocketW(AF_INET, type, protocol, NULL, 0, | |
| 1588 WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT); | |
| 1589 if (server == INVALID_SOCKET) | |
| 1590 goto wsaerror; | |
| 1591 if (!SetHandleInformation((HANDLE) server, HANDLE_FLAG_INHERIT, 0)) | |
| 1592 goto error; | |
| 1593 name.sin_family = AF_INET; | |
| 1594 name.sin_addr.s_addr = htonl(INADDR_LOOPBACK); | |
| 1595 name.sin_port = 0; | |
| 1596 if (bind(server, (SOCKADDR*) &name, sizeof(name)) != 0) | |
| 1597 goto wsaerror; | |
| 1598 if (listen(server, 1) != 0) | |
| 1599 goto wsaerror; | |
| 1600 namelen = sizeof(name); | |
| 1601 if (getsockname(server, (SOCKADDR*) &name, &namelen) != 0) | |
| 1602 goto wsaerror; | |
| 1603 client0 = WSASocketW(AF_INET, type, protocol, NULL, 0, client0_flags); | |
| 1604 if (client0 == INVALID_SOCKET) | |
| 1605 goto wsaerror; | |
| 1606 if (!SetHandleInformation((HANDLE) client0, HANDLE_FLAG_INHERIT, 0)) | |
| 1607 goto error; | |
| 1608 if (connect(client0, (SOCKADDR*) &name, sizeof(name)) != 0) | |
| 1609 goto wsaerror; | |
| 1610 client1 = WSASocketW(AF_INET, type, protocol, NULL, 0, client1_flags); | |
| 1611 if (client1 == INVALID_SOCKET) | |
| 1612 goto wsaerror; | |
| 1613 if (!SetHandleInformation((HANDLE) client1, HANDLE_FLAG_INHERIT, 0)) | |
| 1614 goto error; | |
| 1615 if (!uv__get_acceptex_function(server, &func_acceptex)) { | |
| 1616 err = WSAEAFNOSUPPORT; | |
| 1617 goto cleanup; | |
| 1618 } | |
| 1619 memset(&overlap, 0, sizeof(overlap)); | |
| 1620 if (!func_acceptex(server, | |
| 1621 client1, | |
| 1622 accept_buffer, | |
| 1623 0, | |
| 1624 sizeof(struct sockaddr_storage), | |
| 1625 sizeof(struct sockaddr_storage), | |
| 1626 &bytes, | |
| 1627 &overlap)) { | |
| 1628 err = WSAGetLastError(); | |
| 1629 if (err == ERROR_IO_PENDING) { | |
| 1630 /* Result should complete immediately, since we already called connect, | |
| 1631 * but empirically, we sometimes have to poll the kernel a couple times | |
| 1632 * until it notices that. */ | |
| 1633 while (!WSAGetOverlappedResult(client1, &overlap, &bytes, FALSE, &flags)) { | |
| 1634 err = WSAGetLastError(); | |
| 1635 if (err != WSA_IO_INCOMPLETE) | |
| 1636 goto cleanup; | |
| 1637 SwitchToThread(); | |
| 1638 } | |
| 1639 } | |
| 1640 else { | |
| 1641 goto cleanup; | |
| 1642 } | |
| 1643 } | |
| 1644 if (setsockopt(client1, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, | |
| 1645 (char*) &server, sizeof(server)) != 0) { | |
| 1646 goto wsaerror; | |
| 1647 } | |
| 1648 | |
| 1649 closesocket(server); | |
| 1650 | |
| 1651 fds[0] = client0; | |
| 1652 fds[1] = client1; | |
| 1653 | |
| 1654 return 0; | |
| 1655 | |
| 1656 wsaerror: | |
| 1657 err = WSAGetLastError(); | |
| 1658 goto cleanup; | |
| 1659 | |
| 1660 error: | |
| 1661 err = GetLastError(); | |
| 1662 goto cleanup; | |
| 1663 | |
| 1664 cleanup: | |
| 1665 if (server != INVALID_SOCKET) | |
| 1666 closesocket(server); | |
| 1667 if (client0 != INVALID_SOCKET) | |
| 1668 closesocket(client0); | |
| 1669 if (client1 != INVALID_SOCKET) | |
| 1670 closesocket(client1); | |
| 1671 | |
| 1672 assert(err); | |
| 1673 return uv_translate_sys_error(err); | |
| 1674 } |