Coverage Report

Created: 2023-06-07 06:23

/src/bind9/lib/isc/netmgr/tcp.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
#include <libgen.h>
15
#include <unistd.h>
16
17
#include <isc/async.h>
18
#include <isc/atomic.h>
19
#include <isc/barrier.h>
20
#include <isc/buffer.h>
21
#include <isc/condition.h>
22
#include <isc/errno.h>
23
#include <isc/log.h>
24
#include <isc/magic.h>
25
#include <isc/mem.h>
26
#include <isc/netmgr.h>
27
#include <isc/quota.h>
28
#include <isc/random.h>
29
#include <isc/refcount.h>
30
#include <isc/region.h>
31
#include <isc/result.h>
32
#include <isc/sockaddr.h>
33
#include <isc/stdtime.h>
34
#include <isc/thread.h>
35
#include <isc/util.h>
36
#include <isc/uv.h>
37
38
#include "../loop_p.h"
39
#include "netmgr-int.h"
40
41
static atomic_uint_fast32_t last_tcpquota_log = 0;
42
43
static bool
44
0
can_log_tcp_quota(void) {
45
0
  isc_stdtime_t last;
46
0
  isc_stdtime_t now = isc_stdtime_now();
47
0
  last = atomic_exchange_relaxed(&last_tcpquota_log, now);
48
0
  if (now != last) {
49
0
    return (true);
50
0
  }
51
52
0
  return (false);
53
0
}
54
55
static isc_result_t
56
tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req);
57
58
static isc_result_t
59
tcp_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req);
60
static void
61
tcp_connect_cb(uv_connect_t *uvreq, int status);
62
static void
63
tcp_stop_cb(uv_handle_t *handle);
64
65
static void
66
tcp_connection_cb(uv_stream_t *server, int status);
67
68
static void
69
tcp_close_cb(uv_handle_t *uvhandle);
70
71
static isc_result_t
72
accept_connection(isc_nmsocket_t *ssock);
73
74
static void
75
quota_accept_cb(void *arg);
76
77
static isc_result_t
78
0
tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
79
0
  isc__networker_t *worker = NULL;
80
0
  isc_result_t result = ISC_R_UNSET;
81
0
  int r;
82
83
0
  REQUIRE(VALID_NMSOCK(sock));
84
0
  REQUIRE(VALID_UVREQ(req));
85
86
0
  REQUIRE(sock->tid == isc_tid());
87
88
0
  worker = sock->worker;
89
90
0
  sock->connecting = true;
91
92
  /* 2 minute timeout */
93
0
  result = isc__nm_socket_connectiontimeout(sock->fd, 120 * 1000);
94
0
  RUNTIME_CHECK(result == ISC_R_SUCCESS);
95
96
0
  r = uv_tcp_init(&worker->loop->loop, &sock->uv_handle.tcp);
97
0
  UV_RUNTIME_CHECK(uv_tcp_init, r);
98
0
  uv_handle_set_data(&sock->uv_handle.handle, sock);
99
100
0
  r = uv_timer_init(&worker->loop->loop, &sock->read_timer);
101
0
  UV_RUNTIME_CHECK(uv_timer_init, r);
102
0
  uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock);
103
104
0
  r = uv_tcp_open(&sock->uv_handle.tcp, sock->fd);
105
0
  if (r != 0) {
106
0
    isc__nm_closesocket(sock->fd);
107
0
    isc__nm_incstats(sock, STATID_OPENFAIL);
108
0
    return (isc_uverr2result(r));
109
0
  }
110
0
  isc__nm_incstats(sock, STATID_OPEN);
111
112
0
  if (req->local.length != 0) {
113
0
    r = uv_tcp_bind(&sock->uv_handle.tcp, &req->local.type.sa, 0);
114
0
    if (r != 0) {
115
0
      isc__nm_incstats(sock, STATID_BINDFAIL);
116
0
      return (isc_uverr2result(r));
117
0
    }
118
0
  }
119
120
0
  isc__nm_set_network_buffers(sock->worker->netmgr,
121
0
            &sock->uv_handle.handle);
122
123
0
  uv_handle_set_data(&req->uv_req.handle, req);
124
0
  r = uv_tcp_connect(&req->uv_req.connect, &sock->uv_handle.tcp,
125
0
         &req->peer.type.sa, tcp_connect_cb);
126
0
  if (r != 0) {
127
0
    isc__nm_incstats(sock, STATID_CONNECTFAIL);
128
0
    return (isc_uverr2result(r));
129
0
  }
130
131
0
  uv_handle_set_data((uv_handle_t *)&sock->read_timer,
132
0
         &req->uv_req.connect);
133
0
  isc__nmsocket_timer_start(sock);
134
135
0
  return (ISC_R_SUCCESS);
136
0
}
137
138
static void
139
0
tcp_connect_cb(uv_connect_t *uvreq, int status) {
140
0
  isc_result_t result = ISC_R_UNSET;
141
0
  isc__nm_uvreq_t *req = NULL;
142
0
  isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)uvreq->handle);
143
0
  struct sockaddr_storage ss;
144
0
  isc__networker_t *worker = NULL;
145
0
  int r;
146
147
0
  REQUIRE(VALID_NMSOCK(sock));
148
0
  REQUIRE(sock->tid == isc_tid());
149
150
0
  worker = sock->worker;
151
152
0
  req = uv_handle_get_data((uv_handle_t *)uvreq);
153
154
0
  REQUIRE(VALID_UVREQ(req));
155
0
  REQUIRE(VALID_NMHANDLE(req->handle));
156
157
0
  INSIST(sock->connecting);
158
159
0
  if (sock->timedout || status == UV_ETIMEDOUT) {
160
    /* Connection timed-out */
161
0
    result = ISC_R_TIMEDOUT;
162
0
    goto error;
163
0
  } else if (isc__nm_closing(worker)) {
164
    /* Network manager shutting down */
165
0
    result = ISC_R_SHUTTINGDOWN;
166
0
    goto error;
167
0
  } else if (isc__nmsocket_closing(sock)) {
168
    /* Connection canceled */
169
0
    result = ISC_R_CANCELED;
170
0
    goto error;
171
0
  } else if (status == UV_EADDRINUSE) {
172
    /*
173
     * On FreeBSD the TCP connect() call sometimes results in a
174
     * spurious transient EADDRINUSE. Try a few more times before
175
     * giving up.
176
     */
177
0
    if (--req->connect_tries > 0) {
178
0
      r = uv_tcp_connect(&req->uv_req.connect,
179
0
             &sock->uv_handle.tcp,
180
0
             &req->peer.type.sa, tcp_connect_cb);
181
0
      if (r != 0) {
182
0
        result = isc_uverr2result(r);
183
0
        goto error;
184
0
      }
185
0
      return;
186
0
    }
187
0
    result = isc_uverr2result(status);
188
0
    goto error;
189
0
  } else if (status != 0) {
190
0
    result = isc_uverr2result(status);
191
0
    goto error;
192
0
  }
193
194
0
  isc__nmsocket_timer_stop(sock);
195
0
  uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock);
196
197
0
  isc__nm_incstats(sock, STATID_CONNECT);
198
0
  r = uv_tcp_getpeername(&sock->uv_handle.tcp, (struct sockaddr *)&ss,
199
0
             &(int){ sizeof(ss) });
200
0
  if (r != 0) {
201
0
    result = isc_uverr2result(r);
202
0
    goto error;
203
0
  }
204
205
0
  sock->connecting = false;
206
0
  sock->connected = true;
207
208
0
  result = isc_sockaddr_fromsockaddr(&sock->peer, (struct sockaddr *)&ss);
209
0
  RUNTIME_CHECK(result == ISC_R_SUCCESS);
210
211
0
  isc__nm_connectcb(sock, req, ISC_R_SUCCESS, false);
212
213
0
  return;
214
0
error:
215
0
  isc__nm_failed_connect_cb(sock, req, result, false);
216
0
}
217
218
void
219
isc_nm_tcpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
220
      isc_nm_cb_t connect_cb, void *connect_cbarg,
221
0
      unsigned int timeout) {
222
0
  isc_result_t result = ISC_R_SUCCESS;
223
0
  isc_nmsocket_t *sock = NULL;
224
0
  isc__nm_uvreq_t *req = NULL;
225
0
  sa_family_t sa_family;
226
0
  isc__networker_t *worker = &mgr->workers[isc_tid()];
227
0
  uv_os_sock_t fd = -1;
228
229
0
  REQUIRE(VALID_NM(mgr));
230
0
  REQUIRE(local != NULL);
231
0
  REQUIRE(peer != NULL);
232
233
0
  if (isc__nm_closing(worker)) {
234
0
    connect_cb(NULL, ISC_R_SHUTTINGDOWN, connect_cbarg);
235
0
    return;
236
0
  }
237
238
0
  sa_family = peer->type.sa.sa_family;
239
240
0
  result = isc__nm_socket(sa_family, SOCK_STREAM, 0, &fd);
241
0
  if (result != ISC_R_SUCCESS) {
242
0
    connect_cb(NULL, result, connect_cbarg);
243
0
    return;
244
0
  }
245
246
0
  sock = isc_mem_get(worker->mctx, sizeof(*sock));
247
0
  isc__nmsocket_init(sock, worker, isc_nm_tcpsocket, local, NULL);
248
249
0
  sock->connect_timeout = timeout;
250
0
  sock->fd = fd;
251
0
  sock->client = true;
252
253
0
  req = isc__nm_uvreq_get(sock);
254
0
  req->cb.connect = connect_cb;
255
0
  req->cbarg = connect_cbarg;
256
0
  req->peer = *peer;
257
0
  req->local = *local;
258
0
  req->handle = isc__nmhandle_get(sock, &req->peer, &sock->iface);
259
260
0
  (void)isc__nm_socket_min_mtu(sock->fd, sa_family);
261
0
  (void)isc__nm_socket_tcp_maxseg(sock->fd, NM_MAXSEG);
262
263
0
  sock->active = true;
264
265
0
  result = tcp_connect_direct(sock, req);
266
0
  if (result != ISC_R_SUCCESS) {
267
0
    sock->active = false;
268
0
    isc__nm_tcp_close(sock);
269
0
    isc__nm_connectcb(sock, req, result, true);
270
0
  }
271
272
  /*
273
   * The sock is now attached to the handle.
274
   */
275
0
  isc__nmsocket_detach(&sock);
276
0
}
277
278
static uv_os_sock_t
279
0
isc__nm_tcp_lb_socket(isc_nm_t *mgr, sa_family_t sa_family) {
280
0
  isc_result_t result;
281
0
  uv_os_sock_t sock;
282
283
0
  result = isc__nm_socket(sa_family, SOCK_STREAM, 0, &sock);
284
0
  RUNTIME_CHECK(result == ISC_R_SUCCESS);
285
286
0
  (void)isc__nm_socket_incoming_cpu(sock);
287
0
  (void)isc__nm_socket_v6only(sock, sa_family);
288
289
  /* FIXME: set mss */
290
291
0
  result = isc__nm_socket_reuse(sock);
292
0
  RUNTIME_CHECK(result == ISC_R_SUCCESS);
293
294
0
  if (mgr->load_balance_sockets) {
295
0
    result = isc__nm_socket_reuse_lb(sock);
296
0
    RUNTIME_CHECK(result == ISC_R_SUCCESS);
297
0
  }
298
299
0
  return (sock);
300
0
}
301
302
static void
303
0
start_tcp_child_job(void *arg) {
304
0
  isc_nmsocket_t *sock = arg;
305
306
0
  REQUIRE(VALID_NMSOCK(sock));
307
0
  REQUIRE(VALID_NMSOCK(sock->parent));
308
0
  REQUIRE(sock->type == isc_nm_tcpsocket);
309
0
  REQUIRE(sock->tid == isc_tid());
310
311
0
  sa_family_t sa_family = sock->iface.type.sa.sa_family;
312
0
  int r, flags = 0;
313
0
  isc_result_t result = ISC_R_UNSET;
314
0
  isc_loop_t *loop = sock->worker->loop;
315
0
  struct sockaddr_storage ss;
316
317
0
  (void)isc__nm_socket_min_mtu(sock->fd, sa_family);
318
0
  (void)isc__nm_socket_tcp_maxseg(sock->fd, NM_MAXSEG);
319
320
0
  r = uv_tcp_init(&loop->loop, &sock->uv_handle.tcp);
321
0
  UV_RUNTIME_CHECK(uv_tcp_init, r);
322
0
  uv_handle_set_data(&sock->uv_handle.handle, sock);
323
  /* This keeps the socket alive after everything else is gone */
324
0
  isc__nmsocket_attach(sock, &(isc_nmsocket_t *){ NULL });
325
326
0
  r = uv_timer_init(&loop->loop, &sock->read_timer);
327
0
  UV_RUNTIME_CHECK(uv_timer_init, r);
328
0
  uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock);
329
330
0
  r = uv_tcp_open(&sock->uv_handle.tcp, sock->fd);
331
0
  if (r < 0) {
332
0
    isc__nm_closesocket(sock->fd);
333
0
    isc__nm_incstats(sock, STATID_OPENFAIL);
334
0
    goto done;
335
0
  }
336
0
  isc__nm_incstats(sock, STATID_OPEN);
337
338
0
  if (sa_family == AF_INET6) {
339
0
    flags = UV_TCP_IPV6ONLY;
340
0
  }
341
342
0
  if (sock->worker->netmgr->load_balance_sockets) {
343
0
    r = isc__nm_tcp_freebind(&sock->uv_handle.tcp,
344
0
           &sock->iface.type.sa, flags);
345
0
    if (r < 0) {
346
0
      isc__nm_incstats(sock, STATID_BINDFAIL);
347
0
      goto done;
348
0
    }
349
0
  } else if (sock->tid == 0) {
350
0
    r = isc__nm_tcp_freebind(&sock->uv_handle.tcp,
351
0
           &sock->iface.type.sa, flags);
352
0
    if (r < 0) {
353
0
      isc__nm_incstats(sock, STATID_BINDFAIL);
354
0
      goto done;
355
0
    }
356
0
    sock->parent->uv_handle.tcp.flags = sock->uv_handle.tcp.flags;
357
0
  } else {
358
    /* The socket is already bound, just copy the flags */
359
0
    sock->uv_handle.tcp.flags = sock->parent->uv_handle.tcp.flags;
360
0
  }
361
362
0
  isc__nm_set_network_buffers(sock->worker->netmgr,
363
0
            &sock->uv_handle.handle);
364
365
  /*
366
   * The callback will run in the same thread uv_listen() was called
367
   * from, so a race with tcp_connection_cb() isn't possible.
368
   */
369
0
  r = uv_listen((uv_stream_t *)&sock->uv_handle.tcp, sock->backlog,
370
0
          tcp_connection_cb);
371
0
  if (r != 0) {
372
0
    isc__nmsocket_log(sock, ISC_LOG_ERROR, "uv_listen failed: %s",
373
0
          isc_result_totext(isc_uverr2result(r)));
374
0
    isc__nm_incstats(sock, STATID_BINDFAIL);
375
0
    goto done;
376
0
  }
377
378
0
  if (sock->tid == 0) {
379
0
    r = uv_tcp_getsockname(&sock->uv_handle.tcp,
380
0
               (struct sockaddr *)&ss,
381
0
               &(int){ sizeof(ss) });
382
0
    if (r != 0) {
383
0
      goto done;
384
0
    }
385
386
0
    result = isc_sockaddr_fromsockaddr(&sock->parent->iface,
387
0
               (struct sockaddr *)&ss);
388
0
    if (result != ISC_R_SUCCESS) {
389
0
      goto done_result;
390
0
    }
391
0
  }
392
393
0
done:
394
0
  result = isc_uverr2result(r);
395
396
0
done_result:
397
0
  if (result != ISC_R_SUCCESS) {
398
0
    sock->pquota = NULL;
399
0
  }
400
401
0
  sock->result = result;
402
403
0
  REQUIRE(!loop->paused);
404
405
0
  if (sock->tid != 0) {
406
0
    isc_barrier_wait(&sock->parent->listen_barrier);
407
0
  }
408
0
}
409
410
static void
411
start_tcp_child(isc_nm_t *mgr, isc_sockaddr_t *iface, isc_nmsocket_t *sock,
412
0
    uv_os_sock_t fd, int tid) {
413
0
  isc_nmsocket_t *csock = &sock->children[tid];
414
0
  isc__networker_t *worker = &mgr->workers[tid];
415
416
0
  isc__nmsocket_init(csock, worker, isc_nm_tcpsocket, iface, sock);
417
0
  csock->accept_cb = sock->accept_cb;
418
0
  csock->accept_cbarg = sock->accept_cbarg;
419
0
  csock->backlog = sock->backlog;
420
421
  /*
422
   * Quota isn't attached, just assigned.
423
   */
424
0
  csock->pquota = sock->pquota;
425
426
0
  if (mgr->load_balance_sockets) {
427
0
    UNUSED(fd);
428
0
    csock->fd = isc__nm_tcp_lb_socket(mgr,
429
0
              iface->type.sa.sa_family);
430
0
  } else {
431
0
    csock->fd = dup(fd);
432
0
  }
433
0
  REQUIRE(csock->fd >= 0);
434
435
0
  if (tid == 0) {
436
0
    start_tcp_child_job(csock);
437
0
  } else {
438
0
    isc_async_run(worker->loop, start_tcp_child_job, csock);
439
0
  }
440
0
}
441
442
isc_result_t
443
isc_nm_listentcp(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface,
444
     isc_nm_accept_cb_t accept_cb, void *accept_cbarg, int backlog,
445
0
     isc_quota_t *quota, isc_nmsocket_t **sockp) {
446
0
  isc_nmsocket_t *sock = NULL;
447
0
  size_t children_size = 0;
448
0
  uv_os_sock_t fd = -1;
449
0
  isc_result_t result = ISC_R_UNSET;
450
0
  isc__networker_t *worker = &mgr->workers[0];
451
452
0
  REQUIRE(VALID_NM(mgr));
453
0
  REQUIRE(isc_tid() == 0);
454
455
0
  if (workers == 0) {
456
0
    workers = mgr->nloops;
457
0
  }
458
0
  REQUIRE(workers <= mgr->nloops);
459
460
0
  sock = isc_mem_get(worker->mctx, sizeof(*sock));
461
0
  isc__nmsocket_init(sock, worker, isc_nm_tcplistener, iface, NULL);
462
463
0
  sock->nchildren = (workers == ISC_NM_LISTEN_ALL) ? (uint32_t)mgr->nloops
464
0
               : workers;
465
0
  children_size = sock->nchildren * sizeof(sock->children[0]);
466
0
  sock->children = isc_mem_getx(worker->mctx, children_size,
467
0
              ISC_MEM_ZERO);
468
469
0
  isc__nmsocket_barrier_init(sock);
470
471
0
  sock->accept_cb = accept_cb;
472
0
  sock->accept_cbarg = accept_cbarg;
473
0
  sock->backlog = backlog;
474
0
  sock->pquota = quota;
475
476
0
  if (!mgr->load_balance_sockets) {
477
0
    fd = isc__nm_tcp_lb_socket(mgr, iface->type.sa.sa_family);
478
0
  }
479
480
0
  start_tcp_child(mgr, iface, sock, fd, 0);
481
0
  result = sock->children[0].result;
482
0
  INSIST(result != ISC_R_UNSET);
483
484
0
  for (size_t i = 1; i < sock->nchildren; i++) {
485
0
    start_tcp_child(mgr, iface, sock, fd, i);
486
0
  }
487
488
0
  isc_barrier_wait(&sock->listen_barrier);
489
490
0
  if (!mgr->load_balance_sockets) {
491
0
    isc__nm_closesocket(fd);
492
0
  }
493
494
  /*
495
   * If any of the child sockets have failed then isc_nm_listentcp
496
   * fails.
497
   */
498
0
  for (size_t i = 1; i < sock->nchildren; i++) {
499
0
    if (result == ISC_R_SUCCESS &&
500
0
        sock->children[i].result != ISC_R_SUCCESS)
501
0
    {
502
0
      result = sock->children[i].result;
503
0
    }
504
0
  }
505
506
0
  if (result != ISC_R_SUCCESS) {
507
0
    sock->active = false;
508
0
    isc__nm_tcp_stoplistening(sock);
509
0
    isc_nmsocket_close(&sock);
510
511
0
    return (result);
512
0
  }
513
514
0
  sock->active = true;
515
516
0
  *sockp = sock;
517
0
  return (ISC_R_SUCCESS);
518
0
}
519
520
static void
521
0
tcp_connection_cb(uv_stream_t *server, int status) {
522
0
  isc_nmsocket_t *ssock = uv_handle_get_data((uv_handle_t *)server);
523
0
  isc_result_t result;
524
525
0
  REQUIRE(ssock->accept_cb != NULL);
526
527
0
  if (status != 0) {
528
0
    result = isc_uverr2result(status);
529
0
    goto done;
530
0
  }
531
532
0
  REQUIRE(VALID_NMSOCK(ssock));
533
0
  REQUIRE(ssock->tid == isc_tid());
534
535
0
  if (isc__nmsocket_closing(ssock)) {
536
0
    result = ISC_R_CANCELED;
537
0
    goto done;
538
0
  }
539
540
  /* Prepare the child socket */
541
0
  isc_nmsocket_t *csock = isc_mem_get(ssock->worker->mctx,
542
0
              sizeof(isc_nmsocket_t));
543
0
  isc__nmsocket_init(csock, ssock->worker, isc_nm_tcpsocket,
544
0
         &ssock->iface, NULL);
545
0
  isc__nmsocket_attach(ssock, &csock->server);
546
547
0
  if (csock->server->pquota != NULL) {
548
0
    result = isc_quota_acquire_cb(csock->server->pquota,
549
0
                &csock->quotacb, quota_accept_cb,
550
0
                csock);
551
0
    if (result == ISC_R_QUOTA) {
552
0
      isc__nm_incstats(ssock, STATID_ACCEPTFAIL);
553
0
      goto done;
554
0
    }
555
0
  }
556
557
0
  result = accept_connection(csock);
558
0
done:
559
0
  isc__nm_accept_connection_log(ssock, result, can_log_tcp_quota());
560
0
}
561
562
static void
563
0
stop_tcp_child_job(void *arg) {
564
0
  isc_nmsocket_t *sock = arg;
565
566
0
  REQUIRE(VALID_NMSOCK(sock));
567
0
  REQUIRE(sock->tid == isc_tid());
568
0
  REQUIRE(sock->parent != NULL);
569
0
  REQUIRE(sock->type == isc_nm_tcpsocket);
570
0
  REQUIRE(!sock->closing);
571
572
0
  sock->active = false;
573
0
  sock->closing = true;
574
575
  /*
576
   * The order of the close operation is important here, the uv_close()
577
   * gets scheduled in the reverse order, so we need to close the timer
578
   * last, so its gone by the time we destroy the socket
579
   */
580
581
  /* 2. close the listening socket */
582
0
  isc__nmsocket_clearcb(sock);
583
0
  isc__nm_stop_reading(sock);
584
0
  uv_close(&sock->uv_handle.handle, tcp_stop_cb);
585
586
  /* 1. close the read timer */
587
0
  isc__nmsocket_timer_stop(sock);
588
0
  uv_close(&sock->read_timer, NULL);
589
590
0
  REQUIRE(!sock->worker->loop->paused);
591
0
  isc_barrier_wait(&sock->parent->stop_barrier);
592
0
}
593
594
static void
595
0
stop_tcp_child(isc_nmsocket_t *sock) {
596
0
  REQUIRE(VALID_NMSOCK(sock));
597
598
0
  if (sock->tid == 0) {
599
0
    stop_tcp_child_job(sock);
600
0
  } else {
601
0
    isc_async_run(sock->worker->loop, stop_tcp_child_job, sock);
602
0
  }
603
0
}
604
605
void
606
0
isc__nm_tcp_stoplistening(isc_nmsocket_t *sock) {
607
0
  REQUIRE(VALID_NMSOCK(sock));
608
0
  REQUIRE(sock->type == isc_nm_tcplistener);
609
0
  REQUIRE(sock->tid == isc_tid());
610
0
  REQUIRE(sock->tid == 0);
611
0
  REQUIRE(!sock->closing);
612
613
0
  sock->closing = true;
614
615
  /* Mark the parent socket inactive */
616
0
  sock->active = false;
617
618
  /* Stop all the other threads' children */
619
0
  for (size_t i = 1; i < sock->nchildren; i++) {
620
0
    stop_tcp_child(&sock->children[i]);
621
0
  }
622
623
  /* Stop the child for the main thread */
624
0
  stop_tcp_child(&sock->children[0]);
625
626
  /* Stop the parent */
627
0
  sock->closed = true;
628
629
0
  isc__nmsocket_prep_destroy(sock);
630
0
}
631
632
static void
633
0
tcp_stop_cb(uv_handle_t *handle) {
634
0
  isc_nmsocket_t *sock = uv_handle_get_data(handle);
635
0
  uv_handle_set_data(handle, NULL);
636
637
0
  REQUIRE(VALID_NMSOCK(sock));
638
0
  REQUIRE(sock->tid == isc_tid());
639
0
  REQUIRE(sock->closing);
640
0
  REQUIRE(sock->type == isc_nm_tcpsocket);
641
0
  REQUIRE(!sock->closed);
642
643
0
  sock->closed = true;
644
645
0
  isc__nm_incstats(sock, STATID_CLOSE);
646
647
0
  isc__nmsocket_detach(&sock);
648
0
}
649
650
void
651
isc__nm_tcp_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result,
652
0
         bool async) {
653
0
  REQUIRE(VALID_NMSOCK(sock));
654
0
  REQUIRE(result != ISC_R_SUCCESS);
655
656
0
  isc__nmsocket_timer_stop(sock);
657
0
  isc__nm_stop_reading(sock);
658
659
0
  if (sock->recv_cb != NULL) {
660
0
    isc__nm_uvreq_t *req = isc__nm_get_read_req(sock, NULL);
661
0
    isc__nmsocket_clearcb(sock);
662
0
    isc__nm_readcb(sock, req, result, async);
663
0
  }
664
665
0
  isc__nmsocket_prep_destroy(sock);
666
0
}
667
668
void
669
0
isc__nm_tcp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
670
0
  isc_nmsocket_t *sock;
671
0
  isc_nm_t *netmgr;
672
0
  isc_result_t result;
673
674
0
  REQUIRE(VALID_NMHANDLE(handle));
675
0
  REQUIRE(VALID_NMSOCK(handle->sock));
676
677
0
  sock = handle->sock;
678
0
  netmgr = sock->worker->netmgr;
679
680
0
  REQUIRE(sock->type == isc_nm_tcpsocket);
681
0
  REQUIRE(sock->statichandle == handle);
682
683
0
  sock->recv_cb = cb;
684
0
  sock->recv_cbarg = cbarg;
685
686
  /* Initialize the timer */
687
0
  if (sock->read_timeout == 0) {
688
0
    sock->read_timeout =
689
0
      sock->keepalive
690
0
        ? atomic_load_relaxed(&netmgr->keepalive)
691
0
        : atomic_load_relaxed(&netmgr->idle);
692
0
  }
693
694
0
  if (isc__nmsocket_closing(sock)) {
695
0
    result = ISC_R_CANCELED;
696
0
    goto failure;
697
0
  }
698
699
0
  result = isc__nm_start_reading(sock);
700
0
  if (result != ISC_R_SUCCESS) {
701
0
    goto failure;
702
0
  }
703
704
0
  if (!sock->manual_read_timer) {
705
0
    isc__nmsocket_timer_start(sock);
706
0
  }
707
708
0
  return;
709
0
failure:
710
0
  sock->reading = true;
711
0
  isc__nm_tcp_failed_read_cb(sock, result, true);
712
0
}
713
714
void
715
0
isc__nm_tcp_read_stop(isc_nmhandle_t *handle) {
716
0
  REQUIRE(VALID_NMHANDLE(handle));
717
0
  REQUIRE(VALID_NMSOCK(handle->sock));
718
719
0
  isc_nmsocket_t *sock = handle->sock;
720
721
0
  isc__nmsocket_timer_stop(sock);
722
0
  isc__nm_stop_reading(sock);
723
724
0
  return;
725
0
}
726
727
void
728
0
isc__nm_tcp_read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) {
729
0
  isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)stream);
730
0
  isc__nm_uvreq_t *req = NULL;
731
0
  isc_nm_t *netmgr = NULL;
732
733
0
  REQUIRE(VALID_NMSOCK(sock));
734
0
  REQUIRE(sock->tid == isc_tid());
735
0
  REQUIRE(buf != NULL);
736
737
0
  netmgr = sock->worker->netmgr;
738
739
0
  if (isc__nmsocket_closing(sock)) {
740
0
    isc__nm_tcp_failed_read_cb(sock, ISC_R_CANCELED, false);
741
0
    goto free;
742
0
  }
743
744
0
  if (nread < 0) {
745
0
    if (nread != UV_EOF) {
746
0
      isc__nm_incstats(sock, STATID_RECVFAIL);
747
0
    }
748
749
0
    isc__nm_tcp_failed_read_cb(sock, isc_uverr2result(nread),
750
0
             false);
751
752
0
    goto free;
753
0
  }
754
755
0
  req = isc__nm_get_read_req(sock, NULL);
756
757
  /*
758
   * The callback will be called synchronously because the
759
   * result is ISC_R_SUCCESS, so we don't need to retain
760
   * the buffer
761
   */
762
0
  req->uvbuf.base = buf->base;
763
0
  req->uvbuf.len = nread;
764
765
0
  if (!sock->client) {
766
0
    sock->read_timeout =
767
0
      sock->keepalive
768
0
        ? atomic_load_relaxed(&netmgr->keepalive)
769
0
        : atomic_load_relaxed(&netmgr->idle);
770
0
  }
771
772
0
  isc__nm_readcb(sock, req, ISC_R_SUCCESS, false);
773
774
  /* The readcb could have paused the reading */
775
0
  if (sock->reading && !sock->manual_read_timer) {
776
    /* The timer will be updated */
777
0
    isc__nmsocket_timer_restart(sock);
778
0
  }
779
780
0
free:
781
0
  if (nread < 0) {
782
    /*
783
     * The buffer may be a null buffer on error.
784
     */
785
0
    if (buf->base == NULL && buf->len == 0) {
786
0
      return;
787
0
    }
788
0
  }
789
790
0
  isc__nm_free_uvbuf(sock, buf);
791
0
}
792
793
/*
794
 * This is called after we get a quota_accept_cb() callback.
795
 */
796
static void
797
0
tcpaccept_cb(void *arg) {
798
0
  isc_nmsocket_t *csock = arg;
799
0
  isc_nmsocket_t *ssock = csock->server;
800
801
0
  REQUIRE(VALID_NMSOCK(csock));
802
0
  REQUIRE(csock->tid == isc_tid());
803
804
0
  isc_result_t result = accept_connection(csock);
805
0
  isc__nm_accept_connection_log(ssock, result, can_log_tcp_quota());
806
0
  isc__nmsocket_detach(&csock);
807
0
}
808
809
static void
810
0
quota_accept_cb(void *arg) {
811
0
  isc_nmsocket_t *csock = arg;
812
0
  isc_nmsocket_t *ssock = csock->server;
813
814
0
  REQUIRE(VALID_NMSOCK(csock));
815
816
  /*
817
   * This needs to be asynchronous, because the quota might have been
818
   * released by a different child socket.
819
   */
820
0
  if (csock->tid == isc_tid()) {
821
0
    isc_result_t result = accept_connection(csock);
822
0
    isc__nm_accept_connection_log(ssock, result,
823
0
                can_log_tcp_quota());
824
0
  } else {
825
0
    isc__nmsocket_attach(csock, &(isc_nmsocket_t *){ NULL });
826
0
    isc_async_run(csock->worker->loop, tcpaccept_cb, csock);
827
0
  }
828
0
}
829
830
static isc_result_t
831
0
accept_connection(isc_nmsocket_t *csock) {
832
0
  int r;
833
0
  isc_result_t result;
834
0
  struct sockaddr_storage ss;
835
0
  isc_sockaddr_t local;
836
0
  isc_nmhandle_t *handle = NULL;
837
838
0
  REQUIRE(VALID_NMSOCK(csock));
839
0
  REQUIRE(VALID_NMSOCK(csock->server));
840
0
  REQUIRE(csock->tid == isc_tid());
841
842
0
  csock->accepting = true;
843
0
  csock->accept_cb = csock->server->accept_cb;
844
0
  csock->accept_cbarg = csock->server->accept_cbarg;
845
0
  csock->recv_cb = csock->server->recv_cb;
846
0
  csock->recv_cbarg = csock->server->recv_cbarg;
847
0
  csock->read_timeout = atomic_load_relaxed(&csock->worker->netmgr->init);
848
849
0
  r = uv_tcp_init(&csock->worker->loop->loop, &csock->uv_handle.tcp);
850
0
  UV_RUNTIME_CHECK(uv_tcp_init, r);
851
0
  uv_handle_set_data(&csock->uv_handle.handle, csock);
852
853
0
  r = uv_timer_init(&csock->worker->loop->loop, &csock->read_timer);
854
0
  UV_RUNTIME_CHECK(uv_timer_init, r);
855
0
  uv_handle_set_data((uv_handle_t *)&csock->read_timer, csock);
856
857
  /*
858
   * We need to initialize the tcp and timer before failing because
859
   * isc__nm_tcp_close() can't handle uninitalized TCP nmsocket.
860
   */
861
0
  if (isc__nmsocket_closing(csock)) {
862
0
    result = ISC_R_CANCELED;
863
0
    goto failure;
864
0
  }
865
866
0
  r = uv_accept(&csock->server->uv_handle.stream,
867
0
          &csock->uv_handle.stream);
868
0
  if (r != 0) {
869
0
    result = isc_uverr2result(r);
870
0
    goto failure;
871
0
  }
872
873
0
  r = uv_tcp_getpeername(&csock->uv_handle.tcp, (struct sockaddr *)&ss,
874
0
             &(int){ sizeof(ss) });
875
0
  if (r != 0) {
876
0
    result = isc_uverr2result(r);
877
0
    goto failure;
878
0
  }
879
880
0
  result = isc_sockaddr_fromsockaddr(&csock->peer,
881
0
             (struct sockaddr *)&ss);
882
0
  if (result != ISC_R_SUCCESS) {
883
0
    goto failure;
884
0
  }
885
886
0
  r = uv_tcp_getsockname(&csock->uv_handle.tcp, (struct sockaddr *)&ss,
887
0
             &(int){ sizeof(ss) });
888
0
  if (r != 0) {
889
0
    result = isc_uverr2result(r);
890
0
    goto failure;
891
0
  }
892
893
0
  result = isc_sockaddr_fromsockaddr(&local, (struct sockaddr *)&ss);
894
0
  if (result != ISC_R_SUCCESS) {
895
0
    goto failure;
896
0
  }
897
898
0
  handle = isc__nmhandle_get(csock, NULL, &local);
899
900
0
  result = csock->accept_cb(handle, ISC_R_SUCCESS, csock->accept_cbarg);
901
0
  if (result != ISC_R_SUCCESS) {
902
0
    isc_nmhandle_detach(&handle);
903
0
    goto failure;
904
0
  }
905
906
0
  csock->accepting = false;
907
908
0
  isc__nm_incstats(csock, STATID_ACCEPT);
909
910
  /*
911
   * The acceptcb needs to attach to the handle if it wants to keep the
912
   * connection alive
913
   */
914
0
  isc_nmhandle_detach(&handle);
915
916
0
  if (csock->statichandle != NULL) {
917
0
    INSIST(csock->recv_cb != NULL);
918
0
  }
919
920
  /*
921
   * sock is now attached to the handle.
922
   */
923
0
  isc__nmsocket_detach(&csock);
924
925
0
  return (ISC_R_SUCCESS);
926
927
0
failure:
928
0
  csock->active = false;
929
0
  csock->accepting = false;
930
931
0
  if (result != ISC_R_NOTCONNECTED) {
932
    /* IGNORE: The client disconnected before we could accept */
933
0
    isc__nmsocket_log(csock, ISC_LOG_ERROR,
934
0
          "Accepting TCP connection failed: %s",
935
0
          isc_result_totext(result));
936
0
  }
937
938
0
  isc__nmsocket_prep_destroy(csock);
939
940
0
  isc__nmsocket_detach(&csock);
941
942
0
  return (result);
943
0
}
944
945
static void
946
tcp_send(isc_nmhandle_t *handle, const isc_region_t *region, isc_nm_cb_t cb,
947
0
   void *cbarg, const bool dnsmsg) {
948
0
  REQUIRE(VALID_NMHANDLE(handle));
949
0
  REQUIRE(VALID_NMSOCK(handle->sock));
950
951
0
  isc_nmsocket_t *sock = handle->sock;
952
0
  isc_result_t result;
953
0
  isc__nm_uvreq_t *uvreq = NULL;
954
0
  isc_nm_t *netmgr = sock->worker->netmgr;
955
956
0
  REQUIRE(sock->type == isc_nm_tcpsocket);
957
0
  REQUIRE(sock->tid == isc_tid());
958
959
0
  uvreq = isc__nm_uvreq_get(sock);
960
0
  if (dnsmsg) {
961
0
    *(uint16_t *)uvreq->tcplen = htons(region->length);
962
0
  }
963
0
  uvreq->uvbuf.base = (char *)region->base;
964
0
  uvreq->uvbuf.len = region->length;
965
966
0
  isc_nmhandle_attach(handle, &uvreq->handle);
967
968
0
  uvreq->cb.send = cb;
969
0
  uvreq->cbarg = cbarg;
970
971
0
  if (sock->write_timeout == 0) {
972
0
    sock->write_timeout =
973
0
      sock->keepalive
974
0
        ? atomic_load_relaxed(&netmgr->keepalive)
975
0
        : atomic_load_relaxed(&netmgr->idle);
976
0
  }
977
978
0
  result = tcp_send_direct(sock, uvreq);
979
0
  if (result != ISC_R_SUCCESS) {
980
0
    isc__nm_incstats(sock, STATID_SENDFAIL);
981
0
    isc__nm_failed_send_cb(sock, uvreq, result, true);
982
0
  }
983
984
0
  return;
985
0
}
986
987
void
988
isc__nm_tcp_send(isc_nmhandle_t *handle, const isc_region_t *region,
989
0
     isc_nm_cb_t cb, void *cbarg) {
990
0
  tcp_send(handle, region, cb, cbarg, false);
991
0
}
992
993
void
994
isc__nm_tcp_senddns(isc_nmhandle_t *handle, const isc_region_t *region,
995
0
        isc_nm_cb_t cb, void *cbarg) {
996
0
  tcp_send(handle, region, cb, cbarg, true);
997
0
}
998
999
static void
1000
0
tcp_send_cb(uv_write_t *req, int status) {
1001
0
  isc__nm_uvreq_t *uvreq = (isc__nm_uvreq_t *)req->data;
1002
0
  isc_nmsocket_t *sock = NULL;
1003
1004
0
  REQUIRE(VALID_UVREQ(uvreq));
1005
0
  REQUIRE(VALID_NMSOCK(uvreq->sock));
1006
1007
0
  sock = uvreq->sock;
1008
1009
0
  isc_nm_timer_stop(uvreq->timer);
1010
0
  isc_nm_timer_detach(&uvreq->timer);
1011
1012
0
  if (status < 0) {
1013
0
    isc__nm_incstats(sock, STATID_SENDFAIL);
1014
0
    isc__nm_failed_send_cb(sock, uvreq, isc_uverr2result(status),
1015
0
               false);
1016
0
    return;
1017
0
  }
1018
1019
0
  isc__nm_sendcb(sock, uvreq, ISC_R_SUCCESS, false);
1020
0
}
1021
1022
static isc_result_t
1023
0
tcp_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
1024
0
  REQUIRE(VALID_NMSOCK(sock));
1025
0
  REQUIRE(VALID_UVREQ(req));
1026
0
  REQUIRE(sock->tid == isc_tid());
1027
0
  REQUIRE(sock->type == isc_nm_tcpsocket);
1028
1029
0
  int r;
1030
0
  uv_buf_t bufs[2] = { { 0 }, { 0 } }; /* ugly, but required for old GCC
1031
            versions */
1032
0
  size_t nbufs = 1;
1033
1034
0
  if (isc__nmsocket_closing(sock)) {
1035
0
    return (ISC_R_CANCELED);
1036
0
  }
1037
1038
  /* Check if we are not trying to send a DNS message */
1039
0
  if (*(uint16_t *)req->tcplen == 0) {
1040
0
    bufs[0].base = req->uvbuf.base;
1041
0
    bufs[0].len = req->uvbuf.len;
1042
1043
0
    r = uv_try_write(&sock->uv_handle.stream, bufs, nbufs);
1044
1045
0
    if (r == (int)(bufs[0].len)) {
1046
      /* Wrote everything */
1047
0
      isc__nm_sendcb(sock, req, ISC_R_SUCCESS, true);
1048
0
      return (ISC_R_SUCCESS);
1049
0
    } else if (r > 0) {
1050
0
      bufs[0].base += (size_t)r;
1051
0
      bufs[0].len -= (size_t)r;
1052
0
    } else if (!(r == UV_ENOSYS || r == UV_EAGAIN)) {
1053
0
      return (isc_uverr2result(r));
1054
0
    }
1055
0
  } else {
1056
0
    nbufs = 2;
1057
0
    bufs[0].base = req->tcplen;
1058
0
    bufs[0].len = 2;
1059
0
    bufs[1].base = req->uvbuf.base;
1060
0
    bufs[1].len = req->uvbuf.len;
1061
1062
0
    r = uv_try_write(&sock->uv_handle.stream, bufs, nbufs);
1063
1064
0
    if (r == (int)(bufs[0].len + bufs[1].len)) {
1065
      /* Wrote everything */
1066
0
      isc__nm_sendcb(sock, req, ISC_R_SUCCESS, true);
1067
0
      return (ISC_R_SUCCESS);
1068
0
    } else if (r == 1) {
1069
      /* Partial write of DNSMSG length */
1070
0
      bufs[0].base = req->tcplen + 1;
1071
0
      bufs[0].len = 1;
1072
0
    } else if (r > 0) {
1073
      /* Partial write of DNSMSG */
1074
0
      nbufs = 1;
1075
0
      bufs[0].base = req->uvbuf.base + (r - 2);
1076
0
      bufs[0].len = req->uvbuf.len - (r - 2);
1077
0
    } else if (!(r == UV_ENOSYS || r == UV_EAGAIN)) {
1078
0
      return (isc_uverr2result(r));
1079
0
    }
1080
0
  }
1081
1082
0
  r = uv_write(&req->uv_req.write, &sock->uv_handle.stream, bufs, nbufs,
1083
0
         tcp_send_cb);
1084
0
  if (r < 0) {
1085
0
    return (isc_uverr2result(r));
1086
0
  }
1087
1088
0
  isc_nm_timer_create(req->handle, isc__nmsocket_writetimeout_cb, req,
1089
0
          &req->timer);
1090
0
  if (sock->write_timeout > 0) {
1091
0
    isc_nm_timer_start(req->timer, sock->write_timeout);
1092
0
  }
1093
1094
0
  return (ISC_R_SUCCESS);
1095
0
}
1096
1097
static void
1098
0
tcp_close_sock(isc_nmsocket_t *sock) {
1099
0
  REQUIRE(VALID_NMSOCK(sock));
1100
0
  REQUIRE(sock->tid == isc_tid());
1101
0
  REQUIRE(sock->closing);
1102
0
  REQUIRE(!sock->closed);
1103
1104
0
  sock->closed = true;
1105
0
  sock->connected = false;
1106
1107
0
  isc__nm_incstats(sock, STATID_CLOSE);
1108
1109
0
  if (sock->server != NULL) {
1110
0
    if (sock->server->pquota != NULL) {
1111
0
      isc_quota_release(sock->server->pquota);
1112
0
    }
1113
0
    isc__nmsocket_detach(&sock->server);
1114
0
  }
1115
1116
0
  isc__nmsocket_prep_destroy(sock);
1117
0
}
1118
1119
static void
1120
0
tcp_close_cb(uv_handle_t *handle) {
1121
0
  isc_nmsocket_t *sock = uv_handle_get_data(handle);
1122
0
  uv_handle_set_data(handle, NULL);
1123
1124
0
  tcp_close_sock(sock);
1125
0
}
1126
1127
void
1128
0
isc__nm_tcp_close(isc_nmsocket_t *sock) {
1129
0
  REQUIRE(VALID_NMSOCK(sock));
1130
0
  REQUIRE(sock->type == isc_nm_tcpsocket);
1131
0
  REQUIRE(!isc__nmsocket_active(sock));
1132
0
  REQUIRE(sock->tid == isc_tid());
1133
0
  REQUIRE(sock->parent == NULL);
1134
0
  REQUIRE(!sock->closing);
1135
1136
0
  sock->closing = true;
1137
1138
  /*
1139
   * The order of the close operation is important here, the uv_close()
1140
   * gets scheduled in the reverse order, so we need to close the timer
1141
   * last, so its gone by the time we destroy the socket
1142
   */
1143
1144
0
  if (!uv_is_closing(&sock->uv_handle.handle)) {
1145
    /* Normal order of operation */
1146
1147
    /* 2. close the socket + destroy the socket in callback */
1148
0
    isc__nmsocket_clearcb(sock);
1149
0
    isc__nm_stop_reading(sock);
1150
0
    uv_close(&sock->uv_handle.handle, tcp_close_cb);
1151
1152
    /* 1. close the timer */
1153
0
    isc__nmsocket_timer_stop(sock);
1154
0
    uv_close((uv_handle_t *)&sock->read_timer, NULL);
1155
0
  } else {
1156
    /* The socket was already closed elsewhere */
1157
1158
    /* 1. close the timer + destroy the socket in callback */
1159
0
    isc__nmsocket_timer_stop(sock);
1160
0
    uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock);
1161
0
    uv_close((uv_handle_t *)&sock->read_timer, tcp_close_cb);
1162
0
  }
1163
0
}
1164
1165
static void
1166
0
tcp_close_connect_cb(uv_handle_t *handle) {
1167
0
  isc_nmsocket_t *sock = uv_handle_get_data(handle);
1168
1169
0
  REQUIRE(VALID_NMSOCK(sock));
1170
1171
0
  REQUIRE(sock->tid == isc_tid());
1172
1173
0
  isc__nmsocket_prep_destroy(sock);
1174
0
  isc__nmsocket_detach(&sock);
1175
0
}
1176
1177
void
1178
0
isc__nm_tcp_shutdown(isc_nmsocket_t *sock) {
1179
0
  REQUIRE(VALID_NMSOCK(sock));
1180
0
  REQUIRE(sock->tid == isc_tid());
1181
0
  REQUIRE(sock->type == isc_nm_tcpsocket);
1182
1183
  /*
1184
   * If the socket is active, mark it inactive and
1185
   * continue. If it isn't active, stop now.
1186
   */
1187
0
  if (!sock->active) {
1188
0
    return;
1189
0
  }
1190
0
  sock->active = false;
1191
1192
0
  INSIST(!sock->accepting);
1193
1194
0
  if (sock->connecting) {
1195
0
    isc_nmsocket_t *tsock = NULL;
1196
0
    isc__nmsocket_attach(sock, &tsock);
1197
0
    uv_close(&sock->uv_handle.handle, tcp_close_connect_cb);
1198
0
    return;
1199
0
  }
1200
1201
  /* There's a handle attached to the socket (from accept or connect) */
1202
0
  if (sock->statichandle) {
1203
0
    isc__nm_failed_read_cb(sock, ISC_R_SHUTTINGDOWN, false);
1204
0
    return;
1205
0
  }
1206
1207
  /* Destroy the non-listening socket */
1208
0
  if (sock->parent == NULL) {
1209
0
    isc__nmsocket_prep_destroy(sock);
1210
0
    return;
1211
0
  }
1212
1213
  /* Destroy the listening socket if on the same loop */
1214
0
  if (sock->tid == sock->parent->tid) {
1215
0
    isc__nmsocket_prep_destroy(sock->parent);
1216
0
  }
1217
0
}
1218
1219
void
1220
0
isc__nmhandle_tcp_set_manual_timer(isc_nmhandle_t *handle, const bool manual) {
1221
0
  isc_nmsocket_t *sock;
1222
1223
0
  REQUIRE(VALID_NMHANDLE(handle));
1224
0
  sock = handle->sock;
1225
0
  REQUIRE(VALID_NMSOCK(sock));
1226
0
  REQUIRE(sock->type == isc_nm_tcpsocket);
1227
0
  REQUIRE(sock->tid == isc_tid());
1228
0
  REQUIRE(!sock->reading);
1229
1230
0
  sock->manual_read_timer = manual;
1231
0
}