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