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