1 /* $NetBSD: netmgr.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 <inttypes.h> 17 #include <unistd.h> 18 #include <uv.h> 19 #ifdef HAVE_LIBCTRACE 20 #include <execinfo.h> 21 #endif /* ifdef HAVE_LIBCTRACE */ 22 23 #include <isc/atomic.h> 24 #include <isc/barrier.h> 25 #include <isc/buffer.h> 26 #include <isc/condition.h> 27 #include <isc/errno.h> 28 #include <isc/list.h> 29 #include <isc/log.h> 30 #include <isc/magic.h> 31 #include <isc/mem.h> 32 #include <isc/netmgr.h> 33 #include <isc/print.h> 34 #include <isc/quota.h> 35 #include <isc/random.h> 36 #include <isc/refcount.h> 37 #include <isc/region.h> 38 #include <isc/result.h> 39 #include <isc/sockaddr.h> 40 #include <isc/stats.h> 41 #include <isc/strerr.h> 42 #include <isc/task.h> 43 #include <isc/thread.h> 44 #include <isc/util.h> 45 46 #include "netmgr-int.h" 47 #include "netmgr_p.h" 48 #include "openssl_shim.h" 49 #include "trampoline_p.h" 50 #include "uv-compat.h" 51 52 /*% 53 * How many isc_nmhandles and isc_nm_uvreqs will we be 54 * caching for reuse in a socket. 55 */ 56 #define ISC_NM_HANDLES_STACK_SIZE 600 57 #define ISC_NM_REQS_STACK_SIZE 600 58 59 /*% 60 * Shortcut index arrays to get access to statistics counters. 61 */ 62 63 static const isc_statscounter_t udp4statsindex[] = { 64 isc_sockstatscounter_udp4open, 65 isc_sockstatscounter_udp4openfail, 66 isc_sockstatscounter_udp4close, 67 isc_sockstatscounter_udp4bindfail, 68 isc_sockstatscounter_udp4connectfail, 69 isc_sockstatscounter_udp4connect, 70 -1, 71 -1, 72 isc_sockstatscounter_udp4sendfail, 73 isc_sockstatscounter_udp4recvfail, 74 isc_sockstatscounter_udp4active 75 }; 76 77 static const isc_statscounter_t udp6statsindex[] = { 78 isc_sockstatscounter_udp6open, 79 isc_sockstatscounter_udp6openfail, 80 isc_sockstatscounter_udp6close, 81 isc_sockstatscounter_udp6bindfail, 82 isc_sockstatscounter_udp6connectfail, 83 isc_sockstatscounter_udp6connect, 84 -1, 85 -1, 86 isc_sockstatscounter_udp6sendfail, 87 isc_sockstatscounter_udp6recvfail, 88 isc_sockstatscounter_udp6active 89 }; 90 91 static const isc_statscounter_t tcp4statsindex[] = { 92 isc_sockstatscounter_tcp4open, isc_sockstatscounter_tcp4openfail, 93 isc_sockstatscounter_tcp4close, isc_sockstatscounter_tcp4bindfail, 94 isc_sockstatscounter_tcp4connectfail, isc_sockstatscounter_tcp4connect, 95 isc_sockstatscounter_tcp4acceptfail, isc_sockstatscounter_tcp4accept, 96 isc_sockstatscounter_tcp4sendfail, isc_sockstatscounter_tcp4recvfail, 97 isc_sockstatscounter_tcp4active 98 }; 99 100 static const isc_statscounter_t tcp6statsindex[] = { 101 isc_sockstatscounter_tcp6open, isc_sockstatscounter_tcp6openfail, 102 isc_sockstatscounter_tcp6close, isc_sockstatscounter_tcp6bindfail, 103 isc_sockstatscounter_tcp6connectfail, isc_sockstatscounter_tcp6connect, 104 isc_sockstatscounter_tcp6acceptfail, isc_sockstatscounter_tcp6accept, 105 isc_sockstatscounter_tcp6sendfail, isc_sockstatscounter_tcp6recvfail, 106 isc_sockstatscounter_tcp6active 107 }; 108 109 #if 0 110 /* XXX: not currently used */ 111 static const isc_statscounter_t unixstatsindex[] = { 112 isc_sockstatscounter_unixopen, 113 isc_sockstatscounter_unixopenfail, 114 isc_sockstatscounter_unixclose, 115 isc_sockstatscounter_unixbindfail, 116 isc_sockstatscounter_unixconnectfail, 117 isc_sockstatscounter_unixconnect, 118 isc_sockstatscounter_unixacceptfail, 119 isc_sockstatscounter_unixaccept, 120 isc_sockstatscounter_unixsendfail, 121 isc_sockstatscounter_unixrecvfail, 122 isc_sockstatscounter_unixactive 123 }; 124 #endif /* if 0 */ 125 126 /* 127 * libuv is not thread safe, but has mechanisms to pass messages 128 * between threads. Each socket is owned by a thread. For UDP 129 * sockets we have a set of sockets for each interface and we can 130 * choose a sibling and send the message directly. For TCP, or if 131 * we're calling from a non-networking thread, we need to pass the 132 * request using async_cb. 133 */ 134 135 #if defined(HAVE_THREAD_LOCAL) 136 #include <threads.h> 137 static thread_local int isc__nm_tid_v = ISC_NETMGR_TID_UNKNOWN; 138 #elif defined(HAVE___THREAD) 139 static __thread int isc__nm_tid_v = ISC_NETMGR_TID_UNKNOWN; 140 #elif HAVE___DECLSPEC_THREAD 141 __declspec(thread) int isc__nm_tid_v = ISC_NETMGR_TID_UNKNOWN; 142 #endif /* if defined(HAVE_THREAD_LOCAL) */ 143 144 static void 145 nmsocket_maybe_destroy(isc_nmsocket_t *sock FLARG); 146 static void 147 nmhandle_free(isc_nmsocket_t *sock, isc_nmhandle_t *handle); 148 static isc_threadresult_t 149 nm_thread(isc_threadarg_t worker0); 150 static void 151 async_cb(uv_async_t *handle); 152 153 static bool 154 process_netievent(isc__networker_t *worker, isc__netievent_t *ievent); 155 static isc_result_t 156 process_queue(isc__networker_t *worker, netievent_type_t type); 157 static void 158 wait_for_priority_queue(isc__networker_t *worker); 159 static void 160 drain_queue(isc__networker_t *worker, netievent_type_t type); 161 162 static void 163 isc__nm_async_stop(isc__networker_t *worker, isc__netievent_t *ev0); 164 static void 165 isc__nm_async_pause(isc__networker_t *worker, isc__netievent_t *ev0); 166 static void 167 isc__nm_async_resume(isc__networker_t *worker, isc__netievent_t *ev0); 168 static void 169 isc__nm_async_detach(isc__networker_t *worker, isc__netievent_t *ev0); 170 static void 171 isc__nm_async_close(isc__networker_t *worker, isc__netievent_t *ev0); 172 173 static void 174 isc__nm_threadpool_initialize(uint32_t workers); 175 static void 176 isc__nm_work_cb(uv_work_t *req); 177 static void 178 isc__nm_after_work_cb(uv_work_t *req, int status); 179 180 void 181 isc__nmsocket_reset(isc_nmsocket_t *sock); 182 183 /*%< 184 * Issue a 'handle closed' callback on the socket. 185 */ 186 187 static void 188 nmhandle_detach_cb(isc_nmhandle_t **handlep FLARG); 189 190 int 191 isc_nm_tid(void) { 192 return (isc__nm_tid_v); 193 } 194 195 bool 196 isc__nm_in_netthread(void) { 197 return (isc__nm_tid_v >= 0); 198 } 199 200 #ifdef WIN32 201 static void 202 isc__nm_winsock_initialize(void) { 203 WORD wVersionRequested = MAKEWORD(2, 2); 204 WSADATA wsaData; 205 int result; 206 207 result = WSAStartup(wVersionRequested, &wsaData); 208 if (result != 0) { 209 char strbuf[ISC_STRERRORSIZE]; 210 strerror_r(result, strbuf, sizeof(strbuf)); 211 UNEXPECTED_ERROR(__FILE__, __LINE__, 212 "WSAStartup() failed with error code %lu: %s", 213 result, strbuf); 214 } 215 216 /* 217 * Confirm that the WinSock DLL supports version 2.2. Note that if the 218 * DLL supports versions greater than 2.2 in addition to 2.2, it will 219 * still return 2.2 in wVersion since that is the version we requested. 220 */ 221 if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) { 222 UNEXPECTED_ERROR(__FILE__, __LINE__, 223 "Unusable WinSock DLL version: %u.%u", 224 LOBYTE(wsaData.wVersion), 225 HIBYTE(wsaData.wVersion)); 226 } 227 } 228 229 static void 230 isc__nm_winsock_destroy(void) { 231 WSACleanup(); 232 } 233 #endif /* WIN32 */ 234 235 static void 236 isc__nm_threadpool_initialize(uint32_t nworkers) { 237 char buf[11]; 238 int r = uv_os_getenv("UV_THREADPOOL_SIZE", buf, 239 &(size_t){ sizeof(buf) }); 240 if (r == UV_ENOENT) { 241 snprintf(buf, sizeof(buf), "%" PRIu32, nworkers); 242 uv_os_setenv("UV_THREADPOOL_SIZE", buf); 243 } 244 } 245 246 #if HAVE_DECL_UV_UDP_MMSG_FREE 247 #define MINIMAL_UV_VERSION UV_VERSION(1, 40, 0) 248 #elif HAVE_DECL_UV_UDP_RECVMMSG 249 #define MAXIMAL_UV_VERSION UV_VERSION(1, 39, 99) 250 #define MINIMAL_UV_VERSION UV_VERSION(1, 37, 0) 251 #elif _WIN32 252 #define MINIMAL_UV_VERSION UV_VERSION(1, 0, 0) 253 #else 254 #define MAXIMAL_UV_VERSION UV_VERSION(1, 34, 99) 255 #define MINIMAL_UV_VERSION UV_VERSION(1, 0, 0) 256 #endif 257 258 void 259 isc__netmgr_create(isc_mem_t *mctx, uint32_t nworkers, isc_nm_t **netmgrp) { 260 isc_nm_t *mgr = NULL; 261 char name[32]; 262 263 REQUIRE(nworkers > 0); 264 265 #ifdef MAXIMAL_UV_VERSION 266 if (uv_version() > MAXIMAL_UV_VERSION) { 267 isc_error_fatal(__FILE__, __LINE__, 268 "libuv version too new: running with libuv %s " 269 "when compiled with libuv %s will lead to " 270 "libuv failures", 271 uv_version_string(), UV_VERSION_STRING); 272 } 273 #endif /* MAXIMAL_UV_VERSION */ 274 275 if (uv_version() < MINIMAL_UV_VERSION) { 276 isc_error_fatal(__FILE__, __LINE__, 277 "libuv version too old: running with libuv %s " 278 "when compiled with libuv %s will lead to " 279 "libuv failures", 280 uv_version_string(), UV_VERSION_STRING); 281 } 282 283 #ifdef WIN32 284 isc__nm_winsock_initialize(); 285 #endif /* WIN32 */ 286 287 isc__nm_threadpool_initialize(nworkers); 288 289 mgr = isc_mem_get(mctx, sizeof(*mgr)); 290 *mgr = (isc_nm_t){ 291 .nworkers = nworkers * 2, 292 .nlisteners = nworkers, 293 }; 294 295 isc_mem_attach(mctx, &mgr->mctx); 296 isc_mutex_init(&mgr->lock); 297 isc_condition_init(&mgr->wkstatecond); 298 isc_condition_init(&mgr->wkpausecond); 299 isc_refcount_init(&mgr->references, 1); 300 atomic_init(&mgr->maxudp, 0); 301 atomic_init(&mgr->interlocked, ISC_NETMGR_NON_INTERLOCKED); 302 atomic_init(&mgr->workers_paused, 0); 303 atomic_init(&mgr->paused, false); 304 atomic_init(&mgr->closing, false); 305 #if HAVE_SO_REUSEPORT_LB 306 mgr->load_balance_sockets = true; 307 #else 308 mgr->load_balance_sockets = false; 309 #endif 310 311 #ifdef NETMGR_TRACE 312 ISC_LIST_INIT(mgr->active_sockets); 313 #endif 314 315 /* 316 * Default TCP timeout values. 317 * May be updated by isc_nm_tcptimeouts(). 318 */ 319 atomic_init(&mgr->init, 30000); 320 atomic_init(&mgr->idle, 30000); 321 atomic_init(&mgr->keepalive, 30000); 322 atomic_init(&mgr->advertised, 30000); 323 324 isc_barrier_init(&mgr->pausing, mgr->nworkers); 325 isc_barrier_init(&mgr->resuming, mgr->nworkers); 326 327 mgr->workers = isc_mem_get(mctx, 328 mgr->nworkers * sizeof(isc__networker_t)); 329 for (int i = 0; i < mgr->nworkers; i++) { 330 isc__networker_t *worker = &mgr->workers[i]; 331 int r; 332 333 *worker = (isc__networker_t){ 334 .mgr = mgr, 335 .id = i, 336 }; 337 338 r = uv_loop_init(&worker->loop); 339 UV_RUNTIME_CHECK(uv_loop_init, r); 340 341 worker->loop.data = &mgr->workers[i]; 342 343 r = uv_async_init(&worker->loop, &worker->async, async_cb); 344 UV_RUNTIME_CHECK(uv_async_init, r); 345 346 for (size_t type = 0; type < NETIEVENT_MAX; type++) { 347 isc_mutex_init(&worker->ievents[type].lock); 348 isc_condition_init(&worker->ievents[type].cond); 349 ISC_LIST_INIT(worker->ievents[type].list); 350 } 351 352 worker->recvbuf = isc_mem_get(mctx, ISC_NETMGR_RECVBUF_SIZE); 353 worker->sendbuf = isc_mem_get(mctx, ISC_NETMGR_SENDBUF_SIZE); 354 355 /* 356 * We need to do this here and not in nm_thread to avoid a 357 * race - we could exit isc_nm_start, launch nm_destroy, 358 * and nm_thread would still not be up. 359 */ 360 mgr->workers_running++; 361 isc_thread_create(nm_thread, &mgr->workers[i], &worker->thread); 362 363 snprintf(name, sizeof(name), "net-%d", i); 364 isc_thread_setname(worker->thread, name); 365 } 366 367 mgr->magic = NM_MAGIC; 368 *netmgrp = mgr; 369 } 370 371 /* 372 * Free the resources of the network manager. 373 */ 374 static void 375 nm_destroy(isc_nm_t **mgr0) { 376 REQUIRE(VALID_NM(*mgr0)); 377 REQUIRE(!isc__nm_in_netthread()); 378 379 isc_nm_t *mgr = *mgr0; 380 *mgr0 = NULL; 381 382 isc_refcount_destroy(&mgr->references); 383 384 mgr->magic = 0; 385 386 for (int i = 0; i < mgr->nworkers; i++) { 387 isc__networker_t *worker = &mgr->workers[i]; 388 isc__netievent_t *event = isc__nm_get_netievent_stop(mgr); 389 isc__nm_enqueue_ievent(worker, event); 390 } 391 392 LOCK(&mgr->lock); 393 while (mgr->workers_running > 0) { 394 WAIT(&mgr->wkstatecond, &mgr->lock); 395 } 396 UNLOCK(&mgr->lock); 397 398 for (int i = 0; i < mgr->nworkers; i++) { 399 isc__networker_t *worker = &mgr->workers[i]; 400 int r; 401 402 r = uv_loop_close(&worker->loop); 403 UV_RUNTIME_CHECK(uv_loop_close, r); 404 405 for (size_t type = 0; type < NETIEVENT_MAX; type++) { 406 INSIST(ISC_LIST_EMPTY(worker->ievents[type].list)); 407 isc_condition_destroy(&worker->ievents[type].cond); 408 isc_mutex_destroy(&worker->ievents[type].lock); 409 } 410 411 isc_mem_put(mgr->mctx, worker->sendbuf, 412 ISC_NETMGR_SENDBUF_SIZE); 413 isc_mem_put(mgr->mctx, worker->recvbuf, 414 ISC_NETMGR_RECVBUF_SIZE); 415 isc_thread_join(worker->thread, NULL); 416 } 417 418 if (mgr->stats != NULL) { 419 isc_stats_detach(&mgr->stats); 420 } 421 422 isc_barrier_destroy(&mgr->resuming); 423 isc_barrier_destroy(&mgr->pausing); 424 425 isc_condition_destroy(&mgr->wkstatecond); 426 isc_condition_destroy(&mgr->wkpausecond); 427 isc_mutex_destroy(&mgr->lock); 428 429 isc_mem_put(mgr->mctx, mgr->workers, 430 mgr->nworkers * sizeof(isc__networker_t)); 431 isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(*mgr)); 432 433 #ifdef WIN32 434 isc__nm_winsock_destroy(); 435 #endif /* WIN32 */ 436 } 437 438 static void 439 enqueue_pause(isc__networker_t *worker) { 440 isc__netievent_pause_t *event = 441 isc__nm_get_netievent_pause(worker->mgr); 442 isc__nm_enqueue_ievent(worker, (isc__netievent_t *)event); 443 } 444 445 static void 446 isc__nm_async_pause(isc__networker_t *worker, isc__netievent_t *ev0) { 447 UNUSED(ev0); 448 REQUIRE(worker->paused == false); 449 450 worker->paused = true; 451 uv_stop(&worker->loop); 452 } 453 454 void 455 isc_nm_pause(isc_nm_t *mgr) { 456 REQUIRE(VALID_NM(mgr)); 457 REQUIRE(!atomic_load(&mgr->paused)); 458 459 isc__nm_acquire_interlocked_force(mgr); 460 461 if (isc__nm_in_netthread()) { 462 REQUIRE(isc_nm_tid() == 0); 463 } 464 465 for (int i = 0; i < mgr->nworkers; i++) { 466 isc__networker_t *worker = &mgr->workers[i]; 467 if (i == isc_nm_tid()) { 468 isc__nm_async_pause(worker, NULL); 469 } else { 470 enqueue_pause(worker); 471 } 472 } 473 474 if (isc__nm_in_netthread()) { 475 atomic_fetch_add(&mgr->workers_paused, 1); 476 isc_barrier_wait(&mgr->pausing); 477 } 478 479 LOCK(&mgr->lock); 480 while (atomic_load(&mgr->workers_paused) != mgr->workers_running) { 481 WAIT(&mgr->wkstatecond, &mgr->lock); 482 } 483 UNLOCK(&mgr->lock); 484 485 REQUIRE(atomic_compare_exchange_strong(&mgr->paused, &(bool){ false }, 486 true)); 487 } 488 489 static void 490 enqueue_resume(isc__networker_t *worker) { 491 isc__netievent_resume_t *event = 492 isc__nm_get_netievent_resume(worker->mgr); 493 isc__nm_enqueue_ievent(worker, (isc__netievent_t *)event); 494 } 495 496 static void 497 isc__nm_async_resume(isc__networker_t *worker, isc__netievent_t *ev0) { 498 UNUSED(ev0); 499 REQUIRE(worker->paused == true); 500 501 worker->paused = false; 502 } 503 504 void 505 isc_nm_resume(isc_nm_t *mgr) { 506 REQUIRE(VALID_NM(mgr)); 507 REQUIRE(atomic_load(&mgr->paused)); 508 509 if (isc__nm_in_netthread()) { 510 REQUIRE(isc_nm_tid() == 0); 511 drain_queue(&mgr->workers[isc_nm_tid()], NETIEVENT_PRIORITY); 512 } 513 514 for (int i = 0; i < mgr->nworkers; i++) { 515 isc__networker_t *worker = &mgr->workers[i]; 516 if (i == isc_nm_tid()) { 517 isc__nm_async_resume(worker, NULL); 518 } else { 519 enqueue_resume(worker); 520 } 521 } 522 523 if (isc__nm_in_netthread()) { 524 drain_queue(&mgr->workers[isc_nm_tid()], NETIEVENT_PRIVILEGED); 525 526 atomic_fetch_sub(&mgr->workers_paused, 1); 527 isc_barrier_wait(&mgr->resuming); 528 } 529 530 LOCK(&mgr->lock); 531 while (atomic_load(&mgr->workers_paused) != 0) { 532 WAIT(&mgr->wkstatecond, &mgr->lock); 533 } 534 UNLOCK(&mgr->lock); 535 536 REQUIRE(atomic_compare_exchange_strong(&mgr->paused, &(bool){ true }, 537 false)); 538 539 isc__nm_drop_interlocked(mgr); 540 } 541 542 void 543 isc_nm_attach(isc_nm_t *mgr, isc_nm_t **dst) { 544 REQUIRE(VALID_NM(mgr)); 545 REQUIRE(dst != NULL && *dst == NULL); 546 547 isc_refcount_increment(&mgr->references); 548 549 *dst = mgr; 550 } 551 552 void 553 isc_nm_detach(isc_nm_t **mgr0) { 554 isc_nm_t *mgr = NULL; 555 556 REQUIRE(mgr0 != NULL); 557 REQUIRE(VALID_NM(*mgr0)); 558 559 mgr = *mgr0; 560 *mgr0 = NULL; 561 562 if (isc_refcount_decrement(&mgr->references) == 1) { 563 nm_destroy(&mgr); 564 } 565 } 566 567 void 568 isc__netmgr_shutdown(isc_nm_t *mgr) { 569 REQUIRE(VALID_NM(mgr)); 570 571 atomic_store(&mgr->closing, true); 572 for (int i = 0; i < mgr->nworkers; i++) { 573 isc__netievent_t *event = NULL; 574 event = isc__nm_get_netievent_shutdown(mgr); 575 isc__nm_enqueue_ievent(&mgr->workers[i], event); 576 } 577 } 578 579 void 580 isc__netmgr_destroy(isc_nm_t **netmgrp) { 581 isc_nm_t *mgr = NULL; 582 int counter = 0; 583 584 REQUIRE(VALID_NM(*netmgrp)); 585 586 mgr = *netmgrp; 587 588 /* 589 * Close active connections. 590 */ 591 isc__netmgr_shutdown(mgr); 592 593 /* 594 * Wait for the manager to be dereferenced elsewhere. 595 */ 596 while (isc_refcount_current(&mgr->references) > 1 && counter++ < 1000) { 597 uv_sleep(10); 598 } 599 600 #ifdef NETMGR_TRACE 601 if (isc_refcount_current(&mgr->references) > 1) { 602 isc__nm_dump_active(mgr); 603 UNREACHABLE(); 604 } 605 #endif 606 607 /* 608 * Now just patiently wait 609 */ 610 while (isc_refcount_current(&mgr->references) > 1) { 611 uv_sleep(10); 612 } 613 614 /* 615 * Detach final reference. 616 */ 617 isc_nm_detach(netmgrp); 618 } 619 620 void 621 isc_nm_maxudp(isc_nm_t *mgr, uint32_t maxudp) { 622 REQUIRE(VALID_NM(mgr)); 623 624 atomic_store(&mgr->maxudp, maxudp); 625 } 626 627 void 628 isc_nmhandle_setwritetimeout(isc_nmhandle_t *handle, uint64_t write_timeout) { 629 REQUIRE(VALID_NMHANDLE(handle)); 630 REQUIRE(VALID_NMSOCK(handle->sock)); 631 632 handle->sock->write_timeout = write_timeout; 633 } 634 635 void 636 isc_nm_settimeouts(isc_nm_t *mgr, uint32_t init, uint32_t idle, 637 uint32_t keepalive, uint32_t advertised) { 638 REQUIRE(VALID_NM(mgr)); 639 640 atomic_store(&mgr->init, init); 641 atomic_store(&mgr->idle, idle); 642 atomic_store(&mgr->keepalive, keepalive); 643 atomic_store(&mgr->advertised, advertised); 644 } 645 646 bool 647 isc_nm_getloadbalancesockets(isc_nm_t *mgr) { 648 REQUIRE(VALID_NM(mgr)); 649 650 return (mgr->load_balance_sockets); 651 } 652 653 void 654 isc_nm_setloadbalancesockets(isc_nm_t *mgr, bool enabled) { 655 REQUIRE(VALID_NM(mgr)); 656 657 #if HAVE_SO_REUSEPORT_LB 658 mgr->load_balance_sockets = enabled; 659 #else 660 UNUSED(enabled); 661 #endif 662 } 663 664 void 665 isc_nm_gettimeouts(isc_nm_t *mgr, uint32_t *initial, uint32_t *idle, 666 uint32_t *keepalive, uint32_t *advertised) { 667 REQUIRE(VALID_NM(mgr)); 668 669 if (initial != NULL) { 670 *initial = atomic_load(&mgr->init); 671 } 672 673 if (idle != NULL) { 674 *idle = atomic_load(&mgr->idle); 675 } 676 677 if (keepalive != NULL) { 678 *keepalive = atomic_load(&mgr->keepalive); 679 } 680 681 if (advertised != NULL) { 682 *advertised = atomic_load(&mgr->advertised); 683 } 684 } 685 686 /* 687 * nm_thread is a single worker thread, that runs uv_run event loop 688 * until asked to stop. 689 * 690 * There are four queues for asynchronous events: 691 * 692 * 1. priority queue - netievents on the priority queue are run even when 693 * the taskmgr enters exclusive mode and the netmgr is paused. This 694 * is needed to properly start listening on the interfaces, free 695 * resources on shutdown, or resume from a pause. 696 * 697 * 2. privileged task queue - only privileged tasks are queued here and 698 * this is the first queue that gets processed when network manager 699 * is unpaused using isc_nm_resume(). All netmgr workers need to 700 * clean the privileged task queue before they all proceed to normal 701 * operation. Both task queues are processed when the workers are 702 * shutting down. 703 * 704 * 3. task queue - only (traditional) tasks are scheduled here, and this 705 * queue and the privileged task queue are both processed when the 706 * netmgr workers are finishing. This is needed to process the task 707 * shutdown events. 708 * 709 * 4. normal queue - this is the queue with netmgr events, e.g. reading, 710 * sending, callbacks, etc. 711 */ 712 713 static isc_threadresult_t 714 nm_thread(isc_threadarg_t worker0) { 715 isc__networker_t *worker = (isc__networker_t *)worker0; 716 isc_nm_t *mgr = worker->mgr; 717 718 isc__nm_tid_v = worker->id; 719 720 while (true) { 721 /* 722 * uv_run() runs async_cb() in a loop, which processes 723 * all four event queues until a "pause" or "stop" event 724 * is encountered. On pause, we process only priority and 725 * privileged events until resuming. 726 */ 727 int r = uv_run(&worker->loop, UV_RUN_DEFAULT); 728 INSIST(r > 0 || worker->finished); 729 730 if (worker->paused) { 731 INSIST(atomic_load(&mgr->interlocked) != isc_nm_tid()); 732 733 atomic_fetch_add(&mgr->workers_paused, 1); 734 if (isc_barrier_wait(&mgr->pausing) != 0) { 735 LOCK(&mgr->lock); 736 SIGNAL(&mgr->wkstatecond); 737 UNLOCK(&mgr->lock); 738 } 739 740 while (worker->paused) { 741 wait_for_priority_queue(worker); 742 } 743 744 /* 745 * All workers must drain the privileged event 746 * queue before we resume from pause. 747 */ 748 drain_queue(worker, NETIEVENT_PRIVILEGED); 749 750 atomic_fetch_sub(&mgr->workers_paused, 1); 751 if (isc_barrier_wait(&mgr->resuming) != 0) { 752 LOCK(&mgr->lock); 753 SIGNAL(&mgr->wkstatecond); 754 UNLOCK(&mgr->lock); 755 } 756 } 757 758 if (r == 0) { 759 INSIST(worker->finished); 760 break; 761 } 762 763 INSIST(!worker->finished); 764 } 765 766 /* 767 * We are shutting down. Drain the queues. 768 */ 769 drain_queue(worker, NETIEVENT_PRIVILEGED); 770 drain_queue(worker, NETIEVENT_TASK); 771 772 for (size_t type = 0; type < NETIEVENT_MAX; type++) { 773 LOCK(&worker->ievents[type].lock); 774 INSIST(ISC_LIST_EMPTY(worker->ievents[type].list)); 775 UNLOCK(&worker->ievents[type].lock); 776 } 777 778 LOCK(&mgr->lock); 779 mgr->workers_running--; 780 SIGNAL(&mgr->wkstatecond); 781 UNLOCK(&mgr->lock); 782 783 return ((isc_threadresult_t)0); 784 } 785 786 static bool 787 process_all_queues(isc__networker_t *worker) { 788 bool reschedule = false; 789 /* 790 * The queue processing functions will return false when the 791 * system is pausing or stopping and we don't want to process 792 * the other queues in such case, but we need the async event 793 * to be rescheduled in the next uv_run(). 794 */ 795 for (size_t type = 0; type < NETIEVENT_MAX; type++) { 796 isc_result_t result = process_queue(worker, type); 797 switch (result) { 798 case ISC_R_SUSPEND: 799 reschedule = true; 800 break; 801 case ISC_R_EMPTY: 802 /* empty queue */ 803 break; 804 case ISC_R_SUCCESS: 805 reschedule = true; 806 break; 807 default: 808 UNREACHABLE(); 809 } 810 } 811 812 return (reschedule); 813 } 814 815 /* 816 * async_cb() is a universal callback for 'async' events sent to event loop. 817 * It's the only way to safely pass data to the libuv event loop. We use a 818 * single async event and a set of lockless queues of 'isc__netievent_t' 819 * structures passed from other threads. 820 */ 821 static void 822 async_cb(uv_async_t *handle) { 823 isc__networker_t *worker = (isc__networker_t *)handle->loop->data; 824 825 if (process_all_queues(worker)) { 826 /* 827 * If we didn't process all the events, we need to enqueue 828 * async_cb to be run in the next iteration of the uv_loop 829 */ 830 uv_async_send(handle); 831 } 832 } 833 834 static void 835 isc__nm_async_stop(isc__networker_t *worker, isc__netievent_t *ev0) { 836 UNUSED(ev0); 837 worker->finished = true; 838 /* Close the async handler */ 839 uv_close((uv_handle_t *)&worker->async, NULL); 840 } 841 842 void 843 isc_nm_task_enqueue(isc_nm_t *nm, isc_task_t *task, int threadid) { 844 isc__netievent_t *event = NULL; 845 int tid; 846 isc__networker_t *worker = NULL; 847 848 if (threadid == -1) { 849 tid = (int)isc_random_uniform(nm->nlisteners); 850 } else if (threadid == ISC_NM_TASK_SLOW_OFFSET) { 851 tid = nm->nlisteners + 852 (int)isc_random_uniform(nm->nworkers - nm->nlisteners); 853 } else if (threadid < ISC_NM_TASK_SLOW_OFFSET) { 854 tid = nm->nlisteners + (ISC_NM_TASK_SLOW(threadid) % 855 (nm->nworkers - nm->nlisteners)); 856 } else { 857 tid = threadid % nm->nlisteners; 858 } 859 860 worker = &nm->workers[tid]; 861 862 if (isc_task_privileged(task)) { 863 event = (isc__netievent_t *) 864 isc__nm_get_netievent_privilegedtask(nm, task); 865 } else { 866 event = (isc__netievent_t *)isc__nm_get_netievent_task(nm, 867 task); 868 } 869 870 isc__nm_enqueue_ievent(worker, event); 871 } 872 873 #define isc__nm_async_privilegedtask(worker, ev0) \ 874 isc__nm_async_task(worker, ev0) 875 876 static void 877 isc__nm_async_task(isc__networker_t *worker, isc__netievent_t *ev0) { 878 isc__netievent_task_t *ievent = (isc__netievent_task_t *)ev0; 879 isc_result_t result; 880 881 UNUSED(worker); 882 883 result = isc_task_run(ievent->task); 884 885 switch (result) { 886 case ISC_R_QUOTA: 887 isc_task_ready(ievent->task); 888 return; 889 case ISC_R_SUCCESS: 890 return; 891 default: 892 UNREACHABLE(); 893 } 894 } 895 896 static void 897 wait_for_priority_queue(isc__networker_t *worker) { 898 isc_condition_t *cond = &worker->ievents[NETIEVENT_PRIORITY].cond; 899 isc_mutex_t *lock = &worker->ievents[NETIEVENT_PRIORITY].lock; 900 isc__netievent_list_t *list = 901 &(worker->ievents[NETIEVENT_PRIORITY].list); 902 903 LOCK(lock); 904 while (ISC_LIST_EMPTY(*list)) { 905 WAIT(cond, lock); 906 } 907 UNLOCK(lock); 908 909 drain_queue(worker, NETIEVENT_PRIORITY); 910 } 911 912 static void 913 drain_queue(isc__networker_t *worker, netievent_type_t type) { 914 bool empty = false; 915 while (!empty) { 916 if (process_queue(worker, type) == ISC_R_EMPTY) { 917 LOCK(&worker->ievents[type].lock); 918 empty = ISC_LIST_EMPTY(worker->ievents[type].list); 919 UNLOCK(&worker->ievents[type].lock); 920 } 921 } 922 } 923 924 /* 925 * The two macros here generate the individual cases for the process_netievent() 926 * function. The NETIEVENT_CASE(type) macro is the common case, and 927 * NETIEVENT_CASE_NOMORE(type) is a macro that causes the loop in the 928 * process_queue() to stop, e.g. it's only used for the netievent that 929 * stops/pauses processing the enqueued netievents. 930 */ 931 #define NETIEVENT_CASE(type) \ 932 case netievent_##type: { \ 933 isc__nm_async_##type(worker, ievent); \ 934 isc__nm_put_netievent_##type( \ 935 worker->mgr, (isc__netievent_##type##_t *)ievent); \ 936 return (true); \ 937 } 938 939 #define NETIEVENT_CASE_NOMORE(type) \ 940 case netievent_##type: { \ 941 isc__nm_async_##type(worker, ievent); \ 942 isc__nm_put_netievent_##type(worker->mgr, ievent); \ 943 return (false); \ 944 } 945 946 static bool 947 process_netievent(isc__networker_t *worker, isc__netievent_t *ievent) { 948 REQUIRE(worker->id == isc_nm_tid()); 949 950 switch (ievent->type) { 951 /* Don't process more ievents when we are stopping */ 952 NETIEVENT_CASE_NOMORE(stop); 953 954 NETIEVENT_CASE(privilegedtask); 955 NETIEVENT_CASE(task); 956 957 NETIEVENT_CASE(udpconnect); 958 NETIEVENT_CASE(udplisten); 959 NETIEVENT_CASE(udpstop); 960 NETIEVENT_CASE(udpsend); 961 NETIEVENT_CASE(udpread); 962 NETIEVENT_CASE(udpcancel); 963 NETIEVENT_CASE(udpclose); 964 965 NETIEVENT_CASE(tcpaccept); 966 NETIEVENT_CASE(tcpconnect); 967 NETIEVENT_CASE(tcplisten); 968 NETIEVENT_CASE(tcpstartread); 969 NETIEVENT_CASE(tcppauseread); 970 NETIEVENT_CASE(tcpsend); 971 NETIEVENT_CASE(tcpstop); 972 NETIEVENT_CASE(tcpcancel); 973 NETIEVENT_CASE(tcpclose); 974 975 NETIEVENT_CASE(tcpdnsaccept); 976 NETIEVENT_CASE(tcpdnslisten); 977 NETIEVENT_CASE(tcpdnsconnect); 978 NETIEVENT_CASE(tcpdnssend); 979 NETIEVENT_CASE(tcpdnscancel); 980 NETIEVENT_CASE(tcpdnsclose); 981 NETIEVENT_CASE(tcpdnsread); 982 NETIEVENT_CASE(tcpdnsstop); 983 984 NETIEVENT_CASE(connectcb); 985 NETIEVENT_CASE(readcb); 986 NETIEVENT_CASE(sendcb); 987 988 NETIEVENT_CASE(close); 989 NETIEVENT_CASE(detach); 990 991 NETIEVENT_CASE(shutdown); 992 NETIEVENT_CASE(resume); 993 NETIEVENT_CASE_NOMORE(pause); 994 default: 995 UNREACHABLE(); 996 } 997 return (true); 998 } 999 1000 static isc_result_t 1001 process_queue(isc__networker_t *worker, netievent_type_t type) { 1002 isc__netievent_t *ievent = NULL; 1003 isc__netievent_list_t list; 1004 1005 ISC_LIST_INIT(list); 1006 1007 LOCK(&worker->ievents[type].lock); 1008 ISC_LIST_MOVE(list, worker->ievents[type].list); 1009 UNLOCK(&worker->ievents[type].lock); 1010 1011 ievent = ISC_LIST_HEAD(list); 1012 if (ievent == NULL) { 1013 /* There's nothing scheduled */ 1014 return (ISC_R_EMPTY); 1015 } 1016 1017 while (ievent != NULL) { 1018 isc__netievent_t *next = ISC_LIST_NEXT(ievent, link); 1019 ISC_LIST_DEQUEUE(list, ievent, link); 1020 1021 if (!process_netievent(worker, ievent)) { 1022 /* The netievent told us to stop */ 1023 if (!ISC_LIST_EMPTY(list)) { 1024 /* 1025 * Reschedule the rest of the unprocessed 1026 * events. 1027 */ 1028 LOCK(&worker->ievents[type].lock); 1029 ISC_LIST_PREPENDLIST(worker->ievents[type].list, 1030 list, link); 1031 UNLOCK(&worker->ievents[type].lock); 1032 } 1033 return (ISC_R_SUSPEND); 1034 } 1035 1036 ievent = next; 1037 } 1038 1039 /* We processed at least one */ 1040 return (ISC_R_SUCCESS); 1041 } 1042 1043 void * 1044 isc__nm_get_netievent(isc_nm_t *mgr, isc__netievent_type type) { 1045 isc__netievent_storage_t *event = isc_mem_get(mgr->mctx, 1046 sizeof(*event)); 1047 1048 *event = (isc__netievent_storage_t){ .ni.type = type }; 1049 ISC_LINK_INIT(&(event->ni), link); 1050 return (event); 1051 } 1052 1053 void 1054 isc__nm_put_netievent(isc_nm_t *mgr, void *ievent) { 1055 isc_mem_put(mgr->mctx, ievent, sizeof(isc__netievent_storage_t)); 1056 } 1057 1058 NETIEVENT_SOCKET_DEF(tcpclose); 1059 NETIEVENT_SOCKET_DEF(tcplisten); 1060 NETIEVENT_SOCKET_DEF(tcppauseread); 1061 NETIEVENT_SOCKET_DEF(tcpstartread); 1062 NETIEVENT_SOCKET_DEF(tcpstop); 1063 NETIEVENT_SOCKET_DEF(udpclose); 1064 NETIEVENT_SOCKET_DEF(udplisten); 1065 NETIEVENT_SOCKET_DEF(udpread); 1066 NETIEVENT_SOCKET_DEF(udpsend); 1067 NETIEVENT_SOCKET_DEF(udpstop); 1068 1069 NETIEVENT_SOCKET_DEF(tcpdnsclose); 1070 NETIEVENT_SOCKET_DEF(tcpdnsread); 1071 NETIEVENT_SOCKET_DEF(tcpdnsstop); 1072 NETIEVENT_SOCKET_DEF(tcpdnslisten); 1073 NETIEVENT_SOCKET_REQ_DEF(tcpdnsconnect); 1074 NETIEVENT_SOCKET_REQ_DEF(tcpdnssend); 1075 NETIEVENT_SOCKET_HANDLE_DEF(tcpdnscancel); 1076 NETIEVENT_SOCKET_QUOTA_DEF(tcpdnsaccept); 1077 1078 NETIEVENT_SOCKET_REQ_DEF(tcpconnect); 1079 NETIEVENT_SOCKET_REQ_DEF(tcpsend); 1080 NETIEVENT_SOCKET_REQ_DEF(udpconnect); 1081 NETIEVENT_SOCKET_REQ_RESULT_DEF(connectcb); 1082 NETIEVENT_SOCKET_REQ_RESULT_DEF(readcb); 1083 NETIEVENT_SOCKET_REQ_RESULT_DEF(sendcb); 1084 1085 NETIEVENT_SOCKET_DEF(detach); 1086 NETIEVENT_SOCKET_HANDLE_DEF(tcpcancel); 1087 NETIEVENT_SOCKET_HANDLE_DEF(udpcancel); 1088 1089 NETIEVENT_SOCKET_QUOTA_DEF(tcpaccept); 1090 1091 NETIEVENT_SOCKET_DEF(close); 1092 NETIEVENT_DEF(pause); 1093 NETIEVENT_DEF(resume); 1094 NETIEVENT_DEF(shutdown); 1095 NETIEVENT_DEF(stop); 1096 1097 NETIEVENT_TASK_DEF(task); 1098 NETIEVENT_TASK_DEF(privilegedtask); 1099 1100 void 1101 isc__nm_maybe_enqueue_ievent(isc__networker_t *worker, 1102 isc__netievent_t *event) { 1103 /* 1104 * If we are already in the matching nmthread, process the ievent 1105 * directly. 1106 */ 1107 if (worker->id == isc_nm_tid()) { 1108 process_netievent(worker, event); 1109 return; 1110 } 1111 1112 isc__nm_enqueue_ievent(worker, event); 1113 } 1114 1115 void 1116 isc__nm_enqueue_ievent(isc__networker_t *worker, isc__netievent_t *event) { 1117 netievent_type_t type; 1118 1119 if (event->type > netievent_prio) { 1120 type = NETIEVENT_PRIORITY; 1121 } else { 1122 switch (event->type) { 1123 case netievent_prio: 1124 UNREACHABLE(); 1125 break; 1126 case netievent_privilegedtask: 1127 type = NETIEVENT_PRIVILEGED; 1128 break; 1129 case netievent_task: 1130 type = NETIEVENT_TASK; 1131 break; 1132 default: 1133 type = NETIEVENT_NORMAL; 1134 break; 1135 } 1136 } 1137 1138 /* 1139 * We need to make sure this signal will be delivered and 1140 * the queue will be processed. 1141 */ 1142 LOCK(&worker->ievents[type].lock); 1143 ISC_LIST_ENQUEUE(worker->ievents[type].list, event, link); 1144 if (type == NETIEVENT_PRIORITY) { 1145 SIGNAL(&worker->ievents[type].cond); 1146 } 1147 UNLOCK(&worker->ievents[type].lock); 1148 1149 uv_async_send(&worker->async); 1150 } 1151 1152 bool 1153 isc__nmsocket_active(isc_nmsocket_t *sock) { 1154 REQUIRE(VALID_NMSOCK(sock)); 1155 if (sock->parent != NULL) { 1156 return (atomic_load(&sock->parent->active)); 1157 } 1158 1159 return (atomic_load(&sock->active)); 1160 } 1161 1162 bool 1163 isc__nmsocket_deactivate(isc_nmsocket_t *sock) { 1164 REQUIRE(VALID_NMSOCK(sock)); 1165 1166 if (sock->parent != NULL) { 1167 return (atomic_compare_exchange_strong(&sock->parent->active, 1168 &(bool){ true }, false)); 1169 } 1170 1171 return (atomic_compare_exchange_strong(&sock->active, &(bool){ true }, 1172 false)); 1173 } 1174 1175 void 1176 isc___nmsocket_attach(isc_nmsocket_t *sock, isc_nmsocket_t **target FLARG) { 1177 REQUIRE(VALID_NMSOCK(sock)); 1178 REQUIRE(target != NULL && *target == NULL); 1179 1180 isc_nmsocket_t *rsock = NULL; 1181 1182 if (sock->parent != NULL) { 1183 rsock = sock->parent; 1184 INSIST(rsock->parent == NULL); /* sanity check */ 1185 } else { 1186 rsock = sock; 1187 } 1188 1189 NETMGR_TRACE_LOG("isc__nmsocket_attach():%p->references = %" PRIuFAST32 1190 "\n", 1191 rsock, isc_refcount_current(&rsock->references) + 1); 1192 1193 isc_refcount_increment0(&rsock->references); 1194 1195 *target = sock; 1196 } 1197 1198 /* 1199 * Free all resources inside a socket (including its children if any). 1200 */ 1201 static void 1202 nmsocket_cleanup(isc_nmsocket_t *sock, bool dofree FLARG) { 1203 isc_nmhandle_t *handle = NULL; 1204 isc__nm_uvreq_t *uvreq = NULL; 1205 1206 REQUIRE(VALID_NMSOCK(sock)); 1207 REQUIRE(!isc__nmsocket_active(sock)); 1208 1209 NETMGR_TRACE_LOG("nmsocket_cleanup():%p->references = %" PRIuFAST32 1210 "\n", 1211 sock, isc_refcount_current(&sock->references)); 1212 1213 atomic_store(&sock->destroying, true); 1214 1215 if (sock->parent == NULL && sock->children != NULL) { 1216 /* 1217 * We shouldn't be here unless there are no active handles, 1218 * so we can clean up and free the children. 1219 */ 1220 for (size_t i = 0; i < sock->nchildren; i++) { 1221 if (!atomic_load(&sock->children[i].destroying)) { 1222 nmsocket_cleanup(&sock->children[i], 1223 false FLARG_PASS); 1224 } 1225 } 1226 1227 /* 1228 * This was a parent socket: destroy the listening 1229 * barriers that synchronized the children. 1230 */ 1231 isc_barrier_destroy(&sock->startlistening); 1232 isc_barrier_destroy(&sock->stoplistening); 1233 1234 /* 1235 * Now free them. 1236 */ 1237 isc_mem_put(sock->mgr->mctx, sock->children, 1238 sock->nchildren * sizeof(*sock)); 1239 sock->children = NULL; 1240 sock->nchildren = 0; 1241 } 1242 if (sock->statsindex != NULL) { 1243 isc__nm_decstats(sock->mgr, sock->statsindex[STATID_ACTIVE]); 1244 } 1245 1246 sock->statichandle = NULL; 1247 1248 if (sock->outerhandle != NULL) { 1249 isc__nmhandle_detach(&sock->outerhandle FLARG_PASS); 1250 } 1251 1252 if (sock->outer != NULL) { 1253 isc___nmsocket_detach(&sock->outer FLARG_PASS); 1254 } 1255 1256 while ((handle = isc_astack_pop(sock->inactivehandles)) != NULL) { 1257 nmhandle_free(sock, handle); 1258 } 1259 1260 if (sock->buf != NULL) { 1261 isc_mem_free(sock->mgr->mctx, sock->buf); 1262 } 1263 1264 if (sock->quota != NULL) { 1265 isc_quota_detach(&sock->quota); 1266 } 1267 1268 sock->pquota = NULL; 1269 1270 isc_astack_destroy(sock->inactivehandles); 1271 1272 while ((uvreq = isc_astack_pop(sock->inactivereqs)) != NULL) { 1273 isc_mem_put(sock->mgr->mctx, uvreq, sizeof(*uvreq)); 1274 } 1275 1276 isc_astack_destroy(sock->inactivereqs); 1277 sock->magic = 0; 1278 1279 isc_condition_destroy(&sock->scond); 1280 isc_condition_destroy(&sock->cond); 1281 isc_mutex_destroy(&sock->lock); 1282 #ifdef NETMGR_TRACE 1283 LOCK(&sock->mgr->lock); 1284 ISC_LIST_UNLINK(sock->mgr->active_sockets, sock, active_link); 1285 UNLOCK(&sock->mgr->lock); 1286 #endif 1287 if (dofree) { 1288 isc_nm_t *mgr = sock->mgr; 1289 isc_mem_put(mgr->mctx, sock, sizeof(*sock)); 1290 isc_nm_detach(&mgr); 1291 } else { 1292 isc_nm_detach(&sock->mgr); 1293 } 1294 } 1295 1296 static void 1297 nmsocket_maybe_destroy(isc_nmsocket_t *sock FLARG) { 1298 int active_handles; 1299 bool destroy = false; 1300 1301 NETMGR_TRACE_LOG("%s():%p->references = %" PRIuFAST32 "\n", __func__, 1302 sock, isc_refcount_current(&sock->references)); 1303 1304 if (sock->parent != NULL) { 1305 /* 1306 * This is a child socket and cannot be destroyed except 1307 * as a side effect of destroying the parent, so let's go 1308 * see if the parent is ready to be destroyed. 1309 */ 1310 nmsocket_maybe_destroy(sock->parent FLARG_PASS); 1311 return; 1312 } 1313 1314 /* 1315 * This is a parent socket (or a standalone). See whether the 1316 * children have active handles before deciding whether to 1317 * accept destruction. 1318 */ 1319 LOCK(&sock->lock); 1320 if (atomic_load(&sock->active) || atomic_load(&sock->destroying) || 1321 !atomic_load(&sock->closed) || atomic_load(&sock->references) != 0) 1322 { 1323 UNLOCK(&sock->lock); 1324 return; 1325 } 1326 1327 active_handles = atomic_load(&sock->ah); 1328 if (sock->children != NULL) { 1329 for (size_t i = 0; i < sock->nchildren; i++) { 1330 LOCK(&sock->children[i].lock); 1331 active_handles += atomic_load(&sock->children[i].ah); 1332 UNLOCK(&sock->children[i].lock); 1333 } 1334 } 1335 1336 if (active_handles == 0 || sock->statichandle != NULL) { 1337 destroy = true; 1338 } 1339 1340 NETMGR_TRACE_LOG("%s:%p->active_handles = %d, .statichandle = %p\n", 1341 __func__, sock, active_handles, sock->statichandle); 1342 1343 if (destroy) { 1344 atomic_store(&sock->destroying, true); 1345 UNLOCK(&sock->lock); 1346 nmsocket_cleanup(sock, true FLARG_PASS); 1347 } else { 1348 UNLOCK(&sock->lock); 1349 } 1350 } 1351 1352 void 1353 isc___nmsocket_prep_destroy(isc_nmsocket_t *sock FLARG) { 1354 REQUIRE(sock->parent == NULL); 1355 1356 NETMGR_TRACE_LOG("isc___nmsocket_prep_destroy():%p->references = " 1357 "%" PRIuFAST32 "\n", 1358 sock, isc_refcount_current(&sock->references)); 1359 1360 /* 1361 * The final external reference to the socket is gone. We can try 1362 * destroying the socket, but we have to wait for all the inflight 1363 * handles to finish first. 1364 */ 1365 atomic_store(&sock->active, false); 1366 1367 /* 1368 * If the socket has children, they'll need to be marked inactive 1369 * so they can be cleaned up too. 1370 */ 1371 if (sock->children != NULL) { 1372 for (size_t i = 0; i < sock->nchildren; i++) { 1373 atomic_store(&sock->children[i].active, false); 1374 } 1375 } 1376 1377 /* 1378 * If we're here then we already stopped listening; otherwise 1379 * we'd have a hanging reference from the listening process. 1380 * 1381 * If it's a regular socket we may need to close it. 1382 */ 1383 if (!atomic_load(&sock->closed)) { 1384 switch (sock->type) { 1385 case isc_nm_udpsocket: 1386 isc__nm_udp_close(sock); 1387 return; 1388 case isc_nm_tcpsocket: 1389 isc__nm_tcp_close(sock); 1390 return; 1391 case isc_nm_tcpdnssocket: 1392 isc__nm_tcpdns_close(sock); 1393 return; 1394 default: 1395 break; 1396 } 1397 } 1398 1399 nmsocket_maybe_destroy(sock FLARG_PASS); 1400 } 1401 1402 void 1403 isc___nmsocket_detach(isc_nmsocket_t **sockp FLARG) { 1404 REQUIRE(sockp != NULL && *sockp != NULL); 1405 REQUIRE(VALID_NMSOCK(*sockp)); 1406 1407 isc_nmsocket_t *sock = *sockp, *rsock = NULL; 1408 *sockp = NULL; 1409 1410 /* 1411 * If the socket is a part of a set (a child socket) we are 1412 * counting references for the whole set at the parent. 1413 */ 1414 if (sock->parent != NULL) { 1415 rsock = sock->parent; 1416 INSIST(rsock->parent == NULL); /* Sanity check */ 1417 } else { 1418 rsock = sock; 1419 } 1420 1421 NETMGR_TRACE_LOG("isc__nmsocket_detach():%p->references = %" PRIuFAST32 1422 "\n", 1423 rsock, isc_refcount_current(&rsock->references) - 1); 1424 1425 if (isc_refcount_decrement(&rsock->references) == 1) { 1426 isc___nmsocket_prep_destroy(rsock FLARG_PASS); 1427 } 1428 } 1429 1430 void 1431 isc_nmsocket_close(isc_nmsocket_t **sockp) { 1432 REQUIRE(sockp != NULL); 1433 REQUIRE(VALID_NMSOCK(*sockp)); 1434 REQUIRE((*sockp)->type == isc_nm_udplistener || 1435 (*sockp)->type == isc_nm_tcplistener || 1436 (*sockp)->type == isc_nm_tcpdnslistener); 1437 1438 isc__nmsocket_detach(sockp); 1439 } 1440 1441 void 1442 isc___nmsocket_init(isc_nmsocket_t *sock, isc_nm_t *mgr, isc_nmsocket_type type, 1443 isc_sockaddr_t *iface FLARG) { 1444 uint16_t family; 1445 1446 REQUIRE(sock != NULL); 1447 REQUIRE(mgr != NULL); 1448 REQUIRE(iface != NULL); 1449 1450 family = iface->type.sa.sa_family; 1451 1452 *sock = (isc_nmsocket_t){ .type = type, 1453 .iface = *iface, 1454 .fd = -1, 1455 .inactivehandles = isc_astack_new( 1456 mgr->mctx, ISC_NM_HANDLES_STACK_SIZE), 1457 .inactivereqs = isc_astack_new( 1458 mgr->mctx, ISC_NM_REQS_STACK_SIZE) }; 1459 1460 #if NETMGR_TRACE 1461 sock->backtrace_size = backtrace(sock->backtrace, TRACE_SIZE); 1462 ISC_LINK_INIT(sock, active_link); 1463 ISC_LIST_INIT(sock->active_handles); 1464 LOCK(&mgr->lock); 1465 ISC_LIST_APPEND(mgr->active_sockets, sock, active_link); 1466 UNLOCK(&mgr->lock); 1467 #endif 1468 1469 isc_nm_attach(mgr, &sock->mgr); 1470 sock->uv_handle.handle.data = sock; 1471 1472 ISC_LINK_INIT(&sock->quotacb, link); 1473 1474 switch (type) { 1475 case isc_nm_udpsocket: 1476 case isc_nm_udplistener: 1477 if (family == AF_INET) { 1478 sock->statsindex = udp4statsindex; 1479 } else { 1480 sock->statsindex = udp6statsindex; 1481 } 1482 isc__nm_incstats(sock->mgr, sock->statsindex[STATID_ACTIVE]); 1483 break; 1484 case isc_nm_tcpsocket: 1485 case isc_nm_tcplistener: 1486 case isc_nm_tcpdnssocket: 1487 case isc_nm_tcpdnslistener: 1488 if (family == AF_INET) { 1489 sock->statsindex = tcp4statsindex; 1490 } else { 1491 sock->statsindex = tcp6statsindex; 1492 } 1493 isc__nm_incstats(sock->mgr, sock->statsindex[STATID_ACTIVE]); 1494 break; 1495 default: 1496 break; 1497 } 1498 1499 isc_mutex_init(&sock->lock); 1500 isc_condition_init(&sock->cond); 1501 isc_condition_init(&sock->scond); 1502 isc_refcount_init(&sock->references, 1); 1503 1504 NETMGR_TRACE_LOG("isc__nmsocket_init():%p->references = %" PRIuFAST32 1505 "\n", 1506 sock, isc_refcount_current(&sock->references)); 1507 1508 atomic_init(&sock->active, true); 1509 atomic_init(&sock->sequential, false); 1510 atomic_init(&sock->readpaused, false); 1511 atomic_init(&sock->closing, false); 1512 atomic_init(&sock->listening, 0); 1513 atomic_init(&sock->closed, 0); 1514 atomic_init(&sock->destroying, 0); 1515 atomic_init(&sock->ah, 0); 1516 atomic_init(&sock->client, 0); 1517 atomic_init(&sock->connecting, false); 1518 atomic_init(&sock->keepalive, false); 1519 atomic_init(&sock->connected, false); 1520 atomic_init(&sock->timedout, false); 1521 1522 atomic_init(&sock->active_child_connections, 0); 1523 1524 sock->magic = NMSOCK_MAGIC; 1525 } 1526 1527 void 1528 isc__nmsocket_clearcb(isc_nmsocket_t *sock) { 1529 REQUIRE(VALID_NMSOCK(sock)); 1530 REQUIRE(!isc__nm_in_netthread() || sock->tid == isc_nm_tid()); 1531 1532 sock->recv_cb = NULL; 1533 sock->recv_cbarg = NULL; 1534 sock->accept_cb = NULL; 1535 sock->accept_cbarg = NULL; 1536 sock->connect_cb = NULL; 1537 sock->connect_cbarg = NULL; 1538 } 1539 1540 void 1541 isc__nm_free_uvbuf(isc_nmsocket_t *sock, const uv_buf_t *buf) { 1542 isc__networker_t *worker = NULL; 1543 1544 REQUIRE(VALID_NMSOCK(sock)); 1545 1546 worker = &sock->mgr->workers[sock->tid]; 1547 REQUIRE(buf->base == worker->recvbuf); 1548 1549 worker->recvbuf_inuse = false; 1550 } 1551 1552 static isc_nmhandle_t * 1553 alloc_handle(isc_nmsocket_t *sock) { 1554 isc_nmhandle_t *handle = 1555 isc_mem_get(sock->mgr->mctx, 1556 sizeof(isc_nmhandle_t) + sock->extrahandlesize); 1557 1558 *handle = (isc_nmhandle_t){ .magic = NMHANDLE_MAGIC }; 1559 #ifdef NETMGR_TRACE 1560 ISC_LINK_INIT(handle, active_link); 1561 #endif 1562 isc_refcount_init(&handle->references, 1); 1563 1564 return (handle); 1565 } 1566 1567 isc_nmhandle_t * 1568 isc___nmhandle_get(isc_nmsocket_t *sock, isc_sockaddr_t *peer, 1569 isc_sockaddr_t *local FLARG) { 1570 isc_nmhandle_t *handle = NULL; 1571 1572 REQUIRE(VALID_NMSOCK(sock)); 1573 1574 handle = isc_astack_pop(sock->inactivehandles); 1575 1576 if (handle == NULL) { 1577 handle = alloc_handle(sock); 1578 } else { 1579 isc_refcount_init(&handle->references, 1); 1580 INSIST(VALID_NMHANDLE(handle)); 1581 } 1582 1583 NETMGR_TRACE_LOG( 1584 "isc__nmhandle_get():handle %p->references = %" PRIuFAST32 "\n", 1585 handle, isc_refcount_current(&handle->references)); 1586 1587 isc___nmsocket_attach(sock, &handle->sock FLARG_PASS); 1588 1589 #if NETMGR_TRACE 1590 handle->backtrace_size = backtrace(handle->backtrace, TRACE_SIZE); 1591 #endif 1592 1593 if (peer != NULL) { 1594 handle->peer = *peer; 1595 } else { 1596 handle->peer = sock->peer; 1597 } 1598 1599 if (local != NULL) { 1600 handle->local = *local; 1601 } else { 1602 handle->local = sock->iface; 1603 } 1604 1605 (void)atomic_fetch_add(&sock->ah, 1); 1606 1607 #ifdef NETMGR_TRACE 1608 LOCK(&sock->lock); 1609 ISC_LIST_APPEND(sock->active_handles, handle, active_link); 1610 UNLOCK(&sock->lock); 1611 #endif 1612 1613 switch (sock->type) { 1614 case isc_nm_udpsocket: 1615 case isc_nm_tcpdnssocket: 1616 if (!atomic_load(&sock->client)) { 1617 break; 1618 } 1619 FALLTHROUGH; 1620 case isc_nm_tcpsocket: 1621 INSIST(sock->statichandle == NULL); 1622 1623 /* 1624 * statichandle must be assigned, not attached; 1625 * otherwise, if a handle was detached elsewhere 1626 * it could never reach 0 references, and the 1627 * handle and socket would never be freed. 1628 */ 1629 sock->statichandle = handle; 1630 break; 1631 default: 1632 break; 1633 } 1634 1635 return (handle); 1636 } 1637 1638 void 1639 isc__nmhandle_attach(isc_nmhandle_t *handle, isc_nmhandle_t **handlep FLARG) { 1640 REQUIRE(VALID_NMHANDLE(handle)); 1641 REQUIRE(handlep != NULL && *handlep == NULL); 1642 1643 NETMGR_TRACE_LOG("isc__nmhandle_attach():handle %p->references = " 1644 "%" PRIuFAST32 "\n", 1645 handle, isc_refcount_current(&handle->references) + 1); 1646 1647 isc_refcount_increment(&handle->references); 1648 *handlep = handle; 1649 } 1650 1651 bool 1652 isc_nmhandle_is_stream(isc_nmhandle_t *handle) { 1653 REQUIRE(VALID_NMHANDLE(handle)); 1654 1655 return (handle->sock->type == isc_nm_tcpsocket || 1656 handle->sock->type == isc_nm_tcpdnssocket); 1657 } 1658 1659 static void 1660 nmhandle_free(isc_nmsocket_t *sock, isc_nmhandle_t *handle) { 1661 size_t extra = sock->extrahandlesize; 1662 1663 isc_refcount_destroy(&handle->references); 1664 1665 if (handle->dofree != NULL) { 1666 handle->dofree(handle->opaque); 1667 } 1668 1669 *handle = (isc_nmhandle_t){ .magic = 0 }; 1670 1671 isc_mem_put(sock->mgr->mctx, handle, sizeof(isc_nmhandle_t) + extra); 1672 } 1673 1674 static void 1675 nmhandle_deactivate(isc_nmsocket_t *sock, isc_nmhandle_t *handle) { 1676 bool reuse = false; 1677 1678 /* 1679 * We do all of this under lock to avoid races with socket 1680 * destruction. We have to do this now, because at this point the 1681 * socket is either unused or still attached to event->sock. 1682 */ 1683 LOCK(&sock->lock); 1684 1685 #ifdef NETMGR_TRACE 1686 ISC_LIST_UNLINK(sock->active_handles, handle, active_link); 1687 #endif 1688 1689 INSIST(atomic_fetch_sub(&sock->ah, 1) > 0); 1690 1691 #if !__SANITIZE_ADDRESS__ && !__SANITIZE_THREAD__ 1692 if (atomic_load(&sock->active)) { 1693 reuse = isc_astack_trypush(sock->inactivehandles, handle); 1694 } 1695 #endif /* !__SANITIZE_ADDRESS__ && !__SANITIZE_THREAD__ */ 1696 if (!reuse) { 1697 nmhandle_free(sock, handle); 1698 } 1699 UNLOCK(&sock->lock); 1700 } 1701 1702 void 1703 isc__nmhandle_detach(isc_nmhandle_t **handlep FLARG) { 1704 isc_nmsocket_t *sock = NULL; 1705 isc_nmhandle_t *handle = NULL; 1706 1707 REQUIRE(handlep != NULL); 1708 REQUIRE(VALID_NMHANDLE(*handlep)); 1709 1710 handle = *handlep; 1711 *handlep = NULL; 1712 1713 /* 1714 * If the closehandle_cb is set, it needs to run asynchronously to 1715 * ensure correct ordering of the isc__nm_process_sock_buffer(). 1716 */ 1717 sock = handle->sock; 1718 if (sock->tid == isc_nm_tid() && sock->closehandle_cb == NULL) { 1719 nmhandle_detach_cb(&handle FLARG_PASS); 1720 } else { 1721 isc__netievent_detach_t *event = 1722 isc__nm_get_netievent_detach(sock->mgr, sock); 1723 /* 1724 * we are using implicit "attach" as the last reference 1725 * need to be destroyed explicitly in the async callback 1726 */ 1727 event->handle = handle; 1728 FLARG_IEVENT_PASS(event); 1729 isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], 1730 (isc__netievent_t *)event); 1731 } 1732 } 1733 1734 void 1735 isc__nmsocket_shutdown(isc_nmsocket_t *sock); 1736 1737 static void 1738 nmhandle_detach_cb(isc_nmhandle_t **handlep FLARG) { 1739 isc_nmsocket_t *sock = NULL; 1740 isc_nmhandle_t *handle = NULL; 1741 1742 REQUIRE(handlep != NULL); 1743 REQUIRE(VALID_NMHANDLE(*handlep)); 1744 1745 handle = *handlep; 1746 *handlep = NULL; 1747 1748 NETMGR_TRACE_LOG("isc__nmhandle_detach():%p->references = %" PRIuFAST32 1749 "\n", 1750 handle, isc_refcount_current(&handle->references) - 1); 1751 1752 if (isc_refcount_decrement(&handle->references) > 1) { 1753 return; 1754 } 1755 1756 /* We need an acquire memory barrier here */ 1757 (void)isc_refcount_current(&handle->references); 1758 1759 sock = handle->sock; 1760 handle->sock = NULL; 1761 1762 if (handle->doreset != NULL) { 1763 handle->doreset(handle->opaque); 1764 } 1765 1766 nmhandle_deactivate(sock, handle); 1767 1768 /* 1769 * The handle is gone now. If the socket has a callback configured 1770 * for that (e.g., to perform cleanup after request processing), 1771 * call it now, or schedule it to run asynchronously. 1772 */ 1773 if (sock->closehandle_cb != NULL) { 1774 if (sock->tid == isc_nm_tid()) { 1775 sock->closehandle_cb(sock); 1776 } else { 1777 isc__netievent_close_t *event = 1778 isc__nm_get_netievent_close(sock->mgr, sock); 1779 isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], 1780 (isc__netievent_t *)event); 1781 } 1782 } 1783 1784 if (handle == sock->statichandle) { 1785 /* statichandle is assigned, not attached. */ 1786 sock->statichandle = NULL; 1787 } 1788 1789 isc___nmsocket_detach(&sock FLARG_PASS); 1790 } 1791 1792 void * 1793 isc_nmhandle_getdata(isc_nmhandle_t *handle) { 1794 REQUIRE(VALID_NMHANDLE(handle)); 1795 1796 return (handle->opaque); 1797 } 1798 1799 int 1800 isc_nmhandle_getfd(isc_nmhandle_t *handle) { 1801 REQUIRE(VALID_NMHANDLE(handle)); 1802 1803 return (handle->sock->fd); 1804 } 1805 1806 void 1807 isc_nmhandle_setdata(isc_nmhandle_t *handle, void *arg, 1808 isc_nm_opaquecb_t doreset, isc_nm_opaquecb_t dofree) { 1809 REQUIRE(VALID_NMHANDLE(handle)); 1810 1811 handle->opaque = arg; 1812 handle->doreset = doreset; 1813 handle->dofree = dofree; 1814 } 1815 1816 void 1817 isc__nm_alloc_dnsbuf(isc_nmsocket_t *sock, size_t len) { 1818 REQUIRE(len <= NM_BIG_BUF); 1819 1820 if (sock->buf == NULL) { 1821 /* We don't have the buffer at all */ 1822 size_t alloc_len = len < NM_REG_BUF ? NM_REG_BUF : NM_BIG_BUF; 1823 sock->buf = isc_mem_allocate(sock->mgr->mctx, alloc_len); 1824 sock->buf_size = alloc_len; 1825 } else { 1826 /* We have the buffer but it's too small */ 1827 sock->buf = isc_mem_reallocate(sock->mgr->mctx, sock->buf, 1828 NM_BIG_BUF); 1829 sock->buf_size = NM_BIG_BUF; 1830 } 1831 } 1832 1833 void 1834 isc__nm_failed_send_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req, 1835 isc_result_t eresult) { 1836 REQUIRE(VALID_NMSOCK(sock)); 1837 REQUIRE(VALID_UVREQ(req)); 1838 1839 if (req->cb.send != NULL) { 1840 isc__nm_sendcb(sock, req, eresult, true); 1841 } else { 1842 isc__nm_uvreq_put(&req, sock); 1843 } 1844 } 1845 1846 void 1847 isc__nm_failed_accept_cb(isc_nmsocket_t *sock, isc_result_t eresult) { 1848 REQUIRE(sock->accepting); 1849 REQUIRE(sock->server); 1850 1851 /* 1852 * Detach the quota early to make room for other connections; 1853 * otherwise it'd be detached later asynchronously, and clog 1854 * the quota unnecessarily. 1855 */ 1856 if (sock->quota != NULL) { 1857 isc_quota_detach(&sock->quota); 1858 } 1859 1860 isc__nmsocket_detach(&sock->server); 1861 1862 sock->accepting = false; 1863 1864 switch (eresult) { 1865 case ISC_R_NOTCONNECTED: 1866 /* IGNORE: The client disconnected before we could accept */ 1867 break; 1868 default: 1869 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 1870 ISC_LOGMODULE_NETMGR, ISC_LOG_ERROR, 1871 "Accepting TCP connection failed: %s", 1872 isc_result_totext(eresult)); 1873 } 1874 } 1875 1876 void 1877 isc__nm_failed_connect_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req, 1878 isc_result_t eresult, bool async) { 1879 REQUIRE(VALID_NMSOCK(sock)); 1880 REQUIRE(VALID_UVREQ(req)); 1881 REQUIRE(sock->tid == isc_nm_tid()); 1882 REQUIRE(req->cb.connect != NULL); 1883 1884 isc__nmsocket_timer_stop(sock); 1885 uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock); 1886 1887 INSIST(atomic_compare_exchange_strong(&sock->connecting, 1888 &(bool){ true }, false)); 1889 1890 isc__nmsocket_clearcb(sock); 1891 isc__nm_connectcb(sock, req, eresult, async); 1892 1893 isc__nmsocket_prep_destroy(sock); 1894 } 1895 1896 void 1897 isc__nm_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result, bool async) { 1898 REQUIRE(VALID_NMSOCK(sock)); 1899 UNUSED(async); 1900 1901 switch (sock->type) { 1902 case isc_nm_udpsocket: 1903 isc__nm_udp_failed_read_cb(sock, result); 1904 return; 1905 case isc_nm_tcpsocket: 1906 isc__nm_tcp_failed_read_cb(sock, result); 1907 return; 1908 case isc_nm_tcpdnssocket: 1909 isc__nm_tcpdns_failed_read_cb(sock, result); 1910 return; 1911 default: 1912 UNREACHABLE(); 1913 } 1914 } 1915 1916 void 1917 isc__nmsocket_connecttimeout_cb(uv_timer_t *timer) { 1918 uv_connect_t *uvreq = uv_handle_get_data((uv_handle_t *)timer); 1919 isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)uvreq->handle); 1920 isc__nm_uvreq_t *req = uv_handle_get_data((uv_handle_t *)uvreq); 1921 1922 REQUIRE(VALID_NMSOCK(sock)); 1923 REQUIRE(sock->tid == isc_nm_tid()); 1924 REQUIRE(atomic_load(&sock->connecting)); 1925 REQUIRE(VALID_UVREQ(req)); 1926 REQUIRE(VALID_NMHANDLE(req->handle)); 1927 1928 isc__nmsocket_timer_stop(sock); 1929 1930 /* 1931 * Mark the connection as timed out and shutdown the socket. 1932 */ 1933 1934 INSIST(atomic_compare_exchange_strong(&sock->timedout, &(bool){ false }, 1935 true)); 1936 isc__nmsocket_clearcb(sock); 1937 isc__nmsocket_shutdown(sock); 1938 } 1939 1940 void 1941 isc__nm_accept_connection_log(isc_result_t result, bool can_log_quota) { 1942 int level; 1943 1944 switch (result) { 1945 case ISC_R_SUCCESS: 1946 case ISC_R_NOCONN: 1947 return; 1948 case ISC_R_QUOTA: 1949 case ISC_R_SOFTQUOTA: 1950 if (!can_log_quota) { 1951 return; 1952 } 1953 level = ISC_LOG_INFO; 1954 break; 1955 case ISC_R_NOTCONNECTED: 1956 level = ISC_LOG_INFO; 1957 break; 1958 default: 1959 level = ISC_LOG_ERROR; 1960 } 1961 1962 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_NETMGR, 1963 level, "Accepting TCP connection failed: %s", 1964 isc_result_totext(result)); 1965 } 1966 1967 void 1968 isc__nmsocket_writetimeout_cb(void *data, isc_result_t eresult) { 1969 isc__nm_uvreq_t *req = data; 1970 isc_nmsocket_t *sock = NULL; 1971 1972 REQUIRE(eresult == ISC_R_TIMEDOUT); 1973 REQUIRE(VALID_UVREQ(req)); 1974 REQUIRE(VALID_NMSOCK(req->sock)); 1975 1976 sock = req->sock; 1977 1978 isc__nmsocket_reset(sock); 1979 } 1980 1981 void 1982 isc__nmsocket_readtimeout_cb(uv_timer_t *timer) { 1983 isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)timer); 1984 1985 REQUIRE(VALID_NMSOCK(sock)); 1986 REQUIRE(sock->tid == isc_nm_tid()); 1987 REQUIRE(sock->reading); 1988 1989 if (atomic_load(&sock->client)) { 1990 uv_timer_stop(timer); 1991 1992 if (sock->recv_cb != NULL) { 1993 isc__nm_uvreq_t *req = isc__nm_get_read_req(sock, NULL); 1994 isc__nm_readcb(sock, req, ISC_R_TIMEDOUT); 1995 } 1996 1997 if (!isc__nmsocket_timer_running(sock)) { 1998 isc__nmsocket_clearcb(sock); 1999 isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false); 2000 } 2001 } else { 2002 isc__nm_failed_read_cb(sock, ISC_R_TIMEDOUT, false); 2003 } 2004 } 2005 2006 void 2007 isc__nmsocket_timer_restart(isc_nmsocket_t *sock) { 2008 REQUIRE(VALID_NMSOCK(sock)); 2009 2010 if (atomic_load(&sock->connecting)) { 2011 int r; 2012 2013 if (sock->connect_timeout == 0) { 2014 return; 2015 } 2016 2017 r = uv_timer_start(&sock->read_timer, 2018 isc__nmsocket_connecttimeout_cb, 2019 sock->connect_timeout + 10, 0); 2020 UV_RUNTIME_CHECK(uv_timer_start, r); 2021 2022 } else { 2023 int r; 2024 2025 if (sock->read_timeout == 0) { 2026 return; 2027 } 2028 2029 r = uv_timer_start(&sock->read_timer, 2030 isc__nmsocket_readtimeout_cb, 2031 sock->read_timeout, 0); 2032 UV_RUNTIME_CHECK(uv_timer_start, r); 2033 } 2034 } 2035 2036 bool 2037 isc__nmsocket_timer_running(isc_nmsocket_t *sock) { 2038 REQUIRE(VALID_NMSOCK(sock)); 2039 2040 return (uv_is_active((uv_handle_t *)&sock->read_timer)); 2041 } 2042 2043 void 2044 isc__nmsocket_timer_start(isc_nmsocket_t *sock) { 2045 REQUIRE(VALID_NMSOCK(sock)); 2046 2047 if (isc__nmsocket_timer_running(sock)) { 2048 return; 2049 } 2050 2051 isc__nmsocket_timer_restart(sock); 2052 } 2053 2054 void 2055 isc__nmsocket_timer_stop(isc_nmsocket_t *sock) { 2056 int r; 2057 2058 REQUIRE(VALID_NMSOCK(sock)); 2059 2060 /* uv_timer_stop() is idempotent, no need to check if running */ 2061 2062 r = uv_timer_stop(&sock->read_timer); 2063 UV_RUNTIME_CHECK(uv_timer_stop, r); 2064 } 2065 2066 isc__nm_uvreq_t * 2067 isc__nm_get_read_req(isc_nmsocket_t *sock, isc_sockaddr_t *sockaddr) { 2068 isc__nm_uvreq_t *req = NULL; 2069 2070 req = isc__nm_uvreq_get(sock->mgr, sock); 2071 req->cb.recv = sock->recv_cb; 2072 req->cbarg = sock->recv_cbarg; 2073 2074 switch (sock->type) { 2075 case isc_nm_tcpsocket: 2076 isc_nmhandle_attach(sock->statichandle, &req->handle); 2077 break; 2078 default: 2079 if (atomic_load(&sock->client)) { 2080 isc_nmhandle_attach(sock->statichandle, &req->handle); 2081 } else { 2082 req->handle = isc__nmhandle_get(sock, sockaddr, NULL); 2083 } 2084 break; 2085 } 2086 2087 return (req); 2088 } 2089 2090 /*%< 2091 * Allocator callback for read operations. 2092 * 2093 * Note this doesn't actually allocate anything, it just assigns the 2094 * worker's receive buffer to a socket, and marks it as "in use". 2095 */ 2096 void 2097 isc__nm_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) { 2098 isc_nmsocket_t *sock = uv_handle_get_data(handle); 2099 isc__networker_t *worker = NULL; 2100 2101 REQUIRE(VALID_NMSOCK(sock)); 2102 REQUIRE(isc__nm_in_netthread()); 2103 /* 2104 * The size provided by libuv is only suggested size, and it always 2105 * defaults to 64 * 1024 in the current versions of libuv (see 2106 * src/unix/udp.c and src/unix/stream.c). 2107 */ 2108 UNUSED(size); 2109 2110 worker = &sock->mgr->workers[sock->tid]; 2111 INSIST(!worker->recvbuf_inuse); 2112 INSIST(worker->recvbuf != NULL); 2113 2114 switch (sock->type) { 2115 case isc_nm_udpsocket: 2116 buf->len = ISC_NETMGR_UDP_RECVBUF_SIZE; 2117 break; 2118 case isc_nm_tcpsocket: 2119 case isc_nm_tcpdnssocket: 2120 buf->len = ISC_NETMGR_TCP_RECVBUF_SIZE; 2121 break; 2122 default: 2123 UNREACHABLE(); 2124 } 2125 2126 REQUIRE(buf->len <= ISC_NETMGR_RECVBUF_SIZE); 2127 buf->base = worker->recvbuf; 2128 2129 worker->recvbuf_inuse = true; 2130 } 2131 2132 isc_result_t 2133 isc__nm_start_reading(isc_nmsocket_t *sock) { 2134 isc_result_t result = ISC_R_SUCCESS; 2135 int r; 2136 2137 if (sock->reading) { 2138 return (ISC_R_SUCCESS); 2139 } 2140 2141 switch (sock->type) { 2142 case isc_nm_udpsocket: 2143 r = uv_udp_recv_start(&sock->uv_handle.udp, isc__nm_alloc_cb, 2144 isc__nm_udp_read_cb); 2145 break; 2146 case isc_nm_tcpsocket: 2147 r = uv_read_start(&sock->uv_handle.stream, isc__nm_alloc_cb, 2148 isc__nm_tcp_read_cb); 2149 break; 2150 case isc_nm_tcpdnssocket: 2151 r = uv_read_start(&sock->uv_handle.stream, isc__nm_alloc_cb, 2152 isc__nm_tcpdns_read_cb); 2153 break; 2154 default: 2155 UNREACHABLE(); 2156 } 2157 2158 if (r != 0) { 2159 result = isc__nm_uverr2result(r); 2160 } else { 2161 sock->reading = true; 2162 } 2163 2164 return (result); 2165 } 2166 2167 void 2168 isc__nm_stop_reading(isc_nmsocket_t *sock) { 2169 int r; 2170 2171 if (!sock->reading) { 2172 return; 2173 } 2174 2175 switch (sock->type) { 2176 case isc_nm_udpsocket: 2177 r = uv_udp_recv_stop(&sock->uv_handle.udp); 2178 UV_RUNTIME_CHECK(uv_udp_recv_stop, r); 2179 break; 2180 case isc_nm_tcpsocket: 2181 case isc_nm_tcpdnssocket: 2182 r = uv_read_stop(&sock->uv_handle.stream); 2183 UV_RUNTIME_CHECK(uv_read_stop, r); 2184 break; 2185 default: 2186 UNREACHABLE(); 2187 } 2188 sock->reading = false; 2189 } 2190 2191 bool 2192 isc__nm_closing(isc_nmsocket_t *sock) { 2193 return (atomic_load(&sock->mgr->closing)); 2194 } 2195 2196 bool 2197 isc__nmsocket_closing(isc_nmsocket_t *sock) { 2198 return (!isc__nmsocket_active(sock) || atomic_load(&sock->closing) || 2199 atomic_load(&sock->mgr->closing) || 2200 (sock->server != NULL && !isc__nmsocket_active(sock->server))); 2201 } 2202 2203 static isc_result_t 2204 processbuffer(isc_nmsocket_t *sock) { 2205 switch (sock->type) { 2206 case isc_nm_tcpdnssocket: 2207 return (isc__nm_tcpdns_processbuffer(sock)); 2208 default: 2209 UNREACHABLE(); 2210 } 2211 } 2212 2213 /* 2214 * Process a DNS message. 2215 * 2216 * If we only have an incomplete DNS message, we don't touch any 2217 * timers. If we do have a full message, reset the timer. 2218 * 2219 * Stop reading if this is a client socket, or if the server socket 2220 * has been set to sequential mode, or the number of queries we are 2221 * processing simultaneously has reached the clients-per-connection 2222 * limit. In this case we'll be called again by resume_processing() 2223 * later. 2224 */ 2225 isc_result_t 2226 isc__nm_process_sock_buffer(isc_nmsocket_t *sock) { 2227 for (;;) { 2228 int_fast32_t ah = atomic_load(&sock->ah); 2229 isc_result_t result = processbuffer(sock); 2230 switch (result) { 2231 case ISC_R_NOMORE: 2232 /* 2233 * Don't reset the timer until we have a 2234 * full DNS message. 2235 */ 2236 result = isc__nm_start_reading(sock); 2237 if (result != ISC_R_SUCCESS) { 2238 return (result); 2239 } 2240 /* 2241 * Start the timer only if there are no externally used 2242 * active handles, there's always one active handle 2243 * attached internally to sock->recv_handle in 2244 * accept_connection() 2245 */ 2246 if (ah == 1) { 2247 isc__nmsocket_timer_start(sock); 2248 } 2249 goto done; 2250 case ISC_R_CANCELED: 2251 isc__nmsocket_timer_stop(sock); 2252 isc__nm_stop_reading(sock); 2253 goto done; 2254 case ISC_R_SUCCESS: 2255 /* 2256 * Stop the timer on the successful message read, this 2257 * also allows to restart the timer when we have no more 2258 * data. 2259 */ 2260 isc__nmsocket_timer_stop(sock); 2261 2262 if (atomic_load(&sock->client) || 2263 atomic_load(&sock->sequential) || 2264 ah >= STREAM_CLIENTS_PER_CONN) 2265 { 2266 isc__nm_stop_reading(sock); 2267 goto done; 2268 } 2269 break; 2270 default: 2271 UNREACHABLE(); 2272 } 2273 } 2274 done: 2275 return (ISC_R_SUCCESS); 2276 } 2277 2278 void 2279 isc__nm_resume_processing(void *arg) { 2280 isc_nmsocket_t *sock = (isc_nmsocket_t *)arg; 2281 2282 REQUIRE(VALID_NMSOCK(sock)); 2283 REQUIRE(sock->tid == isc_nm_tid()); 2284 REQUIRE(!atomic_load(&sock->client)); 2285 2286 if (isc__nmsocket_closing(sock)) { 2287 return; 2288 } 2289 2290 isc__nm_process_sock_buffer(sock); 2291 } 2292 2293 void 2294 isc_nmhandle_cleartimeout(isc_nmhandle_t *handle) { 2295 REQUIRE(VALID_NMHANDLE(handle)); 2296 REQUIRE(VALID_NMSOCK(handle->sock)); 2297 2298 switch (handle->sock->type) { 2299 default: 2300 handle->sock->read_timeout = 0; 2301 2302 if (uv_is_active((uv_handle_t *)&handle->sock->read_timer)) { 2303 isc__nmsocket_timer_stop(handle->sock); 2304 } 2305 } 2306 } 2307 2308 void 2309 isc_nmhandle_settimeout(isc_nmhandle_t *handle, uint32_t timeout) { 2310 REQUIRE(VALID_NMHANDLE(handle)); 2311 REQUIRE(VALID_NMSOCK(handle->sock)); 2312 2313 switch (handle->sock->type) { 2314 default: 2315 handle->sock->read_timeout = timeout; 2316 isc__nmsocket_timer_restart(handle->sock); 2317 } 2318 } 2319 2320 void 2321 isc_nmhandle_keepalive(isc_nmhandle_t *handle, bool value) { 2322 isc_nmsocket_t *sock = NULL; 2323 2324 REQUIRE(VALID_NMHANDLE(handle)); 2325 REQUIRE(VALID_NMSOCK(handle->sock)); 2326 2327 sock = handle->sock; 2328 2329 switch (sock->type) { 2330 case isc_nm_tcpsocket: 2331 case isc_nm_tcpdnssocket: 2332 atomic_store(&sock->keepalive, value); 2333 sock->read_timeout = value ? atomic_load(&sock->mgr->keepalive) 2334 : atomic_load(&sock->mgr->idle); 2335 sock->write_timeout = value ? atomic_load(&sock->mgr->keepalive) 2336 : atomic_load(&sock->mgr->idle); 2337 break; 2338 default: 2339 /* 2340 * For any other protocol, this is a no-op. 2341 */ 2342 return; 2343 } 2344 } 2345 2346 void * 2347 isc_nmhandle_getextra(isc_nmhandle_t *handle) { 2348 REQUIRE(VALID_NMHANDLE(handle)); 2349 2350 return (handle->extra); 2351 } 2352 2353 isc_sockaddr_t 2354 isc_nmhandle_peeraddr(isc_nmhandle_t *handle) { 2355 REQUIRE(VALID_NMHANDLE(handle)); 2356 2357 return (handle->peer); 2358 } 2359 2360 isc_sockaddr_t 2361 isc_nmhandle_localaddr(isc_nmhandle_t *handle) { 2362 REQUIRE(VALID_NMHANDLE(handle)); 2363 2364 return (handle->local); 2365 } 2366 2367 isc_nm_t * 2368 isc_nmhandle_netmgr(isc_nmhandle_t *handle) { 2369 REQUIRE(VALID_NMHANDLE(handle)); 2370 REQUIRE(VALID_NMSOCK(handle->sock)); 2371 2372 return (handle->sock->mgr); 2373 } 2374 2375 isc__nm_uvreq_t * 2376 isc___nm_uvreq_get(isc_nm_t *mgr, isc_nmsocket_t *sock FLARG) { 2377 isc__nm_uvreq_t *req = NULL; 2378 2379 REQUIRE(VALID_NM(mgr)); 2380 REQUIRE(VALID_NMSOCK(sock)); 2381 2382 if (sock != NULL && isc__nmsocket_active(sock)) { 2383 /* Try to reuse one */ 2384 req = isc_astack_pop(sock->inactivereqs); 2385 } 2386 2387 if (req == NULL) { 2388 req = isc_mem_get(mgr->mctx, sizeof(*req)); 2389 } 2390 2391 *req = (isc__nm_uvreq_t){ .magic = 0 }; 2392 ISC_LINK_INIT(req, link); 2393 req->uv_req.req.data = req; 2394 isc___nmsocket_attach(sock, &req->sock FLARG_PASS); 2395 req->magic = UVREQ_MAGIC; 2396 2397 return (req); 2398 } 2399 2400 void 2401 isc___nm_uvreq_put(isc__nm_uvreq_t **req0, isc_nmsocket_t *sock FLARG) { 2402 isc__nm_uvreq_t *req = NULL; 2403 isc_nmhandle_t *handle = NULL; 2404 2405 REQUIRE(req0 != NULL); 2406 REQUIRE(VALID_UVREQ(*req0)); 2407 2408 req = *req0; 2409 *req0 = NULL; 2410 2411 INSIST(sock == req->sock); 2412 2413 req->magic = 0; 2414 2415 /* 2416 * We need to save this first to make sure that handle, 2417 * sock, and the netmgr won't all disappear. 2418 */ 2419 handle = req->handle; 2420 req->handle = NULL; 2421 2422 #if !__SANITIZE_ADDRESS__ && !__SANITIZE_THREAD__ 2423 if (!isc__nmsocket_active(sock) || 2424 !isc_astack_trypush(sock->inactivereqs, req)) 2425 { 2426 isc_mem_put(sock->mgr->mctx, req, sizeof(*req)); 2427 } 2428 #else /* !__SANITIZE_ADDRESS__ && !__SANITIZE_THREAD__ */ 2429 isc_mem_put(sock->mgr->mctx, req, sizeof(*req)); 2430 #endif /* !__SANITIZE_ADDRESS__ && !__SANITIZE_THREAD__ */ 2431 2432 if (handle != NULL) { 2433 isc__nmhandle_detach(&handle FLARG_PASS); 2434 } 2435 2436 isc___nmsocket_detach(&sock FLARG_PASS); 2437 } 2438 2439 void 2440 isc_nm_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb, 2441 void *cbarg) { 2442 REQUIRE(VALID_NMHANDLE(handle)); 2443 2444 switch (handle->sock->type) { 2445 case isc_nm_udpsocket: 2446 case isc_nm_udplistener: 2447 isc__nm_udp_send(handle, region, cb, cbarg); 2448 break; 2449 case isc_nm_tcpsocket: 2450 isc__nm_tcp_send(handle, region, cb, cbarg); 2451 break; 2452 case isc_nm_tcpdnssocket: 2453 isc__nm_tcpdns_send(handle, region, cb, cbarg); 2454 break; 2455 default: 2456 UNREACHABLE(); 2457 } 2458 } 2459 2460 void 2461 isc_nm_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) { 2462 REQUIRE(VALID_NMHANDLE(handle)); 2463 2464 /* 2465 * This is always called via callback (from accept or connect), and 2466 * caller must attach to the handle, so the references always need to be 2467 * at least 2. 2468 */ 2469 REQUIRE(isc_refcount_current(&handle->references) >= 2); 2470 2471 switch (handle->sock->type) { 2472 case isc_nm_udpsocket: 2473 isc__nm_udp_read(handle, cb, cbarg); 2474 break; 2475 case isc_nm_tcpsocket: 2476 isc__nm_tcp_read(handle, cb, cbarg); 2477 break; 2478 case isc_nm_tcpdnssocket: 2479 isc__nm_tcpdns_read(handle, cb, cbarg); 2480 break; 2481 default: 2482 UNREACHABLE(); 2483 } 2484 } 2485 2486 void 2487 isc_nm_cancelread(isc_nmhandle_t *handle) { 2488 REQUIRE(VALID_NMHANDLE(handle)); 2489 2490 switch (handle->sock->type) { 2491 case isc_nm_udpsocket: 2492 isc__nm_udp_cancelread(handle); 2493 break; 2494 case isc_nm_tcpsocket: 2495 isc__nm_tcp_cancelread(handle); 2496 break; 2497 case isc_nm_tcpdnssocket: 2498 isc__nm_tcpdns_cancelread(handle); 2499 break; 2500 default: 2501 UNREACHABLE(); 2502 } 2503 } 2504 2505 void 2506 isc_nm_pauseread(isc_nmhandle_t *handle) { 2507 REQUIRE(VALID_NMHANDLE(handle)); 2508 2509 isc_nmsocket_t *sock = handle->sock; 2510 2511 switch (sock->type) { 2512 case isc_nm_tcpsocket: 2513 isc__nm_tcp_pauseread(handle); 2514 break; 2515 default: 2516 UNREACHABLE(); 2517 } 2518 } 2519 2520 void 2521 isc_nm_resumeread(isc_nmhandle_t *handle) { 2522 REQUIRE(VALID_NMHANDLE(handle)); 2523 2524 isc_nmsocket_t *sock = handle->sock; 2525 2526 switch (sock->type) { 2527 case isc_nm_tcpsocket: 2528 isc__nm_tcp_resumeread(handle); 2529 break; 2530 default: 2531 UNREACHABLE(); 2532 } 2533 } 2534 2535 void 2536 isc_nm_stoplistening(isc_nmsocket_t *sock) { 2537 REQUIRE(VALID_NMSOCK(sock)); 2538 2539 switch (sock->type) { 2540 case isc_nm_udplistener: 2541 isc__nm_udp_stoplistening(sock); 2542 break; 2543 case isc_nm_tcpdnslistener: 2544 isc__nm_tcpdns_stoplistening(sock); 2545 break; 2546 case isc_nm_tcplistener: 2547 isc__nm_tcp_stoplistening(sock); 2548 break; 2549 default: 2550 UNREACHABLE(); 2551 } 2552 } 2553 2554 void 2555 isc__nm_connectcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq, 2556 isc_result_t eresult, bool async) { 2557 REQUIRE(VALID_NMSOCK(sock)); 2558 REQUIRE(VALID_UVREQ(uvreq)); 2559 REQUIRE(VALID_NMHANDLE(uvreq->handle)); 2560 2561 if (!async) { 2562 isc__netievent_connectcb_t ievent = { .sock = sock, 2563 .req = uvreq, 2564 .result = eresult }; 2565 isc__nm_async_connectcb(NULL, (isc__netievent_t *)&ievent); 2566 } else { 2567 isc__netievent_connectcb_t *ievent = 2568 isc__nm_get_netievent_connectcb(sock->mgr, sock, uvreq, 2569 eresult); 2570 isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], 2571 (isc__netievent_t *)ievent); 2572 } 2573 } 2574 2575 void 2576 isc__nm_async_connectcb(isc__networker_t *worker, isc__netievent_t *ev0) { 2577 isc__netievent_connectcb_t *ievent = (isc__netievent_connectcb_t *)ev0; 2578 isc_nmsocket_t *sock = ievent->sock; 2579 isc__nm_uvreq_t *uvreq = ievent->req; 2580 isc_result_t eresult = ievent->result; 2581 2582 UNUSED(worker); 2583 2584 REQUIRE(VALID_NMSOCK(sock)); 2585 REQUIRE(VALID_UVREQ(uvreq)); 2586 REQUIRE(VALID_NMHANDLE(uvreq->handle)); 2587 REQUIRE(ievent->sock->tid == isc_nm_tid()); 2588 REQUIRE(uvreq->cb.connect != NULL); 2589 2590 uvreq->cb.connect(uvreq->handle, eresult, uvreq->cbarg); 2591 2592 isc__nm_uvreq_put(&uvreq, sock); 2593 } 2594 2595 void 2596 isc__nm_readcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq, 2597 isc_result_t eresult) { 2598 REQUIRE(VALID_NMSOCK(sock)); 2599 REQUIRE(VALID_UVREQ(uvreq)); 2600 REQUIRE(VALID_NMHANDLE(uvreq->handle)); 2601 2602 if (eresult == ISC_R_SUCCESS || eresult == ISC_R_TIMEDOUT) { 2603 isc__netievent_readcb_t ievent = { .sock = sock, 2604 .req = uvreq, 2605 .result = eresult }; 2606 2607 isc__nm_async_readcb(NULL, (isc__netievent_t *)&ievent); 2608 } else { 2609 isc__netievent_readcb_t *ievent = isc__nm_get_netievent_readcb( 2610 sock->mgr, sock, uvreq, eresult); 2611 isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], 2612 (isc__netievent_t *)ievent); 2613 } 2614 } 2615 2616 void 2617 isc__nm_async_readcb(isc__networker_t *worker, isc__netievent_t *ev0) { 2618 isc__netievent_readcb_t *ievent = (isc__netievent_readcb_t *)ev0; 2619 isc_nmsocket_t *sock = ievent->sock; 2620 isc__nm_uvreq_t *uvreq = ievent->req; 2621 isc_result_t eresult = ievent->result; 2622 isc_region_t region; 2623 2624 UNUSED(worker); 2625 2626 REQUIRE(VALID_NMSOCK(sock)); 2627 REQUIRE(VALID_UVREQ(uvreq)); 2628 REQUIRE(VALID_NMHANDLE(uvreq->handle)); 2629 REQUIRE(sock->tid == isc_nm_tid()); 2630 2631 region.base = (unsigned char *)uvreq->uvbuf.base; 2632 region.length = uvreq->uvbuf.len; 2633 2634 uvreq->cb.recv(uvreq->handle, eresult, ®ion, uvreq->cbarg); 2635 2636 isc__nm_uvreq_put(&uvreq, sock); 2637 } 2638 2639 void 2640 isc__nm_sendcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq, 2641 isc_result_t eresult, bool async) { 2642 REQUIRE(VALID_NMSOCK(sock)); 2643 REQUIRE(VALID_UVREQ(uvreq)); 2644 REQUIRE(VALID_NMHANDLE(uvreq->handle)); 2645 2646 if (!async) { 2647 isc__netievent_sendcb_t ievent = { .sock = sock, 2648 .req = uvreq, 2649 .result = eresult }; 2650 isc__nm_async_sendcb(NULL, (isc__netievent_t *)&ievent); 2651 return; 2652 } 2653 2654 isc__netievent_sendcb_t *ievent = 2655 isc__nm_get_netievent_sendcb(sock->mgr, sock, uvreq, eresult); 2656 isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], 2657 (isc__netievent_t *)ievent); 2658 } 2659 2660 void 2661 isc__nm_async_sendcb(isc__networker_t *worker, isc__netievent_t *ev0) { 2662 isc__netievent_sendcb_t *ievent = (isc__netievent_sendcb_t *)ev0; 2663 isc_nmsocket_t *sock = ievent->sock; 2664 isc__nm_uvreq_t *uvreq = ievent->req; 2665 isc_result_t eresult = ievent->result; 2666 2667 UNUSED(worker); 2668 2669 REQUIRE(VALID_NMSOCK(sock)); 2670 REQUIRE(VALID_UVREQ(uvreq)); 2671 REQUIRE(VALID_NMHANDLE(uvreq->handle)); 2672 REQUIRE(sock->tid == isc_nm_tid()); 2673 2674 uvreq->cb.send(uvreq->handle, eresult, uvreq->cbarg); 2675 2676 isc__nm_uvreq_put(&uvreq, sock); 2677 } 2678 2679 static void 2680 isc__nm_async_close(isc__networker_t *worker, isc__netievent_t *ev0) { 2681 isc__netievent_close_t *ievent = (isc__netievent_close_t *)ev0; 2682 isc_nmsocket_t *sock = ievent->sock; 2683 2684 REQUIRE(VALID_NMSOCK(ievent->sock)); 2685 REQUIRE(sock->tid == isc_nm_tid()); 2686 REQUIRE(sock->closehandle_cb != NULL); 2687 2688 UNUSED(worker); 2689 2690 ievent->sock->closehandle_cb(sock); 2691 } 2692 2693 void 2694 isc__nm_async_detach(isc__networker_t *worker, isc__netievent_t *ev0) { 2695 isc__netievent_detach_t *ievent = (isc__netievent_detach_t *)ev0; 2696 FLARG_IEVENT(ievent); 2697 2698 REQUIRE(VALID_NMSOCK(ievent->sock)); 2699 REQUIRE(VALID_NMHANDLE(ievent->handle)); 2700 REQUIRE(ievent->sock->tid == isc_nm_tid()); 2701 2702 UNUSED(worker); 2703 2704 nmhandle_detach_cb(&ievent->handle FLARG_PASS); 2705 } 2706 2707 static void 2708 reset_shutdown(uv_handle_t *handle) { 2709 isc_nmsocket_t *sock = uv_handle_get_data(handle); 2710 2711 isc__nmsocket_shutdown(sock); 2712 isc__nmsocket_detach(&sock); 2713 } 2714 2715 void 2716 isc__nmsocket_reset(isc_nmsocket_t *sock) { 2717 REQUIRE(VALID_NMSOCK(sock)); 2718 2719 switch (sock->type) { 2720 case isc_nm_tcpsocket: 2721 case isc_nm_tcpdnssocket: 2722 /* 2723 * This can be called from the TCP write timeout. 2724 */ 2725 REQUIRE(sock->parent == NULL); 2726 break; 2727 default: 2728 UNREACHABLE(); 2729 break; 2730 } 2731 2732 if (!uv_is_closing(&sock->uv_handle.handle) && 2733 uv_is_active(&sock->uv_handle.handle)) 2734 { 2735 /* 2736 * The real shutdown will be handled in the respective 2737 * close functions. 2738 */ 2739 isc__nmsocket_attach(sock, &(isc_nmsocket_t *){ NULL }); 2740 int r = uv_tcp_close_reset(&sock->uv_handle.tcp, 2741 reset_shutdown); 2742 UV_RUNTIME_CHECK(uv_tcp_close_reset, r); 2743 } else { 2744 isc__nmsocket_shutdown(sock); 2745 } 2746 } 2747 2748 void 2749 isc__nmsocket_shutdown(isc_nmsocket_t *sock) { 2750 REQUIRE(VALID_NMSOCK(sock)); 2751 switch (sock->type) { 2752 case isc_nm_udpsocket: 2753 isc__nm_udp_shutdown(sock); 2754 break; 2755 case isc_nm_tcpsocket: 2756 isc__nm_tcp_shutdown(sock); 2757 break; 2758 case isc_nm_tcpdnssocket: 2759 isc__nm_tcpdns_shutdown(sock); 2760 break; 2761 case isc_nm_udplistener: 2762 case isc_nm_tcplistener: 2763 case isc_nm_tcpdnslistener: 2764 return; 2765 default: 2766 UNREACHABLE(); 2767 } 2768 } 2769 2770 static void 2771 shutdown_walk_cb(uv_handle_t *handle, void *arg) { 2772 isc_nmsocket_t *sock = uv_handle_get_data(handle); 2773 UNUSED(arg); 2774 2775 if (uv_is_closing(handle)) { 2776 return; 2777 } 2778 2779 switch (handle->type) { 2780 case UV_UDP: 2781 isc__nmsocket_shutdown(sock); 2782 return; 2783 case UV_TCP: 2784 switch (sock->type) { 2785 case isc_nm_tcpsocket: 2786 case isc_nm_tcpdnssocket: 2787 if (sock->parent == NULL) { 2788 /* Reset the TCP connections on shutdown */ 2789 isc__nmsocket_reset(sock); 2790 return; 2791 } 2792 FALLTHROUGH; 2793 default: 2794 isc__nmsocket_shutdown(sock); 2795 } 2796 2797 return; 2798 default: 2799 return; 2800 } 2801 } 2802 2803 void 2804 isc__nm_async_shutdown(isc__networker_t *worker, isc__netievent_t *ev0) { 2805 UNUSED(ev0); 2806 2807 uv_walk(&worker->loop, shutdown_walk_cb, NULL); 2808 } 2809 2810 bool 2811 isc__nm_acquire_interlocked(isc_nm_t *mgr) { 2812 if (!isc__nm_in_netthread()) { 2813 return (false); 2814 } 2815 2816 LOCK(&mgr->lock); 2817 bool success = atomic_compare_exchange_strong( 2818 &mgr->interlocked, &(int){ ISC_NETMGR_NON_INTERLOCKED }, 2819 isc_nm_tid()); 2820 2821 UNLOCK(&mgr->lock); 2822 return (success); 2823 } 2824 2825 void 2826 isc__nm_drop_interlocked(isc_nm_t *mgr) { 2827 if (!isc__nm_in_netthread()) { 2828 return; 2829 } 2830 2831 LOCK(&mgr->lock); 2832 int tid = atomic_exchange(&mgr->interlocked, 2833 ISC_NETMGR_NON_INTERLOCKED); 2834 INSIST(tid != ISC_NETMGR_NON_INTERLOCKED); 2835 BROADCAST(&mgr->wkstatecond); 2836 UNLOCK(&mgr->lock); 2837 } 2838 2839 void 2840 isc__nm_acquire_interlocked_force(isc_nm_t *mgr) { 2841 if (!isc__nm_in_netthread()) { 2842 return; 2843 } 2844 2845 LOCK(&mgr->lock); 2846 while (!atomic_compare_exchange_strong( 2847 &mgr->interlocked, &(int){ ISC_NETMGR_NON_INTERLOCKED }, 2848 isc_nm_tid())) 2849 { 2850 WAIT(&mgr->wkstatecond, &mgr->lock); 2851 } 2852 UNLOCK(&mgr->lock); 2853 } 2854 2855 void 2856 isc_nm_setstats(isc_nm_t *mgr, isc_stats_t *stats) { 2857 REQUIRE(VALID_NM(mgr)); 2858 REQUIRE(mgr->stats == NULL); 2859 REQUIRE(isc_stats_ncounters(stats) == isc_sockstatscounter_max); 2860 2861 isc_stats_attach(stats, &mgr->stats); 2862 } 2863 2864 void 2865 isc__nm_incstats(isc_nm_t *mgr, isc_statscounter_t counterid) { 2866 REQUIRE(VALID_NM(mgr)); 2867 REQUIRE(counterid != -1); 2868 2869 if (mgr->stats != NULL) { 2870 isc_stats_increment(mgr->stats, counterid); 2871 } 2872 } 2873 2874 void 2875 isc__nm_decstats(isc_nm_t *mgr, isc_statscounter_t counterid) { 2876 REQUIRE(VALID_NM(mgr)); 2877 REQUIRE(counterid != -1); 2878 2879 if (mgr->stats != NULL) { 2880 isc_stats_decrement(mgr->stats, counterid); 2881 } 2882 } 2883 2884 isc_result_t 2885 isc__nm_socket(int domain, int type, int protocol, uv_os_sock_t *sockp) { 2886 #ifdef WIN32 2887 SOCKET sock; 2888 sock = socket(domain, type, protocol); 2889 if (sock == INVALID_SOCKET) { 2890 char strbuf[ISC_STRERRORSIZE]; 2891 DWORD socket_errno = WSAGetLastError(); 2892 switch (socket_errno) { 2893 case WSAEMFILE: 2894 case WSAENOBUFS: 2895 return (ISC_R_NORESOURCES); 2896 2897 case WSAEPROTONOSUPPORT: 2898 case WSAEPFNOSUPPORT: 2899 case WSAEAFNOSUPPORT: 2900 return (ISC_R_FAMILYNOSUPPORT); 2901 default: 2902 strerror_r(socket_errno, strbuf, sizeof(strbuf)); 2903 UNEXPECTED_ERROR( 2904 __FILE__, __LINE__, 2905 "socket() failed with error code %lu: %s", 2906 socket_errno, strbuf); 2907 return (ISC_R_UNEXPECTED); 2908 } 2909 } 2910 #else 2911 int sock = socket(domain, type, protocol); 2912 if (sock < 0) { 2913 return (isc_errno_toresult(errno)); 2914 } 2915 #endif 2916 *sockp = (uv_os_sock_t)sock; 2917 return (ISC_R_SUCCESS); 2918 } 2919 2920 void 2921 isc__nm_closesocket(uv_os_sock_t sock) { 2922 #ifdef WIN32 2923 closesocket(sock); 2924 #else 2925 close(sock); 2926 #endif 2927 } 2928 2929 #define setsockopt_on(socket, level, name) \ 2930 setsockopt(socket, level, name, &(int){ 1 }, sizeof(int)) 2931 2932 #define setsockopt_off(socket, level, name) \ 2933 setsockopt(socket, level, name, &(int){ 0 }, sizeof(int)) 2934 2935 isc_result_t 2936 isc__nm_socket_freebind(uv_os_sock_t fd, sa_family_t sa_family) { 2937 /* 2938 * Set the IP_FREEBIND (or equivalent option) on the uv_handle. 2939 */ 2940 #ifdef IP_FREEBIND 2941 UNUSED(sa_family); 2942 if (setsockopt_on(fd, IPPROTO_IP, IP_FREEBIND) == -1) { 2943 return (ISC_R_FAILURE); 2944 } 2945 return (ISC_R_SUCCESS); 2946 #elif defined(IP_BINDANY) || defined(IPV6_BINDANY) 2947 if (sa_family == AF_INET) { 2948 #if defined(IP_BINDANY) 2949 if (setsockopt_on(fd, IPPROTO_IP, IP_BINDANY) == -1) { 2950 return (ISC_R_FAILURE); 2951 } 2952 return (ISC_R_SUCCESS); 2953 #endif 2954 } else if (sa_family == AF_INET6) { 2955 #if defined(IPV6_BINDANY) 2956 if (setsockopt_on(fd, IPPROTO_IPV6, IPV6_BINDANY) == -1) { 2957 return (ISC_R_FAILURE); 2958 } 2959 return (ISC_R_SUCCESS); 2960 #endif 2961 } 2962 return (ISC_R_NOTIMPLEMENTED); 2963 #elif defined(SO_BINDANY) 2964 UNUSED(sa_family); 2965 if (setsockopt_on(fd, SOL_SOCKET, SO_BINDANY) == -1) { 2966 return (ISC_R_FAILURE); 2967 } 2968 return (ISC_R_SUCCESS); 2969 #else 2970 UNUSED(fd); 2971 UNUSED(sa_family); 2972 return (ISC_R_NOTIMPLEMENTED); 2973 #endif 2974 } 2975 2976 isc_result_t 2977 isc__nm_socket_reuse(uv_os_sock_t fd) { 2978 /* 2979 * Generally, the SO_REUSEADDR socket option allows reuse of 2980 * local addresses. 2981 * 2982 * On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some 2983 * additional refinements for programs that use multicast. 2984 * 2985 * On Linux, SO_REUSEPORT has different semantics: it _shares_ the port 2986 * rather than steal it from the current listener, so we don't use it 2987 * here, but rather in isc__nm_socket_reuse_lb(). 2988 * 2989 * On Windows, it also allows a socket to forcibly bind to a port in use 2990 * by another socket. 2991 */ 2992 2993 #if defined(SO_REUSEPORT) && !defined(__linux__) 2994 if (setsockopt_on(fd, SOL_SOCKET, SO_REUSEPORT) == -1) { 2995 return (ISC_R_FAILURE); 2996 } 2997 return (ISC_R_SUCCESS); 2998 #elif defined(SO_REUSEADDR) 2999 if (setsockopt_on(fd, SOL_SOCKET, SO_REUSEADDR) == -1) { 3000 return (ISC_R_FAILURE); 3001 } 3002 return (ISC_R_SUCCESS); 3003 #else 3004 UNUSED(fd); 3005 return (ISC_R_NOTIMPLEMENTED); 3006 #endif 3007 } 3008 3009 isc_result_t 3010 isc__nm_socket_reuse_lb(uv_os_sock_t fd) { 3011 /* 3012 * On FreeBSD 12+, SO_REUSEPORT_LB socket option allows sockets to be 3013 * bound to an identical socket address. For UDP sockets, the use of 3014 * this option can provide better distribution of incoming datagrams to 3015 * multiple processes (or threads) as compared to the traditional 3016 * technique of having multiple processes compete to receive datagrams 3017 * on the same socket. 3018 * 3019 * On Linux, the same thing is achieved simply with SO_REUSEPORT. 3020 */ 3021 #if defined(SO_REUSEPORT_LB) 3022 if (setsockopt_on(fd, SOL_SOCKET, SO_REUSEPORT_LB) == -1) { 3023 return (ISC_R_FAILURE); 3024 } else { 3025 return (ISC_R_SUCCESS); 3026 } 3027 #elif defined(SO_REUSEPORT) && defined(__linux__) 3028 if (setsockopt_on(fd, SOL_SOCKET, SO_REUSEPORT) == -1) { 3029 return (ISC_R_FAILURE); 3030 } else { 3031 return (ISC_R_SUCCESS); 3032 } 3033 #else 3034 UNUSED(fd); 3035 return (ISC_R_NOTIMPLEMENTED); 3036 #endif 3037 } 3038 3039 isc_result_t 3040 isc__nm_socket_incoming_cpu(uv_os_sock_t fd) { 3041 #ifdef SO_INCOMING_CPU 3042 if (setsockopt_on(fd, SOL_SOCKET, SO_INCOMING_CPU) == -1) { 3043 return (ISC_R_FAILURE); 3044 } else { 3045 return (ISC_R_SUCCESS); 3046 } 3047 #else 3048 UNUSED(fd); 3049 #endif 3050 return (ISC_R_NOTIMPLEMENTED); 3051 } 3052 3053 isc_result_t 3054 isc__nm_socket_disable_pmtud(uv_os_sock_t fd, sa_family_t sa_family) { 3055 /* 3056 * Disable the Path MTU Discovery on IP packets 3057 */ 3058 if (sa_family == AF_INET6) { 3059 #if defined(IPV6_DONTFRAG) 3060 if (setsockopt_off(fd, IPPROTO_IPV6, IPV6_DONTFRAG) == -1) { 3061 return (ISC_R_FAILURE); 3062 } else { 3063 return (ISC_R_SUCCESS); 3064 } 3065 #elif defined(IPV6_MTU_DISCOVER) && defined(IP_PMTUDISC_OMIT) 3066 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, 3067 &(int){ IP_PMTUDISC_OMIT }, sizeof(int)) == -1) 3068 { 3069 return (ISC_R_FAILURE); 3070 } else { 3071 return (ISC_R_SUCCESS); 3072 } 3073 #else 3074 UNUSED(fd); 3075 #endif 3076 } else if (sa_family == AF_INET) { 3077 #if defined(IP_DONTFRAG) 3078 if (setsockopt_off(fd, IPPROTO_IP, IP_DONTFRAG) == -1) { 3079 return (ISC_R_FAILURE); 3080 } else { 3081 return (ISC_R_SUCCESS); 3082 } 3083 #elif defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_OMIT) 3084 if (setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, 3085 &(int){ IP_PMTUDISC_OMIT }, sizeof(int)) == -1) 3086 { 3087 return (ISC_R_FAILURE); 3088 } else { 3089 return (ISC_R_SUCCESS); 3090 } 3091 #else 3092 UNUSED(fd); 3093 #endif 3094 } else { 3095 return (ISC_R_FAMILYNOSUPPORT); 3096 } 3097 3098 return (ISC_R_NOTIMPLEMENTED); 3099 } 3100 3101 #if defined(_WIN32) 3102 #define TIMEOUT_TYPE DWORD 3103 #define TIMEOUT_DIV 1000 3104 #define TIMEOUT_OPTNAME TCP_MAXRT 3105 #elif defined(TCP_CONNECTIONTIMEOUT) 3106 #define TIMEOUT_TYPE int 3107 #define TIMEOUT_DIV 1000 3108 #define TIMEOUT_OPTNAME TCP_CONNECTIONTIMEOUT 3109 #elif defined(TCP_RXT_CONNDROPTIME) 3110 #define TIMEOUT_TYPE int 3111 #define TIMEOUT_DIV 1000 3112 #define TIMEOUT_OPTNAME TCP_RXT_CONNDROPTIME 3113 #elif defined(TCP_USER_TIMEOUT) 3114 #define TIMEOUT_TYPE unsigned int 3115 #define TIMEOUT_DIV 1 3116 #define TIMEOUT_OPTNAME TCP_USER_TIMEOUT 3117 #elif defined(TCP_KEEPINIT) 3118 #define TIMEOUT_TYPE int 3119 #define TIMEOUT_DIV 1000 3120 #define TIMEOUT_OPTNAME TCP_KEEPINIT 3121 #endif 3122 3123 isc_result_t 3124 isc__nm_socket_connectiontimeout(uv_os_sock_t fd, int timeout_ms) { 3125 #if defined(TIMEOUT_OPTNAME) 3126 TIMEOUT_TYPE timeout = timeout_ms / TIMEOUT_DIV; 3127 3128 if (timeout == 0) { 3129 timeout = 1; 3130 } 3131 3132 if (setsockopt(fd, IPPROTO_TCP, TIMEOUT_OPTNAME, &timeout, 3133 sizeof(timeout)) == -1) 3134 { 3135 return (ISC_R_FAILURE); 3136 } 3137 3138 return (ISC_R_SUCCESS); 3139 #else 3140 UNUSED(fd); 3141 UNUSED(timeout_ms); 3142 3143 return (ISC_R_SUCCESS); 3144 #endif 3145 } 3146 3147 isc_result_t 3148 isc__nm_socket_tcp_nodelay(uv_os_sock_t fd) { 3149 #ifdef TCP_NODELAY 3150 if (setsockopt_on(fd, IPPROTO_TCP, TCP_NODELAY) == -1) { 3151 return (ISC_R_FAILURE); 3152 } else { 3153 return (ISC_R_SUCCESS); 3154 } 3155 #else 3156 UNUSED(fd); 3157 return (ISC_R_SUCCESS); 3158 #endif 3159 } 3160 3161 static isc_threadresult_t 3162 isc__nm_work_run(isc_threadarg_t arg) { 3163 isc__nm_work_t *work = (isc__nm_work_t *)arg; 3164 3165 work->cb(work->data); 3166 3167 return ((isc_threadresult_t)0); 3168 } 3169 3170 static void 3171 isc__nm_work_cb(uv_work_t *req) { 3172 isc__nm_work_t *work = uv_req_get_data((uv_req_t *)req); 3173 3174 if (isc_tid_v == SIZE_MAX) { 3175 isc__trampoline_t *trampoline_arg = 3176 isc__trampoline_get(isc__nm_work_run, work); 3177 (void)isc__trampoline_run(trampoline_arg); 3178 } else { 3179 (void)isc__nm_work_run((isc_threadarg_t)work); 3180 } 3181 } 3182 3183 static void 3184 isc__nm_after_work_cb(uv_work_t *req, int status) { 3185 isc_result_t result = ISC_R_SUCCESS; 3186 isc__nm_work_t *work = uv_req_get_data((uv_req_t *)req); 3187 isc_nm_t *netmgr = work->netmgr; 3188 3189 if (status != 0) { 3190 result = isc__nm_uverr2result(status); 3191 } 3192 3193 work->after_cb(work->data, result); 3194 3195 isc_mem_put(netmgr->mctx, work, sizeof(*work)); 3196 3197 isc_nm_detach(&netmgr); 3198 } 3199 3200 void 3201 isc_nm_work_offload(isc_nm_t *netmgr, isc_nm_workcb_t work_cb, 3202 isc_nm_after_workcb_t after_work_cb, void *data) { 3203 isc__networker_t *worker = NULL; 3204 isc__nm_work_t *work = NULL; 3205 int r; 3206 3207 REQUIRE(isc__nm_in_netthread()); 3208 REQUIRE(VALID_NM(netmgr)); 3209 3210 worker = &netmgr->workers[isc_nm_tid()]; 3211 3212 work = isc_mem_get(netmgr->mctx, sizeof(*work)); 3213 *work = (isc__nm_work_t){ 3214 .cb = work_cb, 3215 .after_cb = after_work_cb, 3216 .data = data, 3217 }; 3218 3219 isc_nm_attach(netmgr, &work->netmgr); 3220 3221 uv_req_set_data((uv_req_t *)&work->req, work); 3222 3223 r = uv_queue_work(&worker->loop, &work->req, isc__nm_work_cb, 3224 isc__nm_after_work_cb); 3225 UV_RUNTIME_CHECK(uv_queue_work, r); 3226 } 3227 3228 void 3229 isc_nm_timer_create(isc_nmhandle_t *handle, isc_nm_timer_cb cb, void *cbarg, 3230 isc_nm_timer_t **timerp) { 3231 isc__networker_t *worker = NULL; 3232 isc_nmsocket_t *sock = NULL; 3233 isc_nm_timer_t *timer = NULL; 3234 int r; 3235 3236 REQUIRE(isc__nm_in_netthread()); 3237 REQUIRE(VALID_NMHANDLE(handle)); 3238 REQUIRE(VALID_NMSOCK(handle->sock)); 3239 3240 sock = handle->sock; 3241 worker = &sock->mgr->workers[isc_nm_tid()]; 3242 3243 timer = isc_mem_get(sock->mgr->mctx, sizeof(*timer)); 3244 *timer = (isc_nm_timer_t){ .cb = cb, .cbarg = cbarg }; 3245 isc_refcount_init(&timer->references, 1); 3246 isc_nmhandle_attach(handle, &timer->handle); 3247 3248 r = uv_timer_init(&worker->loop, &timer->timer); 3249 UV_RUNTIME_CHECK(uv_timer_init, r); 3250 3251 uv_handle_set_data((uv_handle_t *)&timer->timer, timer); 3252 3253 *timerp = timer; 3254 } 3255 3256 void 3257 isc_nm_timer_attach(isc_nm_timer_t *timer, isc_nm_timer_t **timerp) { 3258 REQUIRE(timer != NULL); 3259 REQUIRE(timerp != NULL && *timerp == NULL); 3260 3261 isc_refcount_increment(&timer->references); 3262 *timerp = timer; 3263 } 3264 3265 static void 3266 timer_destroy(uv_handle_t *uvhandle) { 3267 isc_nm_timer_t *timer = uv_handle_get_data(uvhandle); 3268 isc_nmhandle_t *handle = timer->handle; 3269 isc_mem_t *mctx = timer->handle->sock->mgr->mctx; 3270 3271 isc_mem_put(mctx, timer, sizeof(*timer)); 3272 3273 isc_nmhandle_detach(&handle); 3274 } 3275 3276 void 3277 isc_nm_timer_detach(isc_nm_timer_t **timerp) { 3278 isc_nm_timer_t *timer = NULL; 3279 isc_nmhandle_t *handle = NULL; 3280 3281 REQUIRE(timerp != NULL && *timerp != NULL); 3282 3283 timer = *timerp; 3284 *timerp = NULL; 3285 3286 handle = timer->handle; 3287 3288 REQUIRE(isc__nm_in_netthread()); 3289 REQUIRE(VALID_NMHANDLE(handle)); 3290 REQUIRE(VALID_NMSOCK(handle->sock)); 3291 3292 if (isc_refcount_decrement(&timer->references) == 1) { 3293 int r = uv_timer_stop(&timer->timer); 3294 UV_RUNTIME_CHECK(uv_timer_stop, r); 3295 uv_close((uv_handle_t *)&timer->timer, timer_destroy); 3296 } 3297 } 3298 3299 static void 3300 timer_cb(uv_timer_t *uvtimer) { 3301 isc_nm_timer_t *timer = uv_handle_get_data((uv_handle_t *)uvtimer); 3302 3303 REQUIRE(timer->cb != NULL); 3304 3305 timer->cb(timer->cbarg, ISC_R_TIMEDOUT); 3306 } 3307 3308 void 3309 isc_nm_timer_start(isc_nm_timer_t *timer, uint64_t timeout) { 3310 int r = uv_timer_start(&timer->timer, timer_cb, timeout, 0); 3311 UV_RUNTIME_CHECK(uv_timer_start, r); 3312 } 3313 3314 void 3315 isc_nm_timer_stop(isc_nm_timer_t *timer) { 3316 int r = uv_timer_stop(&timer->timer); 3317 UV_RUNTIME_CHECK(uv_timer_stop, r); 3318 } 3319 3320 #ifdef NETMGR_TRACE 3321 /* 3322 * Dump all active sockets in netmgr. We output to stderr 3323 * as the logger might be already shut down. 3324 */ 3325 3326 static const char * 3327 nmsocket_type_totext(isc_nmsocket_type type) { 3328 switch (type) { 3329 case isc_nm_udpsocket: 3330 return ("isc_nm_udpsocket"); 3331 case isc_nm_udplistener: 3332 return ("isc_nm_udplistener"); 3333 case isc_nm_tcpsocket: 3334 return ("isc_nm_tcpsocket"); 3335 case isc_nm_tcplistener: 3336 return ("isc_nm_tcplistener"); 3337 case isc_nm_tcpdnslistener: 3338 return ("isc_nm_tcpdnslistener"); 3339 case isc_nm_tcpdnssocket: 3340 return ("isc_nm_tcpdnssocket"); 3341 default: 3342 UNREACHABLE(); 3343 } 3344 } 3345 3346 static void 3347 nmhandle_dump(isc_nmhandle_t *handle) { 3348 fprintf(stderr, "Active handle %p, refs %" PRIuFAST32 "\n", handle, 3349 isc_refcount_current(&handle->references)); 3350 fprintf(stderr, "Created by:\n"); 3351 backtrace_symbols_fd(handle->backtrace, handle->backtrace_size, 3352 STDERR_FILENO); 3353 fprintf(stderr, "\n\n"); 3354 } 3355 3356 static void 3357 nmsocket_dump(isc_nmsocket_t *sock) { 3358 isc_nmhandle_t *handle = NULL; 3359 3360 LOCK(&sock->lock); 3361 fprintf(stderr, "\n=================\n"); 3362 fprintf(stderr, "Active %s socket %p, type %s, refs %" PRIuFAST32 "\n", 3363 atomic_load(&sock->client) ? "client" : "server", sock, 3364 nmsocket_type_totext(sock->type), 3365 isc_refcount_current(&sock->references)); 3366 fprintf(stderr, 3367 "Parent %p, listener %p, server %p, statichandle = " 3368 "%p\n", 3369 sock->parent, sock->listener, sock->server, sock->statichandle); 3370 fprintf(stderr, "Flags:%s%s%s%s%s\n", 3371 atomic_load(&sock->active) ? " active" : "", 3372 atomic_load(&sock->closing) ? " closing" : "", 3373 atomic_load(&sock->destroying) ? " destroying" : "", 3374 atomic_load(&sock->connecting) ? " connecting" : "", 3375 sock->accepting ? " accepting" : ""); 3376 fprintf(stderr, "Created by:\n"); 3377 backtrace_symbols_fd(sock->backtrace, sock->backtrace_size, 3378 STDERR_FILENO); 3379 fprintf(stderr, "\n"); 3380 3381 for (handle = ISC_LIST_HEAD(sock->active_handles); handle != NULL; 3382 handle = ISC_LIST_NEXT(handle, active_link)) 3383 { 3384 static bool first = true; 3385 if (first) { 3386 fprintf(stderr, "Active handles:\n"); 3387 first = false; 3388 } 3389 nmhandle_dump(handle); 3390 } 3391 3392 fprintf(stderr, "\n"); 3393 UNLOCK(&sock->lock); 3394 } 3395 3396 void 3397 isc__nm_dump_active(isc_nm_t *nm) { 3398 isc_nmsocket_t *sock = NULL; 3399 3400 REQUIRE(VALID_NM(nm)); 3401 3402 LOCK(&nm->lock); 3403 for (sock = ISC_LIST_HEAD(nm->active_sockets); sock != NULL; 3404 sock = ISC_LIST_NEXT(sock, active_link)) 3405 { 3406 static bool first = true; 3407 if (first) { 3408 fprintf(stderr, "Outstanding sockets\n"); 3409 first = false; 3410 } 3411 nmsocket_dump(sock); 3412 } 3413 UNLOCK(&nm->lock); 3414 } 3415 #endif 3416