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