1 /* $NetBSD: tcp.c,v 1.1 2024/02/18 20:57:55 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 #include <libgen.h> 17 #include <unistd.h> 18 #include <uv.h> 19 20 #include <isc/atomic.h> 21 #include <isc/barrier.h> 22 #include <isc/buffer.h> 23 #include <isc/condition.h> 24 #include <isc/errno.h> 25 #include <isc/log.h> 26 #include <isc/magic.h> 27 #include <isc/mem.h> 28 #include <isc/netmgr.h> 29 #include <isc/quota.h> 30 #include <isc/random.h> 31 #include <isc/refcount.h> 32 #include <isc/region.h> 33 #include <isc/result.h> 34 #include <isc/sockaddr.h> 35 #include <isc/stdtime.h> 36 #include <isc/thread.h> 37 #include <isc/util.h> 38 39 #include "netmgr-int.h" 40 #include "uv-compat.h" 41 42 static atomic_uint_fast32_t last_tcpquota_log = 0; 43 44 static bool 45 can_log_tcp_quota(void) { 46 isc_stdtime_t now, last; 47 48 isc_stdtime_get(&now); 49 last = atomic_exchange_relaxed(&last_tcpquota_log, now); 50 if (now != last) { 51 return (true); 52 } 53 54 return (false); 55 } 56 57 static isc_result_t 58 tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req); 59 60 static void 61 tcp_close_direct(isc_nmsocket_t *sock); 62 63 static isc_result_t 64 tcp_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req); 65 static void 66 tcp_connect_cb(uv_connect_t *uvreq, int status); 67 68 static void 69 tcp_connection_cb(uv_stream_t *server, int status); 70 71 static void 72 tcp_close_cb(uv_handle_t *uvhandle); 73 74 static isc_result_t 75 accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota); 76 77 static void 78 quota_accept_cb(isc_quota_t *quota, void *sock0); 79 80 static void 81 failed_accept_cb(isc_nmsocket_t *sock, isc_result_t eresult); 82 83 static void 84 stop_tcp_parent(isc_nmsocket_t *sock); 85 static void 86 stop_tcp_child(isc_nmsocket_t *sock); 87 88 static void 89 failed_accept_cb(isc_nmsocket_t *sock, isc_result_t eresult) { 90 REQUIRE(sock->accepting); 91 REQUIRE(sock->server); 92 93 /* 94 * Detach the quota early to make room for other connections; 95 * otherwise it'd be detached later asynchronously, and clog 96 * the quota unnecessarily. 97 */ 98 if (sock->quota != NULL) { 99 isc_quota_detach(&sock->quota); 100 } 101 102 isc__nmsocket_detach(&sock->server); 103 104 sock->accepting = false; 105 106 switch (eresult) { 107 case ISC_R_NOTCONNECTED: 108 /* IGNORE: The client disconnected before we could accept */ 109 break; 110 default: 111 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 112 ISC_LOGMODULE_NETMGR, ISC_LOG_ERROR, 113 "Accepting TCP connection failed: %s", 114 isc_result_totext(eresult)); 115 } 116 } 117 118 static isc_result_t 119 tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { 120 isc__networker_t *worker = NULL; 121 isc_result_t result = ISC_R_UNSET; 122 int r; 123 124 REQUIRE(VALID_NMSOCK(sock)); 125 REQUIRE(VALID_UVREQ(req)); 126 127 REQUIRE(isc__nm_in_netthread()); 128 REQUIRE(sock->tid == isc_nm_tid()); 129 130 worker = &sock->mgr->workers[sock->tid]; 131 132 atomic_store(&sock->connecting, true); 133 134 /* 2 minute timeout */ 135 result = isc__nm_socket_connectiontimeout(sock->fd, 120 * 1000); 136 RUNTIME_CHECK(result == ISC_R_SUCCESS); 137 138 r = uv_tcp_init(&worker->loop, &sock->uv_handle.tcp); 139 UV_RUNTIME_CHECK(uv_tcp_init, r); 140 uv_handle_set_data(&sock->uv_handle.handle, sock); 141 142 r = uv_timer_init(&worker->loop, &sock->read_timer); 143 UV_RUNTIME_CHECK(uv_timer_init, r); 144 uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock); 145 146 r = uv_tcp_open(&sock->uv_handle.tcp, sock->fd); 147 if (r != 0) { 148 isc__nm_closesocket(sock->fd); 149 isc__nm_incstats(sock->mgr, sock->statsindex[STATID_OPENFAIL]); 150 goto done; 151 } 152 isc__nm_incstats(sock->mgr, sock->statsindex[STATID_OPEN]); 153 154 if (req->local.length != 0) { 155 r = uv_tcp_bind(&sock->uv_handle.tcp, &req->local.type.sa, 0); 156 if (r != 0) { 157 isc__nm_incstats(sock->mgr, 158 sock->statsindex[STATID_BINDFAIL]); 159 goto done; 160 } 161 } 162 163 uv_handle_set_data(&req->uv_req.handle, req); 164 r = uv_tcp_connect(&req->uv_req.connect, &sock->uv_handle.tcp, 165 &req->peer.type.sa, tcp_connect_cb); 166 if (r != 0) { 167 isc__nm_incstats(sock->mgr, 168 sock->statsindex[STATID_CONNECTFAIL]); 169 goto done; 170 } 171 isc__nm_incstats(sock->mgr, sock->statsindex[STATID_CONNECT]); 172 173 uv_handle_set_data((uv_handle_t *)&sock->read_timer, 174 &req->uv_req.connect); 175 isc__nmsocket_timer_start(sock); 176 177 atomic_store(&sock->connected, true); 178 179 done: 180 result = isc__nm_uverr2result(r); 181 LOCK(&sock->lock); 182 sock->result = result; 183 SIGNAL(&sock->cond); 184 if (!atomic_load(&sock->active)) { 185 WAIT(&sock->scond, &sock->lock); 186 } 187 INSIST(atomic_load(&sock->active)); 188 UNLOCK(&sock->lock); 189 190 return (result); 191 } 192 193 void 194 isc__nm_async_tcpconnect(isc__networker_t *worker, isc__netievent_t *ev0) { 195 isc__netievent_tcpconnect_t *ievent = 196 (isc__netievent_tcpconnect_t *)ev0; 197 isc_nmsocket_t *sock = ievent->sock; 198 isc__nm_uvreq_t *req = ievent->req; 199 isc_result_t result = ISC_R_SUCCESS; 200 201 UNUSED(worker); 202 203 REQUIRE(VALID_NMSOCK(sock)); 204 REQUIRE(sock->type == isc_nm_tcpsocket); 205 REQUIRE(sock->parent == NULL); 206 REQUIRE(sock->tid == isc_nm_tid()); 207 208 result = tcp_connect_direct(sock, req); 209 if (result != ISC_R_SUCCESS) { 210 atomic_store(&sock->active, false); 211 if (sock->fd != (uv_os_sock_t)(-1)) { 212 isc__nm_tcp_close(sock); 213 } 214 isc__nm_connectcb(sock, req, result, true); 215 } 216 217 /* 218 * The sock is now attached to the handle. 219 */ 220 isc__nmsocket_detach(&sock); 221 } 222 223 static void 224 tcp_connect_cb(uv_connect_t *uvreq, int status) { 225 isc_result_t result; 226 isc__nm_uvreq_t *req = NULL; 227 isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)uvreq->handle); 228 struct sockaddr_storage ss; 229 int r; 230 231 REQUIRE(VALID_NMSOCK(sock)); 232 REQUIRE(sock->tid == isc_nm_tid()); 233 234 isc__nmsocket_timer_stop(sock); 235 uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock); 236 237 req = uv_handle_get_data((uv_handle_t *)uvreq); 238 239 REQUIRE(VALID_UVREQ(req)); 240 REQUIRE(VALID_NMHANDLE(req->handle)); 241 242 if (atomic_load(&sock->timedout)) { 243 result = ISC_R_TIMEDOUT; 244 goto error; 245 } 246 247 if (!atomic_load(&sock->connecting)) { 248 /* 249 * The connect was cancelled from timeout; just clean up 250 * the req. 251 */ 252 isc__nm_uvreq_put(&req, sock); 253 return; 254 } else if (isc__nmsocket_closing(sock)) { 255 /* Socket was closed midflight by isc__nm_tcp_shutdown() */ 256 result = ISC_R_CANCELED; 257 goto error; 258 } else if (status == UV_ETIMEDOUT) { 259 /* Timeout status code here indicates hard error */ 260 result = ISC_R_TIMEDOUT; 261 goto error; 262 } else if (status != 0) { 263 result = isc__nm_uverr2result(status); 264 goto error; 265 } 266 267 isc__nm_incstats(sock->mgr, sock->statsindex[STATID_CONNECT]); 268 r = uv_tcp_getpeername(&sock->uv_handle.tcp, (struct sockaddr *)&ss, 269 &(int){ sizeof(ss) }); 270 if (r != 0) { 271 result = isc__nm_uverr2result(r); 272 goto error; 273 } 274 275 atomic_store(&sock->connecting, false); 276 277 result = isc_sockaddr_fromsockaddr(&sock->peer, (struct sockaddr *)&ss); 278 RUNTIME_CHECK(result == ISC_R_SUCCESS); 279 280 isc__nm_connectcb(sock, req, ISC_R_SUCCESS, false); 281 282 return; 283 284 error: 285 isc__nm_failed_connect_cb(sock, req, result, false); 286 } 287 288 void 289 isc_nm_tcpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, 290 isc_nm_cb_t cb, void *cbarg, unsigned int timeout, 291 size_t extrahandlesize) { 292 isc_result_t result = ISC_R_SUCCESS; 293 isc_nmsocket_t *sock = NULL; 294 isc__netievent_tcpconnect_t *ievent = NULL; 295 isc__nm_uvreq_t *req = NULL; 296 sa_family_t sa_family; 297 298 REQUIRE(VALID_NM(mgr)); 299 REQUIRE(local != NULL); 300 REQUIRE(peer != NULL); 301 302 sa_family = peer->type.sa.sa_family; 303 304 sock = isc_mem_get(mgr->mctx, sizeof(*sock)); 305 isc__nmsocket_init(sock, mgr, isc_nm_tcpsocket, local); 306 307 sock->extrahandlesize = extrahandlesize; 308 sock->connect_timeout = timeout; 309 sock->result = ISC_R_UNSET; 310 sock->fd = (uv_os_sock_t)-1; 311 atomic_init(&sock->client, true); 312 313 req = isc__nm_uvreq_get(mgr, sock); 314 req->cb.connect = cb; 315 req->cbarg = cbarg; 316 req->peer = *peer; 317 req->local = *local; 318 req->handle = isc__nmhandle_get(sock, &req->peer, &sock->iface); 319 320 result = isc__nm_socket(sa_family, SOCK_STREAM, 0, &sock->fd); 321 if (result != ISC_R_SUCCESS) { 322 if (isc__nm_in_netthread()) { 323 sock->tid = isc_nm_tid(); 324 isc__nmsocket_clearcb(sock); 325 isc__nm_connectcb(sock, req, result, false); 326 } else { 327 isc__nmsocket_clearcb(sock); 328 sock->tid = isc_random_uniform(mgr->nlisteners); 329 isc__nm_connectcb(sock, req, result, true); 330 } 331 atomic_store(&sock->closed, true); 332 isc__nmsocket_detach(&sock); 333 return; 334 } 335 336 ievent = isc__nm_get_netievent_tcpconnect(mgr, sock, req); 337 338 if (isc__nm_in_netthread()) { 339 atomic_store(&sock->active, true); 340 sock->tid = isc_nm_tid(); 341 isc__nm_async_tcpconnect(&mgr->workers[sock->tid], 342 (isc__netievent_t *)ievent); 343 isc__nm_put_netievent_tcpconnect(mgr, ievent); 344 } else { 345 atomic_init(&sock->active, false); 346 sock->tid = isc_random_uniform(mgr->nlisteners); 347 isc__nm_enqueue_ievent(&mgr->workers[sock->tid], 348 (isc__netievent_t *)ievent); 349 } 350 LOCK(&sock->lock); 351 while (sock->result == ISC_R_UNSET) { 352 WAIT(&sock->cond, &sock->lock); 353 } 354 atomic_store(&sock->active, true); 355 BROADCAST(&sock->scond); 356 UNLOCK(&sock->lock); 357 } 358 359 static uv_os_sock_t 360 isc__nm_tcp_lb_socket(isc_nm_t *mgr, sa_family_t sa_family) { 361 isc_result_t result; 362 uv_os_sock_t sock; 363 364 result = isc__nm_socket(sa_family, SOCK_STREAM, 0, &sock); 365 RUNTIME_CHECK(result == ISC_R_SUCCESS); 366 367 (void)isc__nm_socket_incoming_cpu(sock); 368 369 /* FIXME: set mss */ 370 371 result = isc__nm_socket_reuse(sock); 372 RUNTIME_CHECK(result == ISC_R_SUCCESS); 373 374 #ifndef _WIN32 375 if (mgr->load_balance_sockets) { 376 result = isc__nm_socket_reuse_lb(sock); 377 RUNTIME_CHECK(result == ISC_R_SUCCESS); 378 } 379 #endif 380 381 return (sock); 382 } 383 384 static void 385 start_tcp_child(isc_nm_t *mgr, isc_sockaddr_t *iface, isc_nmsocket_t *sock, 386 uv_os_sock_t fd, int tid) { 387 isc__netievent_tcplisten_t *ievent = NULL; 388 isc_nmsocket_t *csock = &sock->children[tid]; 389 390 isc__nmsocket_init(csock, mgr, isc_nm_tcpsocket, iface); 391 csock->parent = sock; 392 csock->accept_cb = sock->accept_cb; 393 csock->accept_cbarg = sock->accept_cbarg; 394 csock->extrahandlesize = sock->extrahandlesize; 395 csock->backlog = sock->backlog; 396 csock->tid = tid; 397 /* 398 * We don't attach to quota, just assign - to avoid 399 * increasing quota unnecessarily. 400 */ 401 csock->pquota = sock->pquota; 402 isc_quota_cb_init(&csock->quotacb, quota_accept_cb, csock); 403 404 #ifdef _WIN32 405 UNUSED(fd); 406 csock->fd = isc__nm_tcp_lb_socket(mgr, iface->type.sa.sa_family); 407 #else 408 if (mgr->load_balance_sockets) { 409 UNUSED(fd); 410 csock->fd = isc__nm_tcp_lb_socket(mgr, 411 iface->type.sa.sa_family); 412 } else { 413 csock->fd = dup(fd); 414 } 415 #endif 416 REQUIRE(csock->fd >= 0); 417 418 ievent = isc__nm_get_netievent_tcplisten(mgr, csock); 419 isc__nm_maybe_enqueue_ievent(&mgr->workers[tid], 420 (isc__netievent_t *)ievent); 421 } 422 423 static void 424 enqueue_stoplistening(isc_nmsocket_t *sock) { 425 isc__netievent_tcpstop_t *ievent = 426 isc__nm_get_netievent_tcpstop(sock->mgr, sock); 427 isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], 428 (isc__netievent_t *)ievent); 429 } 430 431 isc_result_t 432 isc_nm_listentcp(isc_nm_t *mgr, isc_sockaddr_t *iface, 433 isc_nm_accept_cb_t accept_cb, void *accept_cbarg, 434 size_t extrahandlesize, int backlog, isc_quota_t *quota, 435 isc_nmsocket_t **sockp) { 436 isc_result_t result = ISC_R_SUCCESS; 437 isc_nmsocket_t *sock = NULL; 438 size_t children_size = 0; 439 uv_os_sock_t fd = -1; 440 441 REQUIRE(VALID_NM(mgr)); 442 443 sock = isc_mem_get(mgr->mctx, sizeof(*sock)); 444 isc__nmsocket_init(sock, mgr, isc_nm_tcplistener, iface); 445 446 atomic_init(&sock->rchildren, 0); 447 #if defined(WIN32) 448 sock->nchildren = 1; 449 #else 450 sock->nchildren = mgr->nlisteners; 451 #endif 452 children_size = sock->nchildren * sizeof(sock->children[0]); 453 sock->children = isc_mem_get(mgr->mctx, children_size); 454 memset(sock->children, 0, children_size); 455 456 sock->result = ISC_R_UNSET; 457 458 sock->accept_cb = accept_cb; 459 sock->accept_cbarg = accept_cbarg; 460 sock->extrahandlesize = extrahandlesize; 461 sock->backlog = backlog; 462 sock->pquota = quota; 463 464 sock->tid = 0; 465 sock->fd = -1; 466 467 #ifndef _WIN32 468 if (!mgr->load_balance_sockets) { 469 fd = isc__nm_tcp_lb_socket(mgr, iface->type.sa.sa_family); 470 } 471 #endif 472 473 isc_barrier_init(&sock->startlistening, sock->nchildren); 474 475 for (size_t i = 0; i < sock->nchildren; i++) { 476 if ((int)i == isc_nm_tid()) { 477 continue; 478 } 479 start_tcp_child(mgr, iface, sock, fd, i); 480 } 481 482 if (isc__nm_in_netthread()) { 483 start_tcp_child(mgr, iface, sock, fd, isc_nm_tid()); 484 } 485 486 #ifndef _WIN32 487 if (!mgr->load_balance_sockets) { 488 isc__nm_closesocket(fd); 489 } 490 #endif 491 492 LOCK(&sock->lock); 493 while (atomic_load(&sock->rchildren) != sock->nchildren) { 494 WAIT(&sock->cond, &sock->lock); 495 } 496 result = sock->result; 497 atomic_store(&sock->active, true); 498 UNLOCK(&sock->lock); 499 500 INSIST(result != ISC_R_UNSET); 501 502 if (result == ISC_R_SUCCESS) { 503 REQUIRE(atomic_load(&sock->rchildren) == sock->nchildren); 504 *sockp = sock; 505 } else { 506 atomic_store(&sock->active, false); 507 enqueue_stoplistening(sock); 508 isc_nmsocket_close(&sock); 509 } 510 511 return (result); 512 } 513 514 void 515 isc__nm_async_tcplisten(isc__networker_t *worker, isc__netievent_t *ev0) { 516 isc__netievent_tcplisten_t *ievent = (isc__netievent_tcplisten_t *)ev0; 517 sa_family_t sa_family; 518 int r; 519 int flags = 0; 520 isc_nmsocket_t *sock = NULL; 521 isc_result_t result; 522 isc_nm_t *mgr; 523 524 REQUIRE(VALID_NMSOCK(ievent->sock)); 525 REQUIRE(ievent->sock->tid == isc_nm_tid()); 526 REQUIRE(VALID_NMSOCK(ievent->sock->parent)); 527 528 sock = ievent->sock; 529 sa_family = sock->iface.type.sa.sa_family; 530 mgr = sock->mgr; 531 532 REQUIRE(sock->type == isc_nm_tcpsocket); 533 REQUIRE(sock->parent != NULL); 534 REQUIRE(sock->tid == isc_nm_tid()); 535 536 /* TODO: set min mss */ 537 538 r = uv_tcp_init(&worker->loop, &sock->uv_handle.tcp); 539 UV_RUNTIME_CHECK(uv_tcp_init, r); 540 541 uv_handle_set_data(&sock->uv_handle.handle, sock); 542 /* This keeps the socket alive after everything else is gone */ 543 isc__nmsocket_attach(sock, &(isc_nmsocket_t *){ NULL }); 544 545 r = uv_timer_init(&worker->loop, &sock->read_timer); 546 UV_RUNTIME_CHECK(uv_timer_init, r); 547 uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock); 548 549 LOCK(&sock->parent->lock); 550 551 r = uv_tcp_open(&sock->uv_handle.tcp, sock->fd); 552 if (r < 0) { 553 isc__nm_closesocket(sock->fd); 554 isc__nm_incstats(sock->mgr, sock->statsindex[STATID_OPENFAIL]); 555 goto done; 556 } 557 isc__nm_incstats(sock->mgr, sock->statsindex[STATID_OPEN]); 558 559 if (sa_family == AF_INET6) { 560 flags = UV_TCP_IPV6ONLY; 561 } 562 563 #ifdef _WIN32 564 r = isc_uv_tcp_freebind(&sock->uv_handle.tcp, &sock->iface.type.sa, 565 flags); 566 if (r < 0) { 567 isc__nm_incstats(sock->mgr, sock->statsindex[STATID_BINDFAIL]); 568 goto done; 569 } 570 #else 571 if (mgr->load_balance_sockets) { 572 r = isc_uv_tcp_freebind(&sock->uv_handle.tcp, 573 &sock->iface.type.sa, flags); 574 if (r < 0) { 575 isc__nm_incstats(sock->mgr, 576 sock->statsindex[STATID_BINDFAIL]); 577 goto done; 578 } 579 } else { 580 if (sock->parent->fd == -1) { 581 r = isc_uv_tcp_freebind(&sock->uv_handle.tcp, 582 &sock->iface.type.sa, flags); 583 if (r < 0) { 584 isc__nm_incstats(sock->mgr, STATID_BINDFAIL); 585 goto done; 586 } 587 sock->parent->uv_handle.tcp.flags = 588 sock->uv_handle.tcp.flags; 589 sock->parent->fd = sock->fd; 590 } else { 591 /* The socket is already bound, just copy the flags */ 592 sock->uv_handle.tcp.flags = 593 sock->parent->uv_handle.tcp.flags; 594 } 595 } 596 #endif 597 598 /* 599 * The callback will run in the same thread uv_listen() was called 600 * from, so a race with tcp_connection_cb() isn't possible. 601 */ 602 r = uv_listen((uv_stream_t *)&sock->uv_handle.tcp, sock->backlog, 603 tcp_connection_cb); 604 if (r != 0) { 605 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 606 ISC_LOGMODULE_NETMGR, ISC_LOG_ERROR, 607 "uv_listen failed: %s", 608 isc_result_totext(isc__nm_uverr2result(r))); 609 isc__nm_incstats(sock->mgr, sock->statsindex[STATID_BINDFAIL]); 610 goto done; 611 } 612 613 atomic_store(&sock->listening, true); 614 615 done: 616 result = isc__nm_uverr2result(r); 617 if (result != ISC_R_SUCCESS) { 618 sock->pquota = NULL; 619 } 620 621 atomic_fetch_add(&sock->parent->rchildren, 1); 622 if (sock->parent->result == ISC_R_UNSET) { 623 sock->parent->result = result; 624 } 625 SIGNAL(&sock->parent->cond); 626 UNLOCK(&sock->parent->lock); 627 628 isc_barrier_wait(&sock->parent->startlistening); 629 } 630 631 static void 632 tcp_connection_cb(uv_stream_t *server, int status) { 633 isc_nmsocket_t *ssock = uv_handle_get_data((uv_handle_t *)server); 634 isc_result_t result; 635 isc_quota_t *quota = NULL; 636 637 if (status != 0) { 638 result = isc__nm_uverr2result(status); 639 goto done; 640 } 641 642 REQUIRE(VALID_NMSOCK(ssock)); 643 REQUIRE(ssock->tid == isc_nm_tid()); 644 645 if (isc__nmsocket_closing(ssock)) { 646 result = ISC_R_CANCELED; 647 goto done; 648 } 649 650 if (ssock->pquota != NULL) { 651 result = isc_quota_attach_cb(ssock->pquota, "a, 652 &ssock->quotacb); 653 if (result == ISC_R_QUOTA) { 654 isc__nm_incstats(ssock->mgr, 655 ssock->statsindex[STATID_ACCEPTFAIL]); 656 goto done; 657 } 658 } 659 660 result = accept_connection(ssock, quota); 661 done: 662 isc__nm_accept_connection_log(result, can_log_tcp_quota()); 663 } 664 665 void 666 isc__nm_tcp_stoplistening(isc_nmsocket_t *sock) { 667 REQUIRE(VALID_NMSOCK(sock)); 668 REQUIRE(sock->type == isc_nm_tcplistener); 669 670 if (!atomic_compare_exchange_strong(&sock->closing, &(bool){ false }, 671 true)) 672 { 673 UNREACHABLE(); 674 } 675 676 if (!isc__nm_in_netthread()) { 677 enqueue_stoplistening(sock); 678 } else { 679 stop_tcp_parent(sock); 680 } 681 } 682 683 void 684 isc__nm_async_tcpstop(isc__networker_t *worker, isc__netievent_t *ev0) { 685 isc__netievent_tcpstop_t *ievent = (isc__netievent_tcpstop_t *)ev0; 686 isc_nmsocket_t *sock = ievent->sock; 687 688 UNUSED(worker); 689 690 REQUIRE(VALID_NMSOCK(sock)); 691 REQUIRE(sock->tid == isc_nm_tid()); 692 693 if (sock->parent != NULL) { 694 stop_tcp_child(sock); 695 return; 696 } 697 698 stop_tcp_parent(sock); 699 } 700 701 void 702 isc__nm_tcp_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result) { 703 REQUIRE(VALID_NMSOCK(sock)); 704 REQUIRE(result != ISC_R_SUCCESS); 705 706 isc__nmsocket_timer_stop(sock); 707 isc__nm_stop_reading(sock); 708 709 if (!sock->recv_read) { 710 goto destroy; 711 } 712 sock->recv_read = false; 713 714 if (sock->recv_cb != NULL) { 715 isc__nm_uvreq_t *req = isc__nm_get_read_req(sock, NULL); 716 isc__nmsocket_clearcb(sock); 717 isc__nm_readcb(sock, req, result); 718 } 719 720 destroy: 721 isc__nmsocket_prep_destroy(sock); 722 723 /* 724 * We need to detach from quota after the read callback function had a 725 * chance to be executed. 726 */ 727 if (sock->quota != NULL) { 728 isc_quota_detach(&sock->quota); 729 } 730 } 731 732 void 733 isc__nm_tcp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) { 734 REQUIRE(VALID_NMHANDLE(handle)); 735 REQUIRE(VALID_NMSOCK(handle->sock)); 736 737 isc_nmsocket_t *sock = handle->sock; 738 isc__netievent_tcpstartread_t *ievent = NULL; 739 740 REQUIRE(sock->type == isc_nm_tcpsocket); 741 REQUIRE(sock->statichandle == handle); 742 REQUIRE(sock->tid == isc_nm_tid()); 743 REQUIRE(!sock->recv_read); 744 745 sock->recv_cb = cb; 746 sock->recv_cbarg = cbarg; 747 sock->recv_read = true; 748 if (sock->read_timeout == 0) { 749 sock->read_timeout = 750 (atomic_load(&sock->keepalive) 751 ? atomic_load(&sock->mgr->keepalive) 752 : atomic_load(&sock->mgr->idle)); 753 } 754 755 ievent = isc__nm_get_netievent_tcpstartread(sock->mgr, sock); 756 757 /* 758 * This MUST be done asynchronously, no matter which thread we're 759 * in. The callback function for isc_nm_read() often calls 760 * isc_nm_read() again; if we tried to do that synchronously 761 * we'd clash in processbuffer() and grow the stack indefinitely. 762 */ 763 isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], 764 (isc__netievent_t *)ievent); 765 766 return; 767 } 768 769 void 770 isc__nm_async_tcpstartread(isc__networker_t *worker, isc__netievent_t *ev0) { 771 isc__netievent_tcpstartread_t *ievent = 772 (isc__netievent_tcpstartread_t *)ev0; 773 isc_nmsocket_t *sock = ievent->sock; 774 isc_result_t result; 775 776 REQUIRE(VALID_NMSOCK(sock)); 777 REQUIRE(sock->tid == isc_nm_tid()); 778 UNUSED(worker); 779 780 if (isc__nmsocket_closing(sock)) { 781 result = ISC_R_CANCELED; 782 } else { 783 result = isc__nm_start_reading(sock); 784 } 785 786 if (result != ISC_R_SUCCESS) { 787 sock->reading = true; 788 isc__nm_tcp_failed_read_cb(sock, result); 789 return; 790 } 791 792 isc__nmsocket_timer_start(sock); 793 } 794 795 void 796 isc__nm_tcp_pauseread(isc_nmhandle_t *handle) { 797 isc__netievent_tcppauseread_t *ievent = NULL; 798 isc_nmsocket_t *sock = NULL; 799 800 REQUIRE(VALID_NMHANDLE(handle)); 801 802 sock = handle->sock; 803 804 REQUIRE(VALID_NMSOCK(sock)); 805 806 if (!atomic_compare_exchange_strong(&sock->readpaused, &(bool){ false }, 807 true)) 808 { 809 return; 810 } 811 812 ievent = isc__nm_get_netievent_tcppauseread(sock->mgr, sock); 813 814 isc__nm_maybe_enqueue_ievent(&sock->mgr->workers[sock->tid], 815 (isc__netievent_t *)ievent); 816 817 return; 818 } 819 820 void 821 isc__nm_async_tcppauseread(isc__networker_t *worker, isc__netievent_t *ev0) { 822 isc__netievent_tcppauseread_t *ievent = 823 (isc__netievent_tcppauseread_t *)ev0; 824 isc_nmsocket_t *sock = ievent->sock; 825 826 REQUIRE(VALID_NMSOCK(sock)); 827 REQUIRE(sock->tid == isc_nm_tid()); 828 UNUSED(worker); 829 830 isc__nmsocket_timer_stop(sock); 831 isc__nm_stop_reading(sock); 832 } 833 834 void 835 isc__nm_tcp_resumeread(isc_nmhandle_t *handle) { 836 REQUIRE(VALID_NMHANDLE(handle)); 837 REQUIRE(VALID_NMSOCK(handle->sock)); 838 839 isc__netievent_tcpstartread_t *ievent = NULL; 840 isc_nmsocket_t *sock = handle->sock; 841 842 REQUIRE(sock->tid == isc_nm_tid()); 843 844 if (sock->recv_cb == NULL) { 845 /* We are no longer reading */ 846 return; 847 } 848 849 if (!isc__nmsocket_active(sock)) { 850 sock->reading = true; 851 isc__nm_tcp_failed_read_cb(sock, ISC_R_CANCELED); 852 return; 853 } 854 855 if (!atomic_compare_exchange_strong(&sock->readpaused, &(bool){ true }, 856 false)) 857 { 858 return; 859 } 860 861 ievent = isc__nm_get_netievent_tcpstartread(sock->mgr, sock); 862 863 isc__nm_maybe_enqueue_ievent(&sock->mgr->workers[sock->tid], 864 (isc__netievent_t *)ievent); 865 } 866 867 void 868 isc__nm_tcp_read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { 869 isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)stream); 870 isc__nm_uvreq_t *req = NULL; 871 872 REQUIRE(VALID_NMSOCK(sock)); 873 REQUIRE(sock->tid == isc_nm_tid()); 874 REQUIRE(sock->reading); 875 REQUIRE(buf != NULL); 876 877 if (isc__nmsocket_closing(sock)) { 878 isc__nm_tcp_failed_read_cb(sock, ISC_R_CANCELED); 879 goto free; 880 } 881 882 if (nread < 0) { 883 if (nread != UV_EOF) { 884 isc__nm_incstats(sock->mgr, 885 sock->statsindex[STATID_RECVFAIL]); 886 } 887 888 isc__nm_tcp_failed_read_cb(sock, isc__nm_uverr2result(nread)); 889 890 goto free; 891 } 892 893 req = isc__nm_get_read_req(sock, NULL); 894 895 /* 896 * The callback will be called synchronously because the 897 * result is ISC_R_SUCCESS, so we don't need to retain 898 * the buffer 899 */ 900 req->uvbuf.base = buf->base; 901 req->uvbuf.len = nread; 902 903 if (!atomic_load(&sock->client)) { 904 sock->read_timeout = 905 (atomic_load(&sock->keepalive) 906 ? atomic_load(&sock->mgr->keepalive) 907 : atomic_load(&sock->mgr->idle)); 908 } 909 910 isc__nm_readcb(sock, req, ISC_R_SUCCESS); 911 912 /* The readcb could have paused the reading */ 913 if (sock->reading) { 914 /* The timer will be updated */ 915 isc__nmsocket_timer_restart(sock); 916 } 917 918 free: 919 if (nread < 0) { 920 /* 921 * The buffer may be a null buffer on error. 922 */ 923 if (buf->base == NULL && buf->len == 0) { 924 return; 925 } 926 } 927 928 isc__nm_free_uvbuf(sock, buf); 929 } 930 931 static void 932 quota_accept_cb(isc_quota_t *quota, void *sock0) { 933 isc_nmsocket_t *sock = (isc_nmsocket_t *)sock0; 934 isc__netievent_tcpaccept_t *ievent = NULL; 935 936 REQUIRE(VALID_NMSOCK(sock)); 937 938 /* 939 * Create a tcpaccept event and pass it using the async channel. 940 */ 941 ievent = isc__nm_get_netievent_tcpaccept(sock->mgr, sock, quota); 942 isc__nm_maybe_enqueue_ievent(&sock->mgr->workers[sock->tid], 943 (isc__netievent_t *)ievent); 944 } 945 946 /* 947 * This is called after we get a quota_accept_cb() callback. 948 */ 949 void 950 isc__nm_async_tcpaccept(isc__networker_t *worker, isc__netievent_t *ev0) { 951 isc__netievent_tcpaccept_t *ievent = (isc__netievent_tcpaccept_t *)ev0; 952 isc_nmsocket_t *sock = ievent->sock; 953 isc_result_t result; 954 955 UNUSED(worker); 956 957 REQUIRE(VALID_NMSOCK(sock)); 958 REQUIRE(sock->tid == isc_nm_tid()); 959 960 result = accept_connection(sock, ievent->quota); 961 isc__nm_accept_connection_log(result, can_log_tcp_quota()); 962 } 963 964 static isc_result_t 965 accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) { 966 isc_nmsocket_t *csock = NULL; 967 isc__networker_t *worker = NULL; 968 int r; 969 isc_result_t result; 970 struct sockaddr_storage ss; 971 isc_sockaddr_t local; 972 isc_nmhandle_t *handle = NULL; 973 974 REQUIRE(VALID_NMSOCK(ssock)); 975 REQUIRE(ssock->tid == isc_nm_tid()); 976 977 if (isc__nmsocket_closing(ssock)) { 978 if (quota != NULL) { 979 isc_quota_detach("a); 980 } 981 return (ISC_R_CANCELED); 982 } 983 984 csock = isc_mem_get(ssock->mgr->mctx, sizeof(isc_nmsocket_t)); 985 isc__nmsocket_init(csock, ssock->mgr, isc_nm_tcpsocket, &ssock->iface); 986 csock->tid = ssock->tid; 987 csock->extrahandlesize = ssock->extrahandlesize; 988 isc__nmsocket_attach(ssock, &csock->server); 989 csock->recv_cb = ssock->recv_cb; 990 csock->recv_cbarg = ssock->recv_cbarg; 991 csock->quota = quota; 992 csock->accepting = true; 993 994 worker = &csock->mgr->workers[isc_nm_tid()]; 995 996 r = uv_tcp_init(&worker->loop, &csock->uv_handle.tcp); 997 UV_RUNTIME_CHECK(uv_tcp_init, r); 998 uv_handle_set_data(&csock->uv_handle.handle, csock); 999 1000 r = uv_timer_init(&worker->loop, &csock->read_timer); 1001 UV_RUNTIME_CHECK(uv_timer_init, r); 1002 uv_handle_set_data((uv_handle_t *)&csock->read_timer, csock); 1003 1004 r = uv_accept(&ssock->uv_handle.stream, &csock->uv_handle.stream); 1005 if (r != 0) { 1006 result = isc__nm_uverr2result(r); 1007 goto failure; 1008 } 1009 1010 r = uv_tcp_getpeername(&csock->uv_handle.tcp, (struct sockaddr *)&ss, 1011 &(int){ sizeof(ss) }); 1012 if (r != 0) { 1013 result = isc__nm_uverr2result(r); 1014 goto failure; 1015 } 1016 1017 result = isc_sockaddr_fromsockaddr(&csock->peer, 1018 (struct sockaddr *)&ss); 1019 if (result != ISC_R_SUCCESS) { 1020 goto failure; 1021 } 1022 1023 r = uv_tcp_getsockname(&csock->uv_handle.tcp, (struct sockaddr *)&ss, 1024 &(int){ sizeof(ss) }); 1025 if (r != 0) { 1026 result = isc__nm_uverr2result(r); 1027 goto failure; 1028 } 1029 1030 result = isc_sockaddr_fromsockaddr(&local, (struct sockaddr *)&ss); 1031 if (result != ISC_R_SUCCESS) { 1032 goto failure; 1033 } 1034 1035 handle = isc__nmhandle_get(csock, NULL, &local); 1036 1037 result = ssock->accept_cb(handle, ISC_R_SUCCESS, ssock->accept_cbarg); 1038 if (result != ISC_R_SUCCESS) { 1039 isc_nmhandle_detach(&handle); 1040 goto failure; 1041 } 1042 1043 csock->accepting = false; 1044 1045 isc__nm_incstats(csock->mgr, csock->statsindex[STATID_ACCEPT]); 1046 1047 csock->read_timeout = atomic_load(&csock->mgr->init); 1048 1049 atomic_fetch_add(&ssock->parent->active_child_connections, 1); 1050 1051 /* 1052 * The acceptcb needs to attach to the handle if it wants to keep the 1053 * connection alive 1054 */ 1055 isc_nmhandle_detach(&handle); 1056 1057 /* 1058 * sock is now attached to the handle. 1059 */ 1060 isc__nmsocket_detach(&csock); 1061 1062 return (ISC_R_SUCCESS); 1063 1064 failure: 1065 atomic_store(&csock->active, false); 1066 1067 failed_accept_cb(csock, result); 1068 1069 isc__nmsocket_prep_destroy(csock); 1070 1071 isc__nmsocket_detach(&csock); 1072 1073 return (result); 1074 } 1075 1076 void 1077 isc__nm_tcp_send(isc_nmhandle_t *handle, const isc_region_t *region, 1078 isc_nm_cb_t cb, void *cbarg) { 1079 REQUIRE(VALID_NMHANDLE(handle)); 1080 REQUIRE(VALID_NMSOCK(handle->sock)); 1081 1082 isc_nmsocket_t *sock = handle->sock; 1083 isc__netievent_tcpsend_t *ievent = NULL; 1084 isc__nm_uvreq_t *uvreq = NULL; 1085 1086 REQUIRE(sock->type == isc_nm_tcpsocket); 1087 1088 uvreq = isc__nm_uvreq_get(sock->mgr, sock); 1089 uvreq->uvbuf.base = (char *)region->base; 1090 uvreq->uvbuf.len = region->length; 1091 1092 isc_nmhandle_attach(handle, &uvreq->handle); 1093 1094 uvreq->cb.send = cb; 1095 uvreq->cbarg = cbarg; 1096 1097 ievent = isc__nm_get_netievent_tcpsend(sock->mgr, sock, uvreq); 1098 isc__nm_maybe_enqueue_ievent(&sock->mgr->workers[sock->tid], 1099 (isc__netievent_t *)ievent); 1100 1101 return; 1102 } 1103 1104 static void 1105 tcp_send_cb(uv_write_t *req, int status) { 1106 isc__nm_uvreq_t *uvreq = (isc__nm_uvreq_t *)req->data; 1107 isc_nmsocket_t *sock = NULL; 1108 1109 REQUIRE(VALID_UVREQ(uvreq)); 1110 REQUIRE(VALID_NMSOCK(uvreq->sock)); 1111 1112 sock = uvreq->sock; 1113 1114 isc_nm_timer_stop(uvreq->timer); 1115 isc_nm_timer_detach(&uvreq->timer); 1116 1117 if (status < 0) { 1118 isc__nm_incstats(sock->mgr, sock->statsindex[STATID_SENDFAIL]); 1119 isc__nm_failed_send_cb(sock, uvreq, 1120 isc__nm_uverr2result(status)); 1121 return; 1122 } 1123 1124 isc__nm_sendcb(sock, uvreq, ISC_R_SUCCESS, false); 1125 } 1126 1127 /* 1128 * Handle 'tcpsend' async event - send a packet on the socket 1129 */ 1130 void 1131 isc__nm_async_tcpsend(isc__networker_t *worker, isc__netievent_t *ev0) { 1132 isc_result_t result; 1133 isc__netievent_tcpsend_t *ievent = (isc__netievent_tcpsend_t *)ev0; 1134 isc_nmsocket_t *sock = ievent->sock; 1135 isc__nm_uvreq_t *uvreq = ievent->req; 1136 1137 REQUIRE(sock->type == isc_nm_tcpsocket); 1138 REQUIRE(sock->tid == isc_nm_tid()); 1139 UNUSED(worker); 1140 1141 if (sock->write_timeout == 0) { 1142 sock->write_timeout = 1143 (atomic_load(&sock->keepalive) 1144 ? atomic_load(&sock->mgr->keepalive) 1145 : atomic_load(&sock->mgr->idle)); 1146 } 1147 1148 result = tcp_send_direct(sock, uvreq); 1149 if (result != ISC_R_SUCCESS) { 1150 isc__nm_incstats(sock->mgr, sock->statsindex[STATID_SENDFAIL]); 1151 isc__nm_failed_send_cb(sock, uvreq, result); 1152 } 1153 } 1154 1155 static isc_result_t 1156 tcp_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { 1157 REQUIRE(VALID_NMSOCK(sock)); 1158 REQUIRE(VALID_UVREQ(req)); 1159 REQUIRE(sock->tid == isc_nm_tid()); 1160 REQUIRE(sock->type == isc_nm_tcpsocket); 1161 1162 int r; 1163 1164 if (isc__nmsocket_closing(sock)) { 1165 return (ISC_R_CANCELED); 1166 } 1167 1168 r = uv_write(&req->uv_req.write, &sock->uv_handle.stream, &req->uvbuf, 1169 1, tcp_send_cb); 1170 if (r < 0) { 1171 return (isc__nm_uverr2result(r)); 1172 } 1173 1174 isc_nm_timer_create(req->handle, isc__nmsocket_writetimeout_cb, req, 1175 &req->timer); 1176 if (sock->write_timeout > 0) { 1177 isc_nm_timer_start(req->timer, sock->write_timeout); 1178 } 1179 1180 return (ISC_R_SUCCESS); 1181 } 1182 1183 static void 1184 tcp_stop_cb(uv_handle_t *handle) { 1185 isc_nmsocket_t *sock = uv_handle_get_data(handle); 1186 uv_handle_set_data(handle, NULL); 1187 1188 REQUIRE(VALID_NMSOCK(sock)); 1189 REQUIRE(sock->tid == isc_nm_tid()); 1190 REQUIRE(atomic_load(&sock->closing)); 1191 1192 if (!atomic_compare_exchange_strong(&sock->closed, &(bool){ false }, 1193 true)) 1194 { 1195 UNREACHABLE(); 1196 } 1197 1198 isc__nm_incstats(sock->mgr, sock->statsindex[STATID_CLOSE]); 1199 1200 atomic_store(&sock->listening, false); 1201 1202 isc__nmsocket_detach(&sock); 1203 } 1204 1205 static void 1206 tcp_close_sock(isc_nmsocket_t *sock) { 1207 REQUIRE(VALID_NMSOCK(sock)); 1208 REQUIRE(sock->tid == isc_nm_tid()); 1209 REQUIRE(atomic_load(&sock->closing)); 1210 1211 if (!atomic_compare_exchange_strong(&sock->closed, &(bool){ false }, 1212 true)) 1213 { 1214 UNREACHABLE(); 1215 } 1216 1217 isc__nm_incstats(sock->mgr, sock->statsindex[STATID_CLOSE]); 1218 1219 if (sock->server != NULL) { 1220 isc__nmsocket_detach(&sock->server); 1221 } 1222 1223 atomic_store(&sock->connected, false); 1224 1225 isc__nmsocket_prep_destroy(sock); 1226 } 1227 1228 static void 1229 tcp_close_cb(uv_handle_t *handle) { 1230 isc_nmsocket_t *sock = uv_handle_get_data(handle); 1231 uv_handle_set_data(handle, NULL); 1232 1233 tcp_close_sock(sock); 1234 } 1235 1236 static void 1237 read_timer_close_cb(uv_handle_t *handle) { 1238 isc_nmsocket_t *sock = uv_handle_get_data(handle); 1239 uv_handle_set_data(handle, NULL); 1240 1241 if (sock->parent) { 1242 uv_close(&sock->uv_handle.handle, tcp_stop_cb); 1243 } else if (uv_is_closing(&sock->uv_handle.handle)) { 1244 tcp_close_sock(sock); 1245 } else { 1246 uv_close(&sock->uv_handle.handle, tcp_close_cb); 1247 } 1248 } 1249 1250 static void 1251 stop_tcp_child(isc_nmsocket_t *sock) { 1252 REQUIRE(sock->type == isc_nm_tcpsocket); 1253 REQUIRE(sock->tid == isc_nm_tid()); 1254 1255 if (!atomic_compare_exchange_strong(&sock->closing, &(bool){ false }, 1256 true)) 1257 { 1258 return; 1259 } 1260 1261 tcp_close_direct(sock); 1262 1263 atomic_fetch_sub(&sock->parent->rchildren, 1); 1264 1265 isc_barrier_wait(&sock->parent->stoplistening); 1266 } 1267 1268 static void 1269 stop_tcp_parent(isc_nmsocket_t *sock) { 1270 isc_nmsocket_t *csock = NULL; 1271 1272 REQUIRE(VALID_NMSOCK(sock)); 1273 REQUIRE(sock->tid == isc_nm_tid()); 1274 REQUIRE(sock->type == isc_nm_tcplistener); 1275 1276 isc_barrier_init(&sock->stoplistening, sock->nchildren); 1277 1278 for (size_t i = 0; i < sock->nchildren; i++) { 1279 csock = &sock->children[i]; 1280 REQUIRE(VALID_NMSOCK(csock)); 1281 1282 if ((int)i == isc_nm_tid()) { 1283 /* 1284 * We need to schedule closing the other sockets first 1285 */ 1286 continue; 1287 } 1288 1289 atomic_store(&csock->active, false); 1290 enqueue_stoplistening(csock); 1291 } 1292 1293 csock = &sock->children[isc_nm_tid()]; 1294 atomic_store(&csock->active, false); 1295 stop_tcp_child(csock); 1296 1297 atomic_store(&sock->closed, true); 1298 isc__nmsocket_prep_destroy(sock); 1299 } 1300 1301 static void 1302 tcp_close_direct(isc_nmsocket_t *sock) { 1303 REQUIRE(VALID_NMSOCK(sock)); 1304 REQUIRE(sock->tid == isc_nm_tid()); 1305 REQUIRE(atomic_load(&sock->closing)); 1306 1307 if (sock->server != NULL) { 1308 REQUIRE(VALID_NMSOCK(sock->server)); 1309 REQUIRE(VALID_NMSOCK(sock->server->parent)); 1310 if (sock->server->parent != NULL) { 1311 atomic_fetch_sub( 1312 &sock->server->parent->active_child_connections, 1313 1); 1314 } 1315 } 1316 1317 if (sock->quota != NULL) { 1318 isc_quota_detach(&sock->quota); 1319 } 1320 1321 isc__nmsocket_timer_stop(sock); 1322 isc__nm_stop_reading(sock); 1323 1324 uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock); 1325 uv_close((uv_handle_t *)&sock->read_timer, read_timer_close_cb); 1326 } 1327 1328 void 1329 isc__nm_tcp_close(isc_nmsocket_t *sock) { 1330 REQUIRE(VALID_NMSOCK(sock)); 1331 REQUIRE(sock->type == isc_nm_tcpsocket); 1332 REQUIRE(!isc__nmsocket_active(sock)); 1333 1334 if (!atomic_compare_exchange_strong(&sock->closing, &(bool){ false }, 1335 true)) 1336 { 1337 return; 1338 } 1339 1340 if (sock->tid == isc_nm_tid()) { 1341 tcp_close_direct(sock); 1342 } else { 1343 /* 1344 * We need to create an event and pass it using async channel 1345 */ 1346 isc__netievent_tcpclose_t *ievent = 1347 isc__nm_get_netievent_tcpclose(sock->mgr, sock); 1348 1349 isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], 1350 (isc__netievent_t *)ievent); 1351 } 1352 } 1353 1354 void 1355 isc__nm_async_tcpclose(isc__networker_t *worker, isc__netievent_t *ev0) { 1356 isc__netievent_tcpclose_t *ievent = (isc__netievent_tcpclose_t *)ev0; 1357 isc_nmsocket_t *sock = ievent->sock; 1358 1359 REQUIRE(VALID_NMSOCK(sock)); 1360 REQUIRE(sock->tid == isc_nm_tid()); 1361 1362 UNUSED(worker); 1363 1364 tcp_close_direct(sock); 1365 } 1366 1367 static void 1368 tcp_close_connect_cb(uv_handle_t *handle) { 1369 isc_nmsocket_t *sock = uv_handle_get_data(handle); 1370 1371 REQUIRE(VALID_NMSOCK(sock)); 1372 1373 REQUIRE(isc__nm_in_netthread()); 1374 REQUIRE(sock->tid == isc_nm_tid()); 1375 1376 isc__nmsocket_prep_destroy(sock); 1377 isc__nmsocket_detach(&sock); 1378 } 1379 1380 void 1381 isc__nm_tcp_shutdown(isc_nmsocket_t *sock) { 1382 REQUIRE(VALID_NMSOCK(sock)); 1383 REQUIRE(sock->tid == isc_nm_tid()); 1384 REQUIRE(sock->type == isc_nm_tcpsocket); 1385 1386 /* 1387 * If the socket is active, mark it inactive and 1388 * continue. If it isn't active, stop now. 1389 */ 1390 if (!isc__nmsocket_deactivate(sock)) { 1391 return; 1392 } 1393 1394 if (sock->accepting) { 1395 return; 1396 } 1397 1398 if (atomic_load(&sock->connecting)) { 1399 isc_nmsocket_t *tsock = NULL; 1400 isc__nmsocket_attach(sock, &tsock); 1401 uv_close(&sock->uv_handle.handle, tcp_close_connect_cb); 1402 return; 1403 } 1404 1405 if (sock->statichandle != NULL) { 1406 isc__nm_tcp_failed_read_cb(sock, ISC_R_CANCELED); 1407 return; 1408 } 1409 1410 /* 1411 * Otherwise, we just send the socket to abyss... 1412 */ 1413 if (sock->parent == NULL) { 1414 isc__nmsocket_prep_destroy(sock); 1415 } 1416 } 1417 1418 void 1419 isc__nm_tcp_cancelread(isc_nmhandle_t *handle) { 1420 isc_nmsocket_t *sock = NULL; 1421 isc__netievent_tcpcancel_t *ievent = NULL; 1422 1423 REQUIRE(VALID_NMHANDLE(handle)); 1424 1425 sock = handle->sock; 1426 1427 REQUIRE(VALID_NMSOCK(sock)); 1428 REQUIRE(sock->type == isc_nm_tcpsocket); 1429 1430 ievent = isc__nm_get_netievent_tcpcancel(sock->mgr, sock, handle); 1431 isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], 1432 (isc__netievent_t *)ievent); 1433 } 1434 1435 void 1436 isc__nm_async_tcpcancel(isc__networker_t *worker, isc__netievent_t *ev0) { 1437 isc__netievent_tcpcancel_t *ievent = (isc__netievent_tcpcancel_t *)ev0; 1438 isc_nmsocket_t *sock = ievent->sock; 1439 1440 REQUIRE(VALID_NMSOCK(sock)); 1441 REQUIRE(sock->tid == isc_nm_tid()); 1442 UNUSED(worker); 1443 1444 uv_timer_stop(&sock->read_timer); 1445 1446 isc__nm_tcp_failed_read_cb(sock, ISC_R_EOF); 1447 } 1448 1449 int_fast32_t 1450 isc__nm_tcp_listener_nactive(isc_nmsocket_t *listener) { 1451 int_fast32_t nactive; 1452 1453 REQUIRE(VALID_NMSOCK(listener)); 1454 1455 nactive = atomic_load(&listener->active_child_connections); 1456 INSIST(nactive >= 0); 1457 return (nactive); 1458 } 1459