Home | History | Annotate | Line # | Download | only in netmgr
tcpdns.c revision 1.1
      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, &quota,
    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(&quota);
    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