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