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, "a,
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("a);
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