Coverage Report

Created: 2023-11-19 06:22

/src/bind9/lib/isc/netmgr/netmgr.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 <assert.h>
15
#include <inttypes.h>
16
#include <unistd.h>
17
18
#include <isc/async.h>
19
#include <isc/atomic.h>
20
#include <isc/backtrace.h>
21
#include <isc/barrier.h>
22
#include <isc/buffer.h>
23
#include <isc/condition.h>
24
#include <isc/errno.h>
25
#include <isc/job.h>
26
#include <isc/list.h>
27
#include <isc/log.h>
28
#include <isc/loop.h>
29
#include <isc/magic.h>
30
#include <isc/mem.h>
31
#include <isc/netmgr.h>
32
#include <isc/quota.h>
33
#include <isc/random.h>
34
#include <isc/refcount.h>
35
#include <isc/region.h>
36
#include <isc/result.h>
37
#include <isc/sockaddr.h>
38
#include <isc/stats.h>
39
#include <isc/strerr.h>
40
#include <isc/thread.h>
41
#include <isc/tid.h>
42
#include <isc/tls.h>
43
#include <isc/util.h>
44
#include <isc/uv.h>
45
46
#include "../loop_p.h"
47
#include "netmgr-int.h"
48
#include "openssl_shim.h"
49
50
/*%
51
 * Shortcut index arrays to get access to statistics counters.
52
 */
53
54
static const isc_statscounter_t udp4statsindex[] = {
55
  isc_sockstatscounter_udp4open,
56
  isc_sockstatscounter_udp4openfail,
57
  isc_sockstatscounter_udp4close,
58
  isc_sockstatscounter_udp4bindfail,
59
  isc_sockstatscounter_udp4connectfail,
60
  isc_sockstatscounter_udp4connect,
61
  -1,
62
  -1,
63
  isc_sockstatscounter_udp4sendfail,
64
  isc_sockstatscounter_udp4recvfail,
65
  isc_sockstatscounter_udp4active
66
};
67
68
static const isc_statscounter_t udp6statsindex[] = {
69
  isc_sockstatscounter_udp6open,
70
  isc_sockstatscounter_udp6openfail,
71
  isc_sockstatscounter_udp6close,
72
  isc_sockstatscounter_udp6bindfail,
73
  isc_sockstatscounter_udp6connectfail,
74
  isc_sockstatscounter_udp6connect,
75
  -1,
76
  -1,
77
  isc_sockstatscounter_udp6sendfail,
78
  isc_sockstatscounter_udp6recvfail,
79
  isc_sockstatscounter_udp6active
80
};
81
82
static const isc_statscounter_t tcp4statsindex[] = {
83
  isc_sockstatscounter_tcp4open,        isc_sockstatscounter_tcp4openfail,
84
  isc_sockstatscounter_tcp4close,       isc_sockstatscounter_tcp4bindfail,
85
  isc_sockstatscounter_tcp4connectfail, isc_sockstatscounter_tcp4connect,
86
  isc_sockstatscounter_tcp4acceptfail,  isc_sockstatscounter_tcp4accept,
87
  isc_sockstatscounter_tcp4sendfail,    isc_sockstatscounter_tcp4recvfail,
88
  isc_sockstatscounter_tcp4active
89
};
90
91
static const isc_statscounter_t tcp6statsindex[] = {
92
  isc_sockstatscounter_tcp6open,        isc_sockstatscounter_tcp6openfail,
93
  isc_sockstatscounter_tcp6close,       isc_sockstatscounter_tcp6bindfail,
94
  isc_sockstatscounter_tcp6connectfail, isc_sockstatscounter_tcp6connect,
95
  isc_sockstatscounter_tcp6acceptfail,  isc_sockstatscounter_tcp6accept,
96
  isc_sockstatscounter_tcp6sendfail,    isc_sockstatscounter_tcp6recvfail,
97
  isc_sockstatscounter_tcp6active
98
};
99
100
static void
101
nmsocket_maybe_destroy(isc_nmsocket_t *sock FLARG);
102
static void
103
nmhandle_free(isc_nmsocket_t *sock, isc_nmhandle_t *handle);
104
105
/*%<
106
 * Issue a 'handle closed' callback on the socket.
107
 */
108
109
static void
110
shutdown_walk_cb(uv_handle_t *handle, void *arg);
111
112
static void
113
0
networker_teardown(void *arg) {
114
0
  isc__networker_t *worker = arg;
115
0
  isc_loop_t *loop = worker->loop;
116
117
0
  worker->shuttingdown = true;
118
119
0
  isc__netmgr_log(worker->netmgr, ISC_LOG_DEBUG(1),
120
0
      "Shutting down network manager worker on loop %p(%d)",
121
0
      loop, isc_tid());
122
123
0
  uv_walk(&loop->loop, shutdown_walk_cb, NULL);
124
125
0
  isc__networker_detach(&worker);
126
0
}
127
128
static void
129
0
netmgr_teardown(void *arg) {
130
0
  isc_nm_t *netmgr = (void *)arg;
131
132
0
  if (atomic_compare_exchange_strong_acq_rel(&netmgr->shuttingdown,
133
0
               &(bool){ false }, true))
134
0
  {
135
0
    isc__netmgr_log(netmgr, ISC_LOG_DEBUG(1),
136
0
        "Shutting down network manager");
137
0
  }
138
0
}
139
140
#if HAVE_DECL_UV_UDP_LINUX_RECVERR
141
#define MINIMAL_UV_VERSION UV_VERSION(1, 42, 0)
142
#elif HAVE_DECL_UV_UDP_MMSG_FREE
143
#define MINIMAL_UV_VERSION UV_VERSION(1, 40, 0)
144
#elif HAVE_DECL_UV_UDP_RECVMMSG
145
#define MAXIMAL_UV_VERSION UV_VERSION(1, 39, 99)
146
#define MINIMAL_UV_VERSION UV_VERSION(1, 37, 0)
147
#else
148
0
#define MAXIMAL_UV_VERSION UV_VERSION(1, 34, 99)
149
0
#define MINIMAL_UV_VERSION UV_VERSION(1, 34, 0)
150
#endif
151
152
void
153
0
isc_netmgr_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr, isc_nm_t **netmgrp) {
154
0
  isc_nm_t *netmgr = NULL;
155
156
0
#ifdef MAXIMAL_UV_VERSION
157
0
  if (uv_version() > MAXIMAL_UV_VERSION) {
158
0
    FATAL_ERROR("libuv version too new: running with libuv %s "
159
0
          "when compiled with libuv %s will lead to "
160
0
          "libuv failures",
161
0
          uv_version_string(), UV_VERSION_STRING);
162
0
  }
163
0
#endif /* MAXIMAL_UV_VERSION */
164
165
0
  if (uv_version() < MINIMAL_UV_VERSION) {
166
0
    FATAL_ERROR("libuv version too old: running with libuv %s "
167
0
          "when compiled with libuv %s will lead to "
168
0
          "libuv failures",
169
0
          uv_version_string(), UV_VERSION_STRING);
170
0
  }
171
172
0
  netmgr = isc_mem_get(mctx, sizeof(*netmgr));
173
0
  *netmgr = (isc_nm_t){
174
0
    .loopmgr = loopmgr,
175
0
    .nloops = isc_loopmgr_nloops(loopmgr),
176
0
  };
177
178
0
  isc_mem_attach(mctx, &netmgr->mctx);
179
0
  isc_mutex_init(&netmgr->lock);
180
0
  isc_refcount_init(&netmgr->references, 1);
181
0
  atomic_init(&netmgr->maxudp, 0);
182
0
  atomic_init(&netmgr->shuttingdown, false);
183
0
  atomic_init(&netmgr->recv_tcp_buffer_size, 0);
184
0
  atomic_init(&netmgr->send_tcp_buffer_size, 0);
185
0
  atomic_init(&netmgr->recv_udp_buffer_size, 0);
186
0
  atomic_init(&netmgr->send_udp_buffer_size, 0);
187
0
#if HAVE_SO_REUSEPORT_LB
188
0
  netmgr->load_balance_sockets = true;
189
#else
190
  netmgr->load_balance_sockets = false;
191
#endif
192
193
  /*
194
   * Default TCP timeout values.
195
   * May be updated by isc_nm_tcptimeouts().
196
   */
197
0
  atomic_init(&netmgr->init, 30000);
198
0
  atomic_init(&netmgr->idle, 30000);
199
0
  atomic_init(&netmgr->keepalive, 30000);
200
0
  atomic_init(&netmgr->advertised, 30000);
201
202
0
  netmgr->workers = isc_mem_cget(mctx, netmgr->nloops,
203
0
               sizeof(netmgr->workers[0]));
204
205
0
  isc_loopmgr_teardown(loopmgr, netmgr_teardown, netmgr);
206
207
0
  netmgr->magic = NM_MAGIC;
208
209
0
  for (size_t i = 0; i < netmgr->nloops; i++) {
210
0
    isc_loop_t *loop = isc_loop_get(netmgr->loopmgr, i);
211
0
    isc__networker_t *worker = &netmgr->workers[i];
212
213
0
    *worker = (isc__networker_t){
214
0
      .recvbuf = isc_mem_get(loop->mctx,
215
0
                 ISC_NETMGR_RECVBUF_SIZE),
216
0
      .active_sockets = ISC_LIST_INITIALIZER,
217
0
    };
218
219
0
    isc_nm_attach(netmgr, &worker->netmgr);
220
221
0
    isc_mem_attach(loop->mctx, &worker->mctx);
222
223
0
    isc_mempool_create(worker->mctx, sizeof(isc__nm_uvreq_t),
224
0
           &worker->uvreq_pool);
225
0
    isc_mempool_setfreemax(worker->uvreq_pool, ISC_NM_UVREQS_MAX);
226
227
0
    isc_loop_attach(loop, &worker->loop);
228
0
    isc_loop_teardown(loop, networker_teardown, worker);
229
0
    isc_refcount_init(&worker->references, 1);
230
0
  }
231
232
0
  *netmgrp = netmgr;
233
0
}
234
235
/*
236
 * Free the resources of the network manager.
237
 */
238
static void
239
0
nm_destroy(isc_nm_t **mgr0) {
240
0
  REQUIRE(VALID_NM(*mgr0));
241
242
0
  isc_nm_t *mgr = *mgr0;
243
0
  *mgr0 = NULL;
244
245
0
  isc_refcount_destroy(&mgr->references);
246
247
0
  mgr->magic = 0;
248
249
0
  if (mgr->stats != NULL) {
250
0
    isc_stats_detach(&mgr->stats);
251
0
  }
252
253
0
  isc_mutex_destroy(&mgr->lock);
254
255
0
  isc_mem_cput(mgr->mctx, mgr->workers, mgr->nloops,
256
0
         sizeof(mgr->workers[0]));
257
0
  isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(*mgr));
258
0
}
259
260
void
261
0
isc_nm_attach(isc_nm_t *mgr, isc_nm_t **dst) {
262
0
  REQUIRE(VALID_NM(mgr));
263
0
  REQUIRE(dst != NULL && *dst == NULL);
264
265
0
  isc_refcount_increment(&mgr->references);
266
267
0
  *dst = mgr;
268
0
}
269
270
void
271
0
isc_nm_detach(isc_nm_t **mgr0) {
272
0
  isc_nm_t *mgr = NULL;
273
274
0
  REQUIRE(mgr0 != NULL);
275
0
  REQUIRE(VALID_NM(*mgr0));
276
277
0
  mgr = *mgr0;
278
0
  *mgr0 = NULL;
279
280
0
  if (isc_refcount_decrement(&mgr->references) == 1) {
281
0
    nm_destroy(&mgr);
282
0
  }
283
0
}
284
285
void
286
0
isc_netmgr_destroy(isc_nm_t **netmgrp) {
287
0
  isc_nm_t *mgr = NULL;
288
289
0
  REQUIRE(VALID_NM(*netmgrp));
290
291
0
  mgr = *netmgrp;
292
0
  *netmgrp = NULL;
293
294
0
  REQUIRE(isc_refcount_decrement(&mgr->references) == 1);
295
0
  nm_destroy(&mgr);
296
0
}
297
298
void
299
0
isc_nm_maxudp(isc_nm_t *mgr, uint32_t maxudp) {
300
0
  REQUIRE(VALID_NM(mgr));
301
302
0
  atomic_store_relaxed(&mgr->maxudp, maxudp);
303
0
}
304
305
void
306
0
isc_nmhandle_setwritetimeout(isc_nmhandle_t *handle, uint64_t write_timeout) {
307
0
  REQUIRE(VALID_NMHANDLE(handle));
308
0
  REQUIRE(VALID_NMSOCK(handle->sock));
309
0
  REQUIRE(handle->sock->tid == isc_tid());
310
311
0
  switch (handle->sock->type) {
312
0
  case isc_nm_tcpsocket:
313
0
  case isc_nm_udpsocket:
314
0
    handle->sock->write_timeout = write_timeout;
315
0
    break;
316
0
  case isc_nm_tlssocket:
317
0
    isc__nmhandle_tls_setwritetimeout(handle, write_timeout);
318
0
    break;
319
0
  case isc_nm_streamdnssocket:
320
0
    isc__nmhandle_streamdns_setwritetimeout(handle, write_timeout);
321
0
    break;
322
0
  default:
323
0
    UNREACHABLE();
324
0
    break;
325
0
  }
326
0
}
327
328
void
329
isc_nm_settimeouts(isc_nm_t *mgr, uint32_t init, uint32_t idle,
330
0
       uint32_t keepalive, uint32_t advertised) {
331
0
  REQUIRE(VALID_NM(mgr));
332
333
0
  atomic_store_relaxed(&mgr->init, init);
334
0
  atomic_store_relaxed(&mgr->idle, idle);
335
0
  atomic_store_relaxed(&mgr->keepalive, keepalive);
336
0
  atomic_store_relaxed(&mgr->advertised, advertised);
337
0
}
338
339
void
340
isc_nm_setnetbuffers(isc_nm_t *mgr, int32_t recv_tcp, int32_t send_tcp,
341
0
         int32_t recv_udp, int32_t send_udp) {
342
0
  REQUIRE(VALID_NM(mgr));
343
344
0
  atomic_store_relaxed(&mgr->recv_tcp_buffer_size, recv_tcp);
345
0
  atomic_store_relaxed(&mgr->send_tcp_buffer_size, send_tcp);
346
0
  atomic_store_relaxed(&mgr->recv_udp_buffer_size, recv_udp);
347
0
  atomic_store_relaxed(&mgr->send_udp_buffer_size, send_udp);
348
0
}
349
350
bool
351
0
isc_nm_getloadbalancesockets(isc_nm_t *mgr) {
352
0
  REQUIRE(VALID_NM(mgr));
353
354
0
  return (mgr->load_balance_sockets);
355
0
}
356
357
void
358
0
isc_nm_setloadbalancesockets(isc_nm_t *mgr, ISC_ATTR_UNUSED bool enabled) {
359
0
  REQUIRE(VALID_NM(mgr));
360
361
0
#if HAVE_SO_REUSEPORT_LB
362
0
  mgr->load_balance_sockets = enabled;
363
0
#endif
364
0
}
365
366
void
367
isc_nm_gettimeouts(isc_nm_t *mgr, uint32_t *initial, uint32_t *idle,
368
0
       uint32_t *keepalive, uint32_t *advertised) {
369
0
  REQUIRE(VALID_NM(mgr));
370
371
0
  SET_IF_NOT_NULL(initial, atomic_load_relaxed(&mgr->init));
372
373
0
  SET_IF_NOT_NULL(idle, atomic_load_relaxed(&mgr->idle));
374
375
0
  SET_IF_NOT_NULL(keepalive, atomic_load_relaxed(&mgr->keepalive));
376
377
0
  SET_IF_NOT_NULL(advertised, atomic_load_relaxed(&mgr->advertised));
378
0
}
379
380
bool
381
0
isc__nmsocket_active(isc_nmsocket_t *sock) {
382
0
  REQUIRE(VALID_NMSOCK(sock));
383
384
0
  return (sock->active);
385
0
}
386
387
void
388
0
isc___nmsocket_attach(isc_nmsocket_t *sock, isc_nmsocket_t **target FLARG) {
389
0
  REQUIRE(VALID_NMSOCK(sock));
390
0
  REQUIRE(target != NULL && *target == NULL);
391
392
0
  isc_nmsocket_t *rsock = NULL;
393
394
0
  if (sock->parent != NULL) {
395
0
    rsock = sock->parent;
396
0
    INSIST(rsock->parent == NULL); /* sanity check */
397
0
  } else {
398
0
    rsock = sock;
399
0
  }
400
401
0
  NETMGR_TRACE_LOG("isc__nmsocket_attach():%p->references = %" PRIuFAST32
402
0
       "\n",
403
0
       rsock, isc_refcount_current(&rsock->references) + 1);
404
405
0
  isc_refcount_increment0(&rsock->references);
406
407
0
  *target = sock;
408
0
}
409
410
/*
411
 * Free all resources inside a socket (including its children if any).
412
 */
413
static void
414
0
nmsocket_cleanup(void *arg) {
415
0
  isc_nmsocket_t *sock = arg;
416
417
0
  REQUIRE(VALID_NMSOCK(sock));
418
0
  REQUIRE(!isc__nmsocket_active(sock));
419
420
0
  isc_nmhandle_t *handle = NULL;
421
0
  isc__networker_t *worker = sock->worker;
422
423
0
  isc_refcount_destroy(&sock->references);
424
425
0
  isc__nm_decstats(sock, STATID_ACTIVE);
426
427
0
  REQUIRE(!sock->destroying);
428
0
  sock->destroying = true;
429
430
0
  if (sock->parent == NULL && sock->children != NULL) {
431
    /*
432
     * We shouldn't be here unless there are no active handles,
433
     * so we can clean up and free the children.
434
     */
435
0
    for (size_t i = 0; i < sock->nchildren; i++) {
436
0
      isc_refcount_decrementz(&sock->children[i].references);
437
0
      nmsocket_cleanup(&sock->children[i]);
438
0
    }
439
440
    /*
441
     * Now free them.
442
     */
443
0
    isc_mem_cput(sock->worker->mctx, sock->children,
444
0
           sock->nchildren, sizeof(*sock));
445
0
    sock->children = NULL;
446
0
    sock->nchildren = 0;
447
0
  }
448
449
0
  sock->statichandle = NULL;
450
451
0
  if (sock->outerhandle != NULL) {
452
0
    isc_nmhandle_detach(&sock->outerhandle);
453
0
  }
454
455
0
  if (sock->outer != NULL) {
456
0
    isc__nmsocket_detach(&sock->outer);
457
0
  }
458
459
0
  while ((handle = ISC_LIST_HEAD(sock->inactive_handles)) != NULL) {
460
0
    ISC_LIST_DEQUEUE(sock->inactive_handles, handle, inactive_link);
461
0
    nmhandle_free(sock, handle);
462
0
  }
463
464
0
  INSIST(sock->server == NULL);
465
0
  sock->pquota = NULL;
466
467
0
  isc__nm_tls_cleanup_data(sock);
468
0
#if HAVE_LIBNGHTTP2
469
0
  isc__nm_http_cleanup_data(sock);
470
0
#endif
471
0
  isc__nm_streamdns_cleanup_data(sock);
472
473
0
  if (sock->barriers_initialised) {
474
0
    isc_barrier_destroy(&sock->listen_barrier);
475
0
    isc_barrier_destroy(&sock->stop_barrier);
476
0
  }
477
478
0
  sock->magic = 0;
479
480
  /* Don't free child socket */
481
0
  if (sock->parent == NULL) {
482
0
    REQUIRE(sock->tid == isc_tid());
483
484
0
    ISC_LIST_UNLINK(worker->active_sockets, sock, active_link);
485
486
0
    isc_mem_put(worker->mctx, sock, sizeof(*sock));
487
0
  }
488
489
0
  isc__networker_detach(&worker);
490
0
}
491
492
static bool
493
0
nmsocket_has_active_handles(isc_nmsocket_t *sock) {
494
0
  if (!ISC_LIST_EMPTY(sock->active_handles)) {
495
0
    return (true);
496
0
  }
497
498
0
  if (sock->children != NULL) {
499
0
    for (size_t i = 0; i < sock->nchildren; i++) {
500
0
      isc_nmsocket_t *csock = &sock->children[i];
501
0
      if (!ISC_LIST_EMPTY(csock->active_handles)) {
502
0
        return (true);
503
0
      }
504
0
    }
505
0
  }
506
507
0
  return (false);
508
0
}
509
510
static void
511
0
nmsocket_maybe_destroy(isc_nmsocket_t *sock FLARG) {
512
0
  NETMGR_TRACE_LOG("%s():%p->references = %" PRIuFAST32 "\n", __func__,
513
0
       sock, isc_refcount_current(&sock->references));
514
515
0
  if (sock->parent != NULL) {
516
    /*
517
     * This is a child socket and cannot be destroyed except
518
     * as a side effect of destroying the parent, so let's go
519
     * see if the parent is ready to be destroyed.
520
     */
521
0
    nmsocket_maybe_destroy(sock->parent FLARG_PASS);
522
0
    return;
523
0
  }
524
525
0
  REQUIRE(!sock->destroying);
526
0
  REQUIRE(!sock->active);
527
528
0
  if (!sock->closed) {
529
0
    return;
530
0
  }
531
532
0
  if (isc_refcount_current(&sock->references) != 0) {
533
    /*
534
     * Using such check is valid only if we don't use
535
     * isc_refcount_increment0() on the same variable.
536
     */
537
0
    return;
538
0
  }
539
540
0
  NETMGR_TRACE_LOG("%s:%p->statichandle = %p\n", __func__, sock,
541
0
       sock->statichandle);
542
543
  /*
544
   * This is a parent socket (or a standalone). See whether the
545
   * children have active handles before deciding whether to
546
   * accept destruction.
547
   */
548
0
  if (sock->statichandle == NULL && nmsocket_has_active_handles(sock)) {
549
0
    return;
550
0
  }
551
552
0
  if (sock->tid == isc_tid()) {
553
0
    nmsocket_cleanup(sock);
554
0
  } else {
555
0
    isc_async_run(sock->worker->loop, nmsocket_cleanup, sock);
556
0
  }
557
0
}
558
559
void
560
0
isc___nmsocket_prep_destroy(isc_nmsocket_t *sock FLARG) {
561
0
  REQUIRE(sock->parent == NULL);
562
563
0
  NETMGR_TRACE_LOG("isc___nmsocket_prep_destroy():%p->references = "
564
0
       "%" PRIuFAST32 "\n",
565
0
       sock, isc_refcount_current(&sock->references));
566
567
  /*
568
   * The final external reference to the socket is gone. We can try
569
   * destroying the socket, but we have to wait for all the inflight
570
   * handles to finish first.
571
   */
572
0
  sock->active = false;
573
574
  /*
575
   * If the socket has children, they have been marked inactive by the
576
   * shutdown uv_walk
577
   */
578
579
  /*
580
   * If we're here then we already stopped listening; otherwise
581
   * we'd have a hanging reference from the listening process.
582
   *
583
   * If it's a regular socket we may need to close it.
584
   */
585
0
  if (!sock->closing && !sock->closed) {
586
0
    switch (sock->type) {
587
0
    case isc_nm_udpsocket:
588
0
      isc__nm_udp_close(sock);
589
0
      return;
590
0
    case isc_nm_tcpsocket:
591
0
      isc__nm_tcp_close(sock);
592
0
      return;
593
0
    case isc_nm_streamdnssocket:
594
0
      isc__nm_streamdns_close(sock);
595
0
      return;
596
0
    case isc_nm_tlssocket:
597
0
      isc__nm_tls_close(sock);
598
0
      return;
599
0
#if HAVE_LIBNGHTTP2
600
0
    case isc_nm_httpsocket:
601
0
      isc__nm_http_close(sock);
602
0
      return;
603
0
#endif
604
0
    default:
605
0
      break;
606
0
    }
607
0
  }
608
609
0
  nmsocket_maybe_destroy(sock FLARG_PASS);
610
0
}
611
612
void
613
0
isc___nmsocket_detach(isc_nmsocket_t **sockp FLARG) {
614
0
  REQUIRE(sockp != NULL && *sockp != NULL);
615
0
  REQUIRE(VALID_NMSOCK(*sockp));
616
617
0
  isc_nmsocket_t *sock = *sockp, *rsock = NULL;
618
0
  *sockp = NULL;
619
620
  /*
621
   * If the socket is a part of a set (a child socket) we are
622
   * counting references for the whole set at the parent.
623
   */
624
0
  if (sock->parent != NULL) {
625
0
    rsock = sock->parent;
626
0
    INSIST(rsock->parent == NULL); /* Sanity check */
627
0
  } else {
628
0
    rsock = sock;
629
0
  }
630
631
0
  NETMGR_TRACE_LOG("isc__nmsocket_detach():%p->references = %" PRIuFAST32
632
0
       "\n",
633
0
       rsock, isc_refcount_current(&rsock->references) - 1);
634
635
0
  if (isc_refcount_decrement(&rsock->references) == 1) {
636
0
    isc___nmsocket_prep_destroy(rsock FLARG_PASS);
637
0
  }
638
0
}
639
640
void
641
0
isc_nmsocket_close(isc_nmsocket_t **sockp) {
642
0
  REQUIRE(sockp != NULL);
643
0
  REQUIRE(VALID_NMSOCK(*sockp));
644
0
  REQUIRE((*sockp)->type == isc_nm_udplistener ||
645
0
    (*sockp)->type == isc_nm_tcplistener ||
646
0
    (*sockp)->type == isc_nm_streamdnslistener ||
647
0
    (*sockp)->type == isc_nm_tlslistener ||
648
0
    (*sockp)->type == isc_nm_httplistener);
649
650
0
  isc__nmsocket_detach(sockp);
651
0
}
652
653
void
654
isc___nmsocket_init(isc_nmsocket_t *sock, isc__networker_t *worker,
655
        isc_nmsocket_type type, isc_sockaddr_t *iface,
656
0
        isc_nmsocket_t *parent FLARG) {
657
0
  uint16_t family;
658
659
0
  REQUIRE(sock != NULL);
660
0
  REQUIRE(worker != NULL);
661
662
0
  *sock = (isc_nmsocket_t){
663
0
    .type = type,
664
0
    .tid = worker->loop->tid,
665
0
    .fd = -1,
666
0
    .inactive_handles = ISC_LIST_INITIALIZER,
667
0
    .result = ISC_R_UNSET,
668
0
    .active_handles = ISC_LIST_INITIALIZER,
669
0
    .active_link = ISC_LINK_INITIALIZER,
670
0
    .active = true,
671
0
  };
672
673
0
  if (iface != NULL) {
674
0
    family = iface->type.sa.sa_family;
675
0
    sock->iface = *iface;
676
0
  } else {
677
0
    family = AF_UNSPEC;
678
0
  }
679
680
0
  if (parent) {
681
0
    sock->parent = parent;
682
0
  } else {
683
0
    ISC_LIST_APPEND(worker->active_sockets, sock, active_link);
684
0
  }
685
686
#if ISC_NETMGR_TRACE
687
  sock->backtrace_size = isc_backtrace(sock->backtrace, TRACE_SIZE);
688
#endif
689
690
0
  isc__networker_attach(worker, &sock->worker);
691
0
  sock->uv_handle.handle.data = sock;
692
693
0
  switch (type) {
694
0
  case isc_nm_udpsocket:
695
0
  case isc_nm_udplistener:
696
0
    switch (family) {
697
0
    case AF_INET:
698
0
      sock->statsindex = udp4statsindex;
699
0
      break;
700
0
    case AF_INET6:
701
0
      sock->statsindex = udp6statsindex;
702
0
      break;
703
0
    case AF_UNSPEC:
704
      /*
705
       * Route sockets are AF_UNSPEC, and don't
706
       * have stats counters.
707
       */
708
0
      break;
709
0
    default:
710
0
      UNREACHABLE();
711
0
    }
712
0
    break;
713
0
  case isc_nm_tcpsocket:
714
0
  case isc_nm_tcplistener:
715
0
  case isc_nm_httpsocket:
716
0
  case isc_nm_httplistener:
717
0
    switch (family) {
718
0
    case AF_INET:
719
0
      sock->statsindex = tcp4statsindex;
720
0
      break;
721
0
    case AF_INET6:
722
0
      sock->statsindex = tcp6statsindex;
723
0
      break;
724
0
    default:
725
0
      UNREACHABLE();
726
0
    }
727
0
    break;
728
0
  default:
729
0
    break;
730
0
  }
731
732
0
  isc_refcount_init(&sock->references, 1);
733
734
0
  memset(&sock->tlsstream, 0, sizeof(sock->tlsstream));
735
736
0
  NETMGR_TRACE_LOG("isc__nmsocket_init():%p->references = %" PRIuFAST32
737
0
       "\n",
738
0
       sock, isc_refcount_current(&sock->references));
739
740
0
#if HAVE_LIBNGHTTP2
741
0
  isc__nm_http_initsocket(sock);
742
0
#endif
743
744
0
  sock->magic = NMSOCK_MAGIC;
745
746
0
  isc__nm_incstats(sock, STATID_ACTIVE);
747
0
}
748
749
void
750
0
isc__nmsocket_clearcb(isc_nmsocket_t *sock) {
751
0
  REQUIRE(VALID_NMSOCK(sock));
752
0
  REQUIRE(sock->tid == isc_tid());
753
754
0
  sock->recv_cb = NULL;
755
0
  sock->recv_cbarg = NULL;
756
0
  sock->accept_cb = NULL;
757
0
  sock->accept_cbarg = NULL;
758
0
  sock->connect_cb = NULL;
759
0
  sock->connect_cbarg = NULL;
760
0
}
761
762
void
763
0
isc__nm_free_uvbuf(isc_nmsocket_t *sock, const uv_buf_t *buf) {
764
0
  REQUIRE(VALID_NMSOCK(sock));
765
766
0
  REQUIRE(buf->base == sock->worker->recvbuf);
767
768
0
  sock->worker->recvbuf_inuse = false;
769
0
}
770
771
static isc_nmhandle_t *
772
0
alloc_handle(isc_nmsocket_t *sock) {
773
0
  isc_nmhandle_t *handle = isc_mem_get(sock->worker->mctx,
774
0
               sizeof(isc_nmhandle_t));
775
776
0
  *handle = (isc_nmhandle_t){
777
0
    .magic = NMHANDLE_MAGIC,
778
0
    .active_link = ISC_LINK_INITIALIZER,
779
0
    .inactive_link = ISC_LINK_INITIALIZER,
780
0
  };
781
0
  isc_refcount_init(&handle->references, 1);
782
783
0
  return (handle);
784
0
}
785
786
static isc_nmhandle_t *
787
0
dequeue_handle(isc_nmsocket_t *sock) {
788
0
#if !__SANITIZE_ADDRESS__ && !__SANITIZE_THREAD__
789
0
  isc_nmhandle_t *handle = ISC_LIST_HEAD(sock->inactive_handles);
790
0
  if (handle != NULL) {
791
0
    ISC_LIST_DEQUEUE(sock->inactive_handles, handle, inactive_link);
792
793
0
    sock->inactive_handles_cur--;
794
795
0
    isc_refcount_init(&handle->references, 1);
796
0
    INSIST(VALID_NMHANDLE(handle));
797
0
    return (handle);
798
0
  }
799
#else
800
  INSIST(ISC_LIST_EMPTY(sock->inactive_handles));
801
#endif /* !__SANITIZE_ADDRESS__ && !__SANITIZE_THREAD__ */
802
0
  return (NULL);
803
0
}
804
805
isc_nmhandle_t *
806
isc___nmhandle_get(isc_nmsocket_t *sock, isc_sockaddr_t const *peer,
807
0
       isc_sockaddr_t const *local FLARG) {
808
0
  REQUIRE(VALID_NMSOCK(sock));
809
810
0
  isc_nmhandle_t *handle = dequeue_handle(sock);
811
0
  if (handle == NULL) {
812
0
    handle = alloc_handle(sock);
813
0
  }
814
815
0
  NETMGR_TRACE_LOG(
816
0
    "isc__nmhandle_get():handle %p->references = %" PRIuFAST32 "\n",
817
0
    handle, isc_refcount_current(&handle->references));
818
819
0
  isc___nmsocket_attach(sock, &handle->sock FLARG_PASS);
820
821
#if ISC_NETMGR_TRACE
822
  handle->backtrace_size = isc_backtrace(handle->backtrace, TRACE_SIZE);
823
#endif
824
825
0
  if (peer != NULL) {
826
0
    handle->peer = *peer;
827
0
  } else {
828
0
    handle->peer = sock->peer;
829
0
  }
830
831
0
  if (local != NULL) {
832
0
    handle->local = *local;
833
0
  } else {
834
0
    handle->local = sock->iface;
835
0
  }
836
837
0
  ISC_LIST_APPEND(sock->active_handles, handle, active_link);
838
839
0
  switch (sock->type) {
840
0
  case isc_nm_udpsocket:
841
0
    if (!sock->client) {
842
0
      break;
843
0
    }
844
0
    FALLTHROUGH;
845
0
  case isc_nm_tcpsocket:
846
0
  case isc_nm_tlssocket:
847
0
    INSIST(sock->statichandle == NULL);
848
849
    /*
850
     * statichandle must be assigned, not attached;
851
     * otherwise, if a handle was detached elsewhere
852
     * it could never reach 0 references, and the
853
     * handle and socket would never be freed.
854
     */
855
0
    sock->statichandle = handle;
856
0
    break;
857
0
  default:
858
0
    break;
859
0
  }
860
861
0
#if HAVE_LIBNGHTTP2
862
0
  if (sock->type == isc_nm_httpsocket && sock->h2.session) {
863
0
    isc__nm_httpsession_attach(sock->h2.session,
864
0
             &handle->httpsession);
865
0
  }
866
0
#endif
867
868
0
  return (handle);
869
0
}
870
871
bool
872
0
isc_nmhandle_is_stream(isc_nmhandle_t *handle) {
873
0
  REQUIRE(VALID_NMHANDLE(handle));
874
875
0
  return (handle->sock->type == isc_nm_tcpsocket ||
876
0
    handle->sock->type == isc_nm_tlssocket ||
877
0
    handle->sock->type == isc_nm_httpsocket ||
878
0
    handle->sock->type == isc_nm_streamdnssocket);
879
0
}
880
881
static void
882
0
nmhandle_free(isc_nmsocket_t *sock, isc_nmhandle_t *handle) {
883
0
  handle->magic = 0;
884
885
0
  if (handle->dofree != NULL) {
886
0
    handle->dofree(handle->opaque);
887
0
  }
888
889
0
  isc_mem_put(sock->worker->mctx, handle, sizeof(*handle));
890
0
}
891
892
static void
893
0
nmhandle__destroy(isc_nmhandle_t *handle) {
894
0
  isc_nmsocket_t *sock = handle->sock;
895
0
  handle->sock = NULL;
896
897
#if defined(__SANITIZE_ADDRESS__) || defined(__SANITIZE_THREAD__)
898
  nmhandle_free(sock, handle);
899
#else
900
0
  if (sock->active &&
901
0
      sock->inactive_handles_cur < sock->inactive_handles_max)
902
0
  {
903
0
    sock->inactive_handles_cur++;
904
0
    ISC_LIST_APPEND(sock->inactive_handles, handle, inactive_link);
905
0
  } else {
906
0
    nmhandle_free(sock, handle);
907
0
  }
908
0
#endif
909
910
0
  isc__nmsocket_detach(&sock);
911
0
}
912
913
static void
914
0
isc__nm_closehandle_job(void *arg) {
915
0
  isc_nmhandle_t *handle = arg;
916
0
  isc_nmsocket_t *sock = handle->sock;
917
918
0
  sock->closehandle_cb(sock);
919
920
0
  nmhandle__destroy(handle);
921
0
}
922
923
static void
924
0
nmhandle_destroy(isc_nmhandle_t *handle) {
925
0
  isc_nmsocket_t *sock = handle->sock;
926
927
0
  if (handle->doreset != NULL) {
928
0
    handle->doreset(handle->opaque);
929
0
  }
930
931
0
#if HAVE_LIBNGHTTP2
932
0
  if (sock->type == isc_nm_httpsocket && handle->httpsession != NULL) {
933
0
    isc__nm_httpsession_detach(&handle->httpsession);
934
0
  }
935
0
#endif
936
937
0
  if (handle == sock->statichandle) {
938
    /* statichandle is assigned, not attached. */
939
0
    sock->statichandle = NULL;
940
0
  }
941
942
0
  ISC_LIST_UNLINK(sock->active_handles, handle, active_link);
943
944
0
  if (sock->closehandle_cb == NULL) {
945
0
    nmhandle__destroy(handle);
946
0
    return;
947
0
  }
948
949
  /*
950
   * If the socket has a callback configured for that (e.g.,
951
   * to perform cleanup after request processing), call it
952
   * now asynchronously.
953
   */
954
0
  isc_job_run(sock->worker->loop, &handle->job, isc__nm_closehandle_job,
955
0
        handle);
956
0
}
957
958
#if ISC_NETMGR_TRACE
959
ISC_REFCOUNT_TRACE_IMPL(isc_nmhandle, nmhandle_destroy)
960
#else
961
ISC_REFCOUNT_IMPL(isc_nmhandle, nmhandle_destroy);
962
#endif
963
964
void *
965
0
isc_nmhandle_getdata(isc_nmhandle_t *handle) {
966
0
  REQUIRE(VALID_NMHANDLE(handle));
967
968
0
  return (handle->opaque);
969
0
}
970
971
void
972
isc_nmhandle_setdata(isc_nmhandle_t *handle, void *arg,
973
0
         isc_nm_opaquecb_t doreset, isc_nm_opaquecb_t dofree) {
974
0
  REQUIRE(VALID_NMHANDLE(handle));
975
976
0
  handle->opaque = arg;
977
0
  handle->doreset = doreset;
978
0
  handle->dofree = dofree;
979
0
}
980
981
void
982
isc__nm_failed_send_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req,
983
0
           isc_result_t eresult, bool async) {
984
0
  REQUIRE(VALID_NMSOCK(sock));
985
0
  REQUIRE(VALID_UVREQ(req));
986
987
0
  if (req->cb.send != NULL) {
988
0
    isc__nm_sendcb(sock, req, eresult, async);
989
0
  } else {
990
0
    isc__nm_uvreq_put(&req);
991
0
  }
992
0
}
993
994
void
995
isc__nm_failed_connect_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req,
996
0
        isc_result_t eresult, bool async) {
997
0
  REQUIRE(VALID_NMSOCK(sock));
998
0
  REQUIRE(VALID_UVREQ(req));
999
0
  REQUIRE(sock->tid == isc_tid());
1000
0
  REQUIRE(req->cb.connect != NULL);
1001
0
  REQUIRE(sock->connecting);
1002
1003
0
  sock->connecting = false;
1004
1005
0
  isc__nm_incstats(sock, STATID_CONNECTFAIL);
1006
1007
0
  isc__nmsocket_timer_stop(sock);
1008
0
  uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock);
1009
1010
0
  isc__nmsocket_clearcb(sock);
1011
0
  isc__nm_connectcb(sock, req, eresult, async);
1012
1013
0
  isc__nmsocket_prep_destroy(sock);
1014
0
}
1015
1016
void
1017
0
isc__nm_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result, bool async) {
1018
0
  REQUIRE(VALID_NMSOCK(sock));
1019
0
  UNUSED(async);
1020
0
  switch (sock->type) {
1021
0
  case isc_nm_udpsocket:
1022
0
    isc__nm_udp_failed_read_cb(sock, result, async);
1023
0
    return;
1024
0
  case isc_nm_tcpsocket:
1025
0
    isc__nm_tcp_failed_read_cb(sock, result, async);
1026
0
    return;
1027
0
  case isc_nm_tlssocket:
1028
0
    isc__nm_tls_failed_read_cb(sock, result, async);
1029
0
    return;
1030
0
  case isc_nm_streamdnssocket:
1031
0
    isc__nm_streamdns_failed_read_cb(sock, result, async);
1032
0
    return;
1033
0
  default:
1034
0
    UNREACHABLE();
1035
0
  }
1036
0
}
1037
1038
void
1039
0
isc__nmsocket_connecttimeout_cb(uv_timer_t *timer) {
1040
0
  uv_connect_t *uvreq = uv_handle_get_data((uv_handle_t *)timer);
1041
0
  isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)uvreq->handle);
1042
0
  isc__nm_uvreq_t *req = uv_handle_get_data((uv_handle_t *)uvreq);
1043
1044
0
  REQUIRE(VALID_NMSOCK(sock));
1045
0
  REQUIRE(sock->tid == isc_tid());
1046
0
  REQUIRE(VALID_UVREQ(req));
1047
0
  REQUIRE(VALID_NMHANDLE(req->handle));
1048
0
  REQUIRE(sock->connecting);
1049
1050
0
  isc__nmsocket_timer_stop(sock);
1051
1052
  /*
1053
   * Mark the connection as timed out and shutdown the socket.
1054
   */
1055
0
  REQUIRE(!sock->timedout);
1056
0
  sock->timedout = true;
1057
0
  isc__nmsocket_shutdown(sock);
1058
0
}
1059
1060
void
1061
isc__nm_accept_connection_log(isc_nmsocket_t *sock, isc_result_t result,
1062
0
            bool can_log_quota) {
1063
0
  int level;
1064
1065
0
  switch (result) {
1066
0
  case ISC_R_SUCCESS:
1067
0
  case ISC_R_NOCONN:
1068
0
    return;
1069
0
  case ISC_R_QUOTA:
1070
0
  case ISC_R_SOFTQUOTA:
1071
0
    if (!can_log_quota) {
1072
0
      return;
1073
0
    }
1074
0
    level = ISC_LOG_INFO;
1075
0
    break;
1076
0
  case ISC_R_NOTCONNECTED:
1077
0
    level = ISC_LOG_INFO;
1078
0
    break;
1079
0
  default:
1080
0
    level = ISC_LOG_ERROR;
1081
0
  }
1082
1083
0
  isc__nmsocket_log(sock, level, "Accepting TCP connection failed: %s",
1084
0
        isc_result_totext(result));
1085
0
}
1086
1087
void
1088
0
isc__nmsocket_writetimeout_cb(void *data, isc_result_t eresult) {
1089
0
  isc__nm_uvreq_t *req = data;
1090
0
  isc_nmsocket_t *sock = NULL;
1091
1092
0
  REQUIRE(eresult == ISC_R_TIMEDOUT);
1093
0
  REQUIRE(VALID_UVREQ(req));
1094
0
  REQUIRE(VALID_NMSOCK(req->sock));
1095
1096
0
  sock = req->sock;
1097
1098
0
  isc__nmsocket_reset(sock);
1099
0
}
1100
1101
void
1102
0
isc__nmsocket_readtimeout_cb(uv_timer_t *timer) {
1103
0
  isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)timer);
1104
1105
0
  REQUIRE(VALID_NMSOCK(sock));
1106
0
  REQUIRE(sock->tid == isc_tid());
1107
1108
0
  if (sock->client) {
1109
0
    uv_timer_stop(timer);
1110
1111
0
    if (sock->recv_cb != NULL) {
1112
0
      isc__nm_uvreq_t *req = isc__nm_get_read_req(sock, NULL);
1113
0
      isc__nm_readcb(sock, req, ISC_R_TIMEDOUT, false);
1114
0
    }
1115
1116
0
    if (!isc__nmsocket_timer_running(sock)) {
1117
0
      isc__nmsocket_clearcb(sock);
1118
0
      isc__nm_failed_read_cb(sock, ISC_R_TIMEDOUT, false);
1119
0
    }
1120
0
  } else {
1121
0
    isc__nm_failed_read_cb(sock, ISC_R_TIMEDOUT, false);
1122
0
  }
1123
0
}
1124
1125
void
1126
0
isc__nmsocket_timer_restart(isc_nmsocket_t *sock) {
1127
0
  REQUIRE(VALID_NMSOCK(sock));
1128
1129
0
  switch (sock->type) {
1130
0
  case isc_nm_tlssocket:
1131
0
    isc__nmsocket_tls_timer_restart(sock);
1132
0
    return;
1133
0
  case isc_nm_streamdnssocket:
1134
0
    isc__nmsocket_streamdns_timer_restart(sock);
1135
0
    return;
1136
0
  default:
1137
0
    break;
1138
0
  }
1139
1140
0
  if (uv_is_closing((uv_handle_t *)&sock->read_timer)) {
1141
0
    return;
1142
0
  }
1143
1144
0
  if (sock->connecting) {
1145
0
    int r;
1146
1147
0
    if (sock->connect_timeout == 0) {
1148
0
      return;
1149
0
    }
1150
1151
0
    r = uv_timer_start(&sock->read_timer,
1152
0
           isc__nmsocket_connecttimeout_cb,
1153
0
           sock->connect_timeout + 10, 0);
1154
0
    UV_RUNTIME_CHECK(uv_timer_start, r);
1155
1156
0
  } else {
1157
0
    int r;
1158
1159
0
    if (sock->read_timeout == 0) {
1160
0
      return;
1161
0
    }
1162
1163
0
    r = uv_timer_start(&sock->read_timer,
1164
0
           isc__nmsocket_readtimeout_cb,
1165
0
           sock->read_timeout, 0);
1166
0
    UV_RUNTIME_CHECK(uv_timer_start, r);
1167
0
  }
1168
0
}
1169
1170
bool
1171
0
isc__nmsocket_timer_running(isc_nmsocket_t *sock) {
1172
0
  REQUIRE(VALID_NMSOCK(sock));
1173
1174
0
  switch (sock->type) {
1175
0
  case isc_nm_tlssocket:
1176
0
    return (isc__nmsocket_tls_timer_running(sock));
1177
0
  case isc_nm_streamdnssocket:
1178
0
    return (isc__nmsocket_streamdns_timer_running(sock));
1179
0
  default:
1180
0
    break;
1181
0
  }
1182
1183
0
  return (uv_is_active((uv_handle_t *)&sock->read_timer));
1184
0
}
1185
1186
void
1187
0
isc__nmsocket_timer_start(isc_nmsocket_t *sock) {
1188
0
  REQUIRE(VALID_NMSOCK(sock));
1189
1190
0
  if (isc__nmsocket_timer_running(sock)) {
1191
0
    return;
1192
0
  }
1193
1194
0
  isc__nmsocket_timer_restart(sock);
1195
0
}
1196
1197
void
1198
0
isc__nmsocket_timer_stop(isc_nmsocket_t *sock) {
1199
0
  int r;
1200
1201
0
  REQUIRE(VALID_NMSOCK(sock));
1202
1203
0
  switch (sock->type) {
1204
0
  case isc_nm_tlssocket:
1205
0
    isc__nmsocket_tls_timer_stop(sock);
1206
0
    return;
1207
0
  case isc_nm_streamdnssocket:
1208
0
    isc__nmsocket_streamdns_timer_stop(sock);
1209
0
    return;
1210
0
  default:
1211
0
    break;
1212
0
  }
1213
1214
  /* uv_timer_stop() is idempotent, no need to check if running */
1215
1216
0
  r = uv_timer_stop(&sock->read_timer);
1217
0
  UV_RUNTIME_CHECK(uv_timer_stop, r);
1218
0
}
1219
1220
isc__nm_uvreq_t *
1221
0
isc___nm_get_read_req(isc_nmsocket_t *sock, isc_sockaddr_t *sockaddr FLARG) {
1222
0
  isc__nm_uvreq_t *req = NULL;
1223
1224
0
  req = isc__nm_uvreq_get(sock);
1225
0
  req->cb.recv = sock->recv_cb;
1226
0
  req->cbarg = sock->recv_cbarg;
1227
1228
0
  switch (sock->type) {
1229
0
  case isc_nm_tcpsocket:
1230
0
  case isc_nm_tlssocket:
1231
#if ISC_NETMGR_TRACE
1232
    isc_nmhandle__attach(sock->statichandle,
1233
             &req->handle FLARG_PASS);
1234
#else
1235
0
    isc_nmhandle_attach(sock->statichandle, &req->handle);
1236
0
#endif
1237
0
    break;
1238
0
  case isc_nm_streamdnssocket:
1239
#if ISC_NETMGR_TRACE
1240
    isc_nmhandle__attach(sock->recv_handle,
1241
             &req->handle FLARG_PASS);
1242
#else
1243
0
    isc_nmhandle_attach(sock->recv_handle, &req->handle);
1244
0
#endif
1245
0
    break;
1246
0
  default:
1247
0
    if (sock->client && sock->statichandle != NULL) {
1248
#if ISC_NETMGR_TRACE
1249
      isc_nmhandle__attach(sock->statichandle,
1250
               &req->handle FLARG_PASS);
1251
#else
1252
0
      isc_nmhandle_attach(sock->statichandle, &req->handle);
1253
0
#endif
1254
0
    } else {
1255
0
      req->handle = isc___nmhandle_get(sock, sockaddr,
1256
0
               NULL FLARG_PASS);
1257
0
    }
1258
0
    break;
1259
0
  }
1260
1261
0
  return (req);
1262
0
}
1263
1264
/*%<
1265
 * Allocator callback for read operations.
1266
 *
1267
 * Note this doesn't actually allocate anything, it just assigns the
1268
 * worker's receive buffer to a socket, and marks it as "in use".
1269
 */
1270
void
1271
0
isc__nm_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) {
1272
0
  isc_nmsocket_t *sock = uv_handle_get_data(handle);
1273
0
  isc__networker_t *worker = NULL;
1274
1275
0
  REQUIRE(VALID_NMSOCK(sock));
1276
  /*
1277
   * The size provided by libuv is only suggested size, and it always
1278
   * defaults to 64 * 1024 in the current versions of libuv (see
1279
   * src/unix/udp.c and src/unix/stream.c).
1280
   */
1281
0
  UNUSED(size);
1282
1283
0
  worker = sock->worker;
1284
0
  INSIST(!worker->recvbuf_inuse);
1285
0
  INSIST(worker->recvbuf != NULL);
1286
1287
0
  switch (sock->type) {
1288
0
  case isc_nm_udpsocket:
1289
0
    buf->len = ISC_NETMGR_UDP_RECVBUF_SIZE;
1290
0
    break;
1291
0
  case isc_nm_tcpsocket:
1292
0
    buf->len = ISC_NETMGR_TCP_RECVBUF_SIZE;
1293
0
    break;
1294
0
  default:
1295
0
    UNREACHABLE();
1296
0
  }
1297
1298
0
  REQUIRE(buf->len <= ISC_NETMGR_RECVBUF_SIZE);
1299
0
  buf->base = worker->recvbuf;
1300
1301
0
  worker->recvbuf_inuse = true;
1302
0
}
1303
1304
isc_result_t
1305
0
isc__nm_start_reading(isc_nmsocket_t *sock) {
1306
0
  isc_result_t result = ISC_R_SUCCESS;
1307
0
  int r;
1308
1309
0
  if (uv_is_active(&sock->uv_handle.handle)) {
1310
0
    return (ISC_R_SUCCESS);
1311
0
  }
1312
1313
0
  switch (sock->type) {
1314
0
  case isc_nm_udpsocket:
1315
0
    r = uv_udp_recv_start(&sock->uv_handle.udp, isc__nm_alloc_cb,
1316
0
              isc__nm_udp_read_cb);
1317
0
    break;
1318
0
  case isc_nm_tcpsocket:
1319
0
    r = uv_read_start(&sock->uv_handle.stream, isc__nm_alloc_cb,
1320
0
          isc__nm_tcp_read_cb);
1321
0
    break;
1322
0
  default:
1323
0
    UNREACHABLE();
1324
0
  }
1325
0
  if (r != 0) {
1326
0
    result = isc_uverr2result(r);
1327
0
  }
1328
1329
0
  return (result);
1330
0
}
1331
1332
void
1333
0
isc__nm_stop_reading(isc_nmsocket_t *sock) {
1334
0
  int r;
1335
1336
0
  if (!uv_is_active(&sock->uv_handle.handle)) {
1337
0
    return;
1338
0
  }
1339
1340
0
  switch (sock->type) {
1341
0
  case isc_nm_udpsocket:
1342
0
    r = uv_udp_recv_stop(&sock->uv_handle.udp);
1343
0
    UV_RUNTIME_CHECK(uv_udp_recv_stop, r);
1344
0
    break;
1345
0
  case isc_nm_tcpsocket:
1346
0
    r = uv_read_stop(&sock->uv_handle.stream);
1347
0
    UV_RUNTIME_CHECK(uv_read_stop, r);
1348
0
    break;
1349
0
  default:
1350
0
    UNREACHABLE();
1351
0
  }
1352
0
}
1353
1354
bool
1355
0
isc__nm_closing(isc__networker_t *worker) {
1356
0
  return (worker->shuttingdown);
1357
0
}
1358
1359
bool
1360
0
isc__nmsocket_closing(isc_nmsocket_t *sock) {
1361
0
  return (!sock->active || sock->closing ||
1362
0
    isc__nm_closing(sock->worker) ||
1363
0
    (sock->server != NULL && !isc__nmsocket_active(sock->server)));
1364
0
}
1365
1366
void
1367
0
isc_nmhandle_cleartimeout(isc_nmhandle_t *handle) {
1368
0
  REQUIRE(VALID_NMHANDLE(handle));
1369
0
  REQUIRE(VALID_NMSOCK(handle->sock));
1370
1371
0
  switch (handle->sock->type) {
1372
0
#if HAVE_LIBNGHTTP2
1373
0
  case isc_nm_httpsocket:
1374
0
    isc__nm_http_cleartimeout(handle);
1375
0
    return;
1376
0
#endif
1377
0
  case isc_nm_tlssocket:
1378
0
    isc__nm_tls_cleartimeout(handle);
1379
0
    return;
1380
0
  case isc_nm_streamdnssocket:
1381
0
    isc__nmhandle_streamdns_cleartimeout(handle);
1382
0
    return;
1383
0
  default:
1384
0
    handle->sock->read_timeout = 0;
1385
1386
0
    if (uv_is_active((uv_handle_t *)&handle->sock->read_timer)) {
1387
0
      isc__nmsocket_timer_stop(handle->sock);
1388
0
    }
1389
0
  }
1390
0
}
1391
1392
void
1393
0
isc_nmhandle_settimeout(isc_nmhandle_t *handle, uint32_t timeout) {
1394
0
  REQUIRE(VALID_NMHANDLE(handle));
1395
0
  REQUIRE(VALID_NMSOCK(handle->sock));
1396
1397
0
  switch (handle->sock->type) {
1398
0
#if HAVE_LIBNGHTTP2
1399
0
  case isc_nm_httpsocket:
1400
0
    isc__nm_http_settimeout(handle, timeout);
1401
0
    return;
1402
0
#endif
1403
0
  case isc_nm_tlssocket:
1404
0
    isc__nm_tls_settimeout(handle, timeout);
1405
0
    return;
1406
0
  case isc_nm_streamdnssocket:
1407
0
    isc__nmhandle_streamdns_settimeout(handle, timeout);
1408
0
    return;
1409
0
  default:
1410
0
    handle->sock->read_timeout = timeout;
1411
0
    isc__nmsocket_timer_restart(handle->sock);
1412
0
  }
1413
0
}
1414
1415
void
1416
0
isc_nmhandle_keepalive(isc_nmhandle_t *handle, bool value) {
1417
0
  isc_nmsocket_t *sock = NULL;
1418
0
  isc_nm_t *netmgr = NULL;
1419
1420
0
  REQUIRE(VALID_NMHANDLE(handle));
1421
0
  REQUIRE(VALID_NMSOCK(handle->sock));
1422
1423
0
  sock = handle->sock;
1424
0
  netmgr = sock->worker->netmgr;
1425
1426
0
  REQUIRE(sock->tid == isc_tid());
1427
1428
0
  switch (sock->type) {
1429
0
  case isc_nm_tcpsocket:
1430
0
    sock->keepalive = value;
1431
0
    sock->read_timeout =
1432
0
      value ? atomic_load_relaxed(&netmgr->keepalive)
1433
0
            : atomic_load_relaxed(&netmgr->idle);
1434
0
    sock->write_timeout =
1435
0
      value ? atomic_load_relaxed(&netmgr->keepalive)
1436
0
            : atomic_load_relaxed(&netmgr->idle);
1437
0
    break;
1438
0
  case isc_nm_streamdnssocket:
1439
0
    isc__nmhandle_streamdns_keepalive(handle, value);
1440
0
    break;
1441
0
  case isc_nm_tlssocket:
1442
0
    isc__nmhandle_tls_keepalive(handle, value);
1443
0
    break;
1444
0
#if HAVE_LIBNGHTTP2
1445
0
  case isc_nm_httpsocket:
1446
0
    isc__nmhandle_http_keepalive(handle, value);
1447
0
    break;
1448
0
#endif /* HAVE_LIBNGHTTP2 */
1449
0
  default:
1450
    /*
1451
     * For any other protocol, this is a no-op.
1452
     */
1453
0
    return;
1454
0
  }
1455
0
}
1456
1457
bool
1458
0
isc_nmhandle_timer_running(isc_nmhandle_t *handle) {
1459
0
  REQUIRE(VALID_NMHANDLE(handle));
1460
0
  REQUIRE(VALID_NMSOCK(handle->sock));
1461
1462
0
  return (isc__nmsocket_timer_running(handle->sock));
1463
0
}
1464
1465
isc_sockaddr_t
1466
0
isc_nmhandle_peeraddr(isc_nmhandle_t *handle) {
1467
0
  REQUIRE(VALID_NMHANDLE(handle));
1468
1469
0
  return (handle->peer);
1470
0
}
1471
1472
isc_sockaddr_t
1473
0
isc_nmhandle_localaddr(isc_nmhandle_t *handle) {
1474
0
  REQUIRE(VALID_NMHANDLE(handle));
1475
1476
0
  return (handle->local);
1477
0
}
1478
1479
isc_nm_t *
1480
0
isc_nmhandle_netmgr(isc_nmhandle_t *handle) {
1481
0
  REQUIRE(VALID_NMHANDLE(handle));
1482
0
  REQUIRE(VALID_NMSOCK(handle->sock));
1483
1484
0
  return (handle->sock->worker->netmgr);
1485
0
}
1486
1487
isc__nm_uvreq_t *
1488
0
isc___nm_uvreq_get(isc_nmsocket_t *sock FLARG) {
1489
0
  REQUIRE(VALID_NMSOCK(sock));
1490
0
  REQUIRE(sock->tid == isc_tid());
1491
1492
0
  isc__networker_t *worker = sock->worker;
1493
1494
0
  isc__nm_uvreq_t *req = isc_mempool_get(worker->uvreq_pool);
1495
0
  *req = (isc__nm_uvreq_t){
1496
0
    .connect_tries = 3,
1497
0
    .link = ISC_LINK_INITIALIZER,
1498
0
    .active_link = ISC_LINK_INITIALIZER,
1499
0
    .magic = UVREQ_MAGIC,
1500
0
  };
1501
0
  uv_handle_set_data(&req->uv_req.handle, req);
1502
1503
0
  isc___nmsocket_attach(sock, &req->sock FLARG_PASS);
1504
1505
0
  ISC_LIST_APPEND(sock->active_uvreqs, req, active_link);
1506
1507
0
  return (req);
1508
0
}
1509
1510
void
1511
0
isc___nm_uvreq_put(isc__nm_uvreq_t **reqp FLARG) {
1512
0
  REQUIRE(reqp != NULL && VALID_UVREQ(*reqp));
1513
1514
0
  isc__nm_uvreq_t *req = *reqp;
1515
0
  isc_nmhandle_t *handle = req->handle;
1516
0
  isc_nmsocket_t *sock = req->sock;
1517
1518
0
  *reqp = NULL;
1519
0
  req->handle = NULL;
1520
1521
0
  REQUIRE(VALID_UVREQ(req));
1522
1523
0
  ISC_LIST_UNLINK(sock->active_uvreqs, req, active_link);
1524
1525
0
  if (handle != NULL) {
1526
#if ISC_NETMGR_TRACE
1527
    isc_nmhandle__detach(&handle, func, file, line);
1528
#else
1529
0
    isc_nmhandle_detach(&handle);
1530
0
#endif
1531
0
  }
1532
1533
0
  isc_mempool_put(sock->worker->uvreq_pool, req);
1534
1535
0
  isc___nmsocket_detach(&sock FLARG_PASS);
1536
0
}
1537
1538
void
1539
isc_nm_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
1540
0
      void *cbarg) {
1541
0
  REQUIRE(VALID_NMHANDLE(handle));
1542
1543
0
  switch (handle->sock->type) {
1544
0
  case isc_nm_udpsocket:
1545
0
  case isc_nm_udplistener:
1546
0
    isc__nm_udp_send(handle, region, cb, cbarg);
1547
0
    break;
1548
0
  case isc_nm_tcpsocket:
1549
0
    isc__nm_tcp_send(handle, region, cb, cbarg);
1550
0
    break;
1551
0
  case isc_nm_streamdnssocket:
1552
0
    isc__nm_streamdns_send(handle, region, cb, cbarg);
1553
0
    break;
1554
0
  case isc_nm_tlssocket:
1555
0
    isc__nm_tls_send(handle, region, cb, cbarg);
1556
0
    break;
1557
0
#if HAVE_LIBNGHTTP2
1558
0
  case isc_nm_httpsocket:
1559
0
    isc__nm_http_send(handle, region, cb, cbarg);
1560
0
    break;
1561
0
#endif
1562
0
  default:
1563
0
    UNREACHABLE();
1564
0
  }
1565
0
}
1566
1567
void
1568
isc__nm_senddns(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
1569
0
    void *cbarg) {
1570
0
  REQUIRE(VALID_NMHANDLE(handle));
1571
1572
0
  switch (handle->sock->type) {
1573
0
  case isc_nm_tcpsocket:
1574
0
    isc__nm_tcp_senddns(handle, region, cb, cbarg);
1575
0
    break;
1576
0
  case isc_nm_tlssocket:
1577
0
    isc__nm_tls_senddns(handle, region, cb, cbarg);
1578
0
    break;
1579
0
  default:
1580
0
    UNREACHABLE();
1581
0
  }
1582
0
}
1583
1584
void
1585
0
isc_nm_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
1586
0
  REQUIRE(VALID_NMHANDLE(handle));
1587
1588
0
  switch (handle->sock->type) {
1589
0
  case isc_nm_udpsocket:
1590
0
    isc__nm_udp_read(handle, cb, cbarg);
1591
0
    break;
1592
0
  case isc_nm_tcpsocket:
1593
0
    isc__nm_tcp_read(handle, cb, cbarg);
1594
0
    break;
1595
0
  case isc_nm_streamdnssocket:
1596
0
    isc__nm_streamdns_read(handle, cb, cbarg);
1597
0
    break;
1598
0
  case isc_nm_tlssocket:
1599
0
    isc__nm_tls_read(handle, cb, cbarg);
1600
0
    break;
1601
0
#if HAVE_LIBNGHTTP2
1602
0
  case isc_nm_httpsocket:
1603
0
    isc__nm_http_read(handle, cb, cbarg);
1604
0
    break;
1605
0
#endif
1606
0
  default:
1607
0
    UNREACHABLE();
1608
0
  }
1609
0
}
1610
1611
static void
1612
0
cancelread_cb(void *arg) {
1613
0
  isc_nmhandle_t *handle = arg;
1614
1615
0
  REQUIRE(VALID_NMHANDLE(handle));
1616
0
  REQUIRE(VALID_NMSOCK(handle->sock));
1617
0
  REQUIRE(handle->sock->tid == isc_tid());
1618
1619
0
  REQUIRE(handle->sock->tid == isc_tid());
1620
1621
0
  switch (handle->sock->type) {
1622
0
  case isc_nm_udpsocket:
1623
0
  case isc_nm_streamdnssocket:
1624
0
  case isc_nm_httpsocket:
1625
0
    isc__nm_failed_read_cb(handle->sock, ISC_R_CANCELED, false);
1626
0
    break;
1627
0
  default:
1628
0
    UNREACHABLE();
1629
0
  }
1630
1631
0
  isc_nmhandle_detach(&handle);
1632
0
}
1633
1634
void
1635
0
isc_nm_cancelread(isc_nmhandle_t *handle) {
1636
0
  REQUIRE(VALID_NMHANDLE(handle));
1637
0
  REQUIRE(VALID_NMSOCK(handle->sock));
1638
1639
  /* Running this directly could cause a dead-lock */
1640
0
  isc_nmhandle_ref(handle);
1641
0
  isc_async_run(handle->sock->worker->loop, cancelread_cb, handle);
1642
0
}
1643
1644
void
1645
0
isc_nm_read_stop(isc_nmhandle_t *handle) {
1646
0
  REQUIRE(VALID_NMHANDLE(handle));
1647
1648
0
  isc_nmsocket_t *sock = handle->sock;
1649
1650
0
  switch (sock->type) {
1651
0
  case isc_nm_tcpsocket:
1652
0
    isc__nm_tcp_read_stop(handle);
1653
0
    break;
1654
0
  case isc_nm_tlssocket:
1655
0
    isc__nm_tls_read_stop(handle);
1656
0
    break;
1657
0
  default:
1658
0
    UNREACHABLE();
1659
0
  }
1660
0
}
1661
1662
void
1663
0
isc_nmhandle_close(isc_nmhandle_t *handle) {
1664
0
  REQUIRE(VALID_NMHANDLE(handle));
1665
0
  REQUIRE(VALID_NMSOCK(handle->sock));
1666
1667
0
  isc__nmsocket_clearcb(handle->sock);
1668
0
  isc__nmsocket_prep_destroy(handle->sock);
1669
0
}
1670
1671
void
1672
0
isc_nm_stoplistening(isc_nmsocket_t *sock) {
1673
0
  REQUIRE(VALID_NMSOCK(sock));
1674
1675
0
  switch (sock->type) {
1676
0
  case isc_nm_udplistener:
1677
0
    isc__nm_udp_stoplistening(sock);
1678
0
    break;
1679
0
  case isc_nm_tcplistener:
1680
0
    isc__nm_tcp_stoplistening(sock);
1681
0
    break;
1682
0
  case isc_nm_streamdnslistener:
1683
0
    isc__nm_streamdns_stoplistening(sock);
1684
0
    break;
1685
0
  case isc_nm_tlslistener:
1686
0
    isc__nm_tls_stoplistening(sock);
1687
0
    break;
1688
0
#if HAVE_LIBNGHTTP2
1689
0
  case isc_nm_httplistener:
1690
0
    isc__nm_http_stoplistening(sock);
1691
0
    break;
1692
0
#endif
1693
0
  default:
1694
0
    UNREACHABLE();
1695
0
  }
1696
0
}
1697
1698
void
1699
0
isc__nmsocket_stop(isc_nmsocket_t *listener) {
1700
0
  REQUIRE(VALID_NMSOCK(listener));
1701
0
  REQUIRE(listener->tid == isc_tid());
1702
0
  REQUIRE(listener->tid == 0);
1703
0
  REQUIRE(listener->type == isc_nm_httplistener ||
1704
0
    listener->type == isc_nm_tlslistener ||
1705
0
    listener->type == isc_nm_streamdnslistener);
1706
0
  REQUIRE(!listener->closing);
1707
1708
0
  listener->closing = true;
1709
1710
0
  REQUIRE(listener->outer != NULL);
1711
0
  isc_nm_stoplistening(listener->outer);
1712
1713
0
  listener->accept_cb = NULL;
1714
0
  listener->accept_cbarg = NULL;
1715
0
  listener->recv_cb = NULL;
1716
0
  listener->recv_cbarg = NULL;
1717
1718
0
  isc__nmsocket_detach(&listener->outer);
1719
1720
0
  listener->closed = true;
1721
0
}
1722
1723
void
1724
0
isc__nmsocket_barrier_init(isc_nmsocket_t *listener) {
1725
0
  REQUIRE(listener->nchildren > 0);
1726
0
  isc_barrier_init(&listener->listen_barrier, listener->nchildren);
1727
0
  isc_barrier_init(&listener->stop_barrier, listener->nchildren);
1728
0
  listener->barriers_initialised = true;
1729
0
}
1730
1731
static void
1732
0
isc___nm_connectcb(void *arg) {
1733
0
  isc__nm_uvreq_t *uvreq = arg;
1734
1735
0
  uvreq->cb.connect(uvreq->handle, uvreq->result, uvreq->cbarg);
1736
0
  isc__nm_uvreq_put(&uvreq);
1737
0
}
1738
1739
void
1740
isc__nm_connectcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq,
1741
0
      isc_result_t eresult, bool async) {
1742
0
  REQUIRE(VALID_NMSOCK(sock));
1743
0
  REQUIRE(VALID_UVREQ(uvreq));
1744
0
  REQUIRE(VALID_NMHANDLE(uvreq->handle));
1745
0
  REQUIRE(uvreq->cb.connect != NULL);
1746
1747
0
  uvreq->result = eresult;
1748
1749
0
  if (!async) {
1750
0
    isc___nm_connectcb(uvreq);
1751
0
    return;
1752
0
  }
1753
1754
0
  isc_job_run(sock->worker->loop, &uvreq->job, isc___nm_connectcb, uvreq);
1755
0
}
1756
1757
static void
1758
0
isc___nm_readcb(void *arg) {
1759
0
  isc__nm_uvreq_t *uvreq = arg;
1760
0
  isc_region_t region;
1761
1762
0
  region.base = (unsigned char *)uvreq->uvbuf.base;
1763
0
  region.length = uvreq->uvbuf.len;
1764
0
  uvreq->cb.recv(uvreq->handle, uvreq->result, &region, uvreq->cbarg);
1765
1766
0
  isc__nm_uvreq_put(&uvreq);
1767
0
}
1768
1769
void
1770
isc__nm_readcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq,
1771
0
         isc_result_t eresult, bool async) {
1772
0
  REQUIRE(VALID_NMSOCK(sock));
1773
0
  REQUIRE(VALID_UVREQ(uvreq));
1774
0
  REQUIRE(VALID_NMHANDLE(uvreq->handle));
1775
1776
0
  uvreq->result = eresult;
1777
1778
0
  if (!async) {
1779
0
    isc___nm_readcb(uvreq);
1780
0
    return;
1781
0
  }
1782
1783
0
  isc_job_run(sock->worker->loop, &uvreq->job, isc___nm_readcb, uvreq);
1784
0
}
1785
1786
static void
1787
0
isc___nm_sendcb(void *arg) {
1788
0
  isc__nm_uvreq_t *uvreq = arg;
1789
1790
0
  uvreq->cb.send(uvreq->handle, uvreq->result, uvreq->cbarg);
1791
0
  isc__nm_uvreq_put(&uvreq);
1792
0
}
1793
1794
void
1795
isc__nm_sendcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq,
1796
0
         isc_result_t eresult, bool async) {
1797
0
  REQUIRE(VALID_NMSOCK(sock));
1798
0
  REQUIRE(VALID_UVREQ(uvreq));
1799
0
  REQUIRE(VALID_NMHANDLE(uvreq->handle));
1800
1801
0
  uvreq->result = eresult;
1802
1803
0
  if (!async) {
1804
0
    isc___nm_sendcb(uvreq);
1805
0
    return;
1806
0
  }
1807
1808
0
  isc_job_run(sock->worker->loop, &uvreq->job, isc___nm_sendcb, uvreq);
1809
0
}
1810
1811
static void
1812
0
reset_shutdown(uv_handle_t *handle) {
1813
0
  isc_nmsocket_t *sock = uv_handle_get_data(handle);
1814
1815
0
  isc__nmsocket_shutdown(sock);
1816
0
  isc__nmsocket_detach(&sock);
1817
0
}
1818
1819
void
1820
0
isc__nmsocket_reset(isc_nmsocket_t *sock) {
1821
0
  REQUIRE(VALID_NMSOCK(sock));
1822
1823
0
  switch (sock->type) {
1824
0
  case isc_nm_tcpsocket:
1825
    /*
1826
     * This can be called from the TCP write timeout.
1827
     */
1828
0
    REQUIRE(sock->parent == NULL);
1829
0
    break;
1830
0
  case isc_nm_tlssocket:
1831
0
    isc__nmsocket_tls_reset(sock);
1832
0
    return;
1833
0
  case isc_nm_streamdnssocket:
1834
0
    isc__nmsocket_streamdns_reset(sock);
1835
0
    return;
1836
0
  default:
1837
0
    UNREACHABLE();
1838
0
    break;
1839
0
  }
1840
1841
0
  if (!uv_is_closing(&sock->uv_handle.handle) &&
1842
0
      uv_is_active(&sock->uv_handle.handle))
1843
0
  {
1844
    /*
1845
     * The real shutdown will be handled in the respective
1846
     * close functions.
1847
     */
1848
0
    isc__nmsocket_attach(sock, &(isc_nmsocket_t *){ NULL });
1849
0
    int r = uv_tcp_close_reset(&sock->uv_handle.tcp,
1850
0
             reset_shutdown);
1851
0
    UV_RUNTIME_CHECK(uv_tcp_close_reset, r);
1852
0
  } else {
1853
0
    isc__nmsocket_shutdown(sock);
1854
0
  }
1855
0
}
1856
1857
void
1858
0
isc__nmsocket_shutdown(isc_nmsocket_t *sock) {
1859
0
  REQUIRE(VALID_NMSOCK(sock));
1860
0
  switch (sock->type) {
1861
0
  case isc_nm_udpsocket:
1862
0
    isc__nm_udp_shutdown(sock);
1863
0
    break;
1864
0
  case isc_nm_tcpsocket:
1865
0
    isc__nm_tcp_shutdown(sock);
1866
0
    break;
1867
0
  case isc_nm_udplistener:
1868
0
  case isc_nm_tcplistener:
1869
0
    return;
1870
0
  default:
1871
0
    UNREACHABLE();
1872
0
  }
1873
0
}
1874
1875
static void
1876
0
shutdown_walk_cb(uv_handle_t *handle, void *arg) {
1877
0
  isc_nmsocket_t *sock = NULL;
1878
0
  UNUSED(arg);
1879
1880
0
  if (uv_is_closing(handle)) {
1881
0
    return;
1882
0
  }
1883
1884
0
  sock = uv_handle_get_data(handle);
1885
1886
0
  switch (handle->type) {
1887
0
  case UV_UDP:
1888
0
    isc__nmsocket_shutdown(sock);
1889
0
    return;
1890
0
  case UV_TCP:
1891
0
    switch (sock->type) {
1892
0
    case isc_nm_tcpsocket:
1893
0
      if (sock->parent == NULL) {
1894
        /* Reset the TCP connections on shutdown */
1895
0
        isc__nmsocket_reset(sock);
1896
0
        return;
1897
0
      }
1898
0
      FALLTHROUGH;
1899
0
    default:
1900
0
      isc__nmsocket_shutdown(sock);
1901
0
    }
1902
1903
0
    return;
1904
0
  default:
1905
0
    return;
1906
0
  }
1907
0
}
1908
1909
void
1910
0
isc_nm_setstats(isc_nm_t *mgr, isc_stats_t *stats) {
1911
0
  REQUIRE(VALID_NM(mgr));
1912
0
  REQUIRE(mgr->stats == NULL);
1913
0
  REQUIRE(isc_stats_ncounters(stats) == isc_sockstatscounter_max);
1914
1915
0
  isc_stats_attach(stats, &mgr->stats);
1916
0
}
1917
1918
void
1919
0
isc__nm_incstats(isc_nmsocket_t *sock, isc__nm_statid_t id) {
1920
0
  REQUIRE(VALID_NMSOCK(sock));
1921
0
  REQUIRE(id < STATID_MAX);
1922
1923
0
  if (sock->statsindex != NULL && sock->worker->netmgr->stats != NULL) {
1924
0
    isc_stats_increment(sock->worker->netmgr->stats,
1925
0
            sock->statsindex[id]);
1926
0
  }
1927
0
}
1928
1929
void
1930
0
isc__nm_decstats(isc_nmsocket_t *sock, isc__nm_statid_t id) {
1931
0
  REQUIRE(VALID_NMSOCK(sock));
1932
0
  REQUIRE(id < STATID_MAX);
1933
1934
0
  if (sock->statsindex != NULL && sock->worker->netmgr->stats != NULL) {
1935
0
    isc_stats_decrement(sock->worker->netmgr->stats,
1936
0
            sock->statsindex[id]);
1937
0
  }
1938
0
}
1939
1940
isc_result_t
1941
0
isc_nm_checkaddr(const isc_sockaddr_t *addr, isc_socktype_t type) {
1942
0
  int proto, pf, addrlen, fd, r;
1943
1944
0
  REQUIRE(addr != NULL);
1945
1946
0
  switch (type) {
1947
0
  case isc_socktype_tcp:
1948
0
    proto = SOCK_STREAM;
1949
0
    break;
1950
0
  case isc_socktype_udp:
1951
0
    proto = SOCK_DGRAM;
1952
0
    break;
1953
0
  default:
1954
0
    return (ISC_R_NOTIMPLEMENTED);
1955
0
  }
1956
1957
0
  pf = isc_sockaddr_pf(addr);
1958
0
  if (pf == AF_INET) {
1959
0
    addrlen = sizeof(struct sockaddr_in);
1960
0
  } else {
1961
0
    addrlen = sizeof(struct sockaddr_in6);
1962
0
  }
1963
1964
0
  fd = socket(pf, proto, 0);
1965
0
  if (fd < 0) {
1966
0
    return (isc_errno_toresult(errno));
1967
0
  }
1968
1969
0
  r = bind(fd, (const struct sockaddr *)&addr->type.sa, addrlen);
1970
0
  if (r < 0) {
1971
0
    close(fd);
1972
0
    return (isc_errno_toresult(errno));
1973
0
  }
1974
1975
0
  close(fd);
1976
0
  return (ISC_R_SUCCESS);
1977
0
}
1978
1979
#if defined(TCP_CONNECTIONTIMEOUT)
1980
#define TIMEOUT_TYPE  int
1981
#define TIMEOUT_DIV 1000
1982
#define TIMEOUT_OPTNAME TCP_CONNECTIONTIMEOUT
1983
#elif defined(TCP_RXT_CONNDROPTIME)
1984
#define TIMEOUT_TYPE  int
1985
#define TIMEOUT_DIV 1000
1986
#define TIMEOUT_OPTNAME TCP_RXT_CONNDROPTIME
1987
#elif defined(TCP_USER_TIMEOUT)
1988
#define TIMEOUT_TYPE  unsigned int
1989
#define TIMEOUT_DIV 1
1990
#define TIMEOUT_OPTNAME TCP_USER_TIMEOUT
1991
#elif defined(TCP_KEEPINIT)
1992
#define TIMEOUT_TYPE  int
1993
#define TIMEOUT_DIV 1000
1994
#define TIMEOUT_OPTNAME TCP_KEEPINIT
1995
#endif
1996
1997
void
1998
0
isc__nm_set_network_buffers(isc_nm_t *nm, uv_handle_t *handle) {
1999
0
  int32_t recv_buffer_size = 0;
2000
0
  int32_t send_buffer_size = 0;
2001
2002
0
  switch (handle->type) {
2003
0
  case UV_TCP:
2004
0
    recv_buffer_size =
2005
0
      atomic_load_relaxed(&nm->recv_tcp_buffer_size);
2006
0
    send_buffer_size =
2007
0
      atomic_load_relaxed(&nm->send_tcp_buffer_size);
2008
0
    break;
2009
0
  case UV_UDP:
2010
0
    recv_buffer_size =
2011
0
      atomic_load_relaxed(&nm->recv_udp_buffer_size);
2012
0
    send_buffer_size =
2013
0
      atomic_load_relaxed(&nm->send_udp_buffer_size);
2014
0
    break;
2015
0
  default:
2016
0
    UNREACHABLE();
2017
0
  }
2018
2019
0
  if (recv_buffer_size > 0) {
2020
0
    int r = uv_recv_buffer_size(handle, &recv_buffer_size);
2021
0
    UV_RUNTIME_CHECK(uv_recv_buffer_size, r);
2022
0
  }
2023
2024
0
  if (send_buffer_size > 0) {
2025
0
    int r = uv_send_buffer_size(handle, &send_buffer_size);
2026
0
    UV_RUNTIME_CHECK(uv_send_buffer_size, r);
2027
0
  }
2028
0
}
2029
2030
void
2031
0
isc_nm_bad_request(isc_nmhandle_t *handle) {
2032
0
  isc_nmsocket_t *sock = NULL;
2033
2034
0
  REQUIRE(VALID_NMHANDLE(handle));
2035
0
  REQUIRE(VALID_NMSOCK(handle->sock));
2036
2037
0
  sock = handle->sock;
2038
2039
0
  switch (sock->type) {
2040
0
  case isc_nm_udpsocket:
2041
0
    return;
2042
0
  case isc_nm_tcpsocket:
2043
0
  case isc_nm_streamdnssocket:
2044
0
  case isc_nm_tlssocket:
2045
0
    REQUIRE(sock->parent == NULL);
2046
0
    isc__nmsocket_reset(sock);
2047
0
    return;
2048
0
#if HAVE_LIBNGHTTP2
2049
0
  case isc_nm_httpsocket:
2050
0
    isc__nm_http_bad_request(handle);
2051
0
    return;
2052
0
#endif /* HAVE_LIBNGHTTP2 */
2053
0
  default:
2054
0
    UNREACHABLE();
2055
0
    break;
2056
0
  }
2057
0
}
2058
2059
isc_result_t
2060
0
isc_nm_xfr_checkperm(isc_nmhandle_t *handle) {
2061
0
  isc_nmsocket_t *sock = NULL;
2062
0
  isc_result_t result = ISC_R_NOPERM;
2063
2064
0
  REQUIRE(VALID_NMHANDLE(handle));
2065
0
  REQUIRE(VALID_NMSOCK(handle->sock));
2066
2067
0
  sock = handle->sock;
2068
2069
0
  switch (sock->type) {
2070
0
  case isc_nm_streamdnssocket:
2071
0
    result = isc__nm_streamdns_xfr_checkperm(sock);
2072
0
    break;
2073
0
  default:
2074
0
    break;
2075
0
  }
2076
2077
0
  return (result);
2078
0
}
2079
2080
bool
2081
0
isc_nm_is_http_handle(isc_nmhandle_t *handle) {
2082
0
  REQUIRE(VALID_NMHANDLE(handle));
2083
0
  REQUIRE(VALID_NMSOCK(handle->sock));
2084
2085
0
  return (handle->sock->type == isc_nm_httpsocket);
2086
0
}
2087
2088
void
2089
0
isc_nm_set_maxage(isc_nmhandle_t *handle, const uint32_t ttl) {
2090
0
  isc_nmsocket_t *sock = NULL;
2091
2092
0
  REQUIRE(VALID_NMHANDLE(handle));
2093
0
  REQUIRE(VALID_NMSOCK(handle->sock));
2094
0
  REQUIRE(!handle->sock->client);
2095
2096
#if !HAVE_LIBNGHTTP2
2097
  UNUSED(ttl);
2098
#endif
2099
2100
0
  sock = handle->sock;
2101
0
  switch (sock->type) {
2102
0
#if HAVE_LIBNGHTTP2
2103
0
  case isc_nm_httpsocket:
2104
0
    isc__nm_http_set_maxage(handle, ttl);
2105
0
    break;
2106
0
#endif /* HAVE_LIBNGHTTP2 */
2107
0
  case isc_nm_udpsocket:
2108
0
  case isc_nm_streamdnssocket:
2109
0
    return;
2110
0
    break;
2111
0
  case isc_nm_tcpsocket:
2112
0
  case isc_nm_tlssocket:
2113
0
  default:
2114
0
    UNREACHABLE();
2115
0
    break;
2116
0
  }
2117
0
}
2118
2119
isc_nmsocket_type
2120
0
isc_nm_socket_type(const isc_nmhandle_t *handle) {
2121
0
  REQUIRE(VALID_NMHANDLE(handle));
2122
0
  REQUIRE(VALID_NMSOCK(handle->sock));
2123
2124
0
  return (handle->sock->type);
2125
0
}
2126
2127
bool
2128
0
isc_nm_has_encryption(const isc_nmhandle_t *handle) {
2129
0
  REQUIRE(VALID_NMHANDLE(handle));
2130
0
  REQUIRE(VALID_NMSOCK(handle->sock));
2131
2132
0
  switch (handle->sock->type) {
2133
0
  case isc_nm_tlssocket:
2134
0
    return (true);
2135
0
#if HAVE_LIBNGHTTP2
2136
0
  case isc_nm_httpsocket:
2137
0
    return (isc__nm_http_has_encryption(handle));
2138
0
#endif /* HAVE_LIBNGHTTP2 */
2139
0
  case isc_nm_streamdnssocket:
2140
0
    return (isc__nm_streamdns_has_encryption(handle));
2141
0
  default:
2142
0
    return (false);
2143
0
  };
2144
2145
0
  return (false);
2146
0
}
2147
2148
const char *
2149
0
isc_nm_verify_tls_peer_result_string(const isc_nmhandle_t *handle) {
2150
0
  isc_nmsocket_t *sock = NULL;
2151
2152
0
  REQUIRE(VALID_NMHANDLE(handle));
2153
0
  REQUIRE(VALID_NMSOCK(handle->sock));
2154
2155
0
  sock = handle->sock;
2156
0
  switch (sock->type) {
2157
0
  case isc_nm_tlssocket:
2158
0
    return (isc__nm_tls_verify_tls_peer_result_string(handle));
2159
0
    break;
2160
0
#if HAVE_LIBNGHTTP2
2161
0
  case isc_nm_httpsocket:
2162
0
    return (isc__nm_http_verify_tls_peer_result_string(handle));
2163
0
    break;
2164
0
#endif /* HAVE_LIBNGHTTP2 */
2165
0
  case isc_nm_streamdnssocket:
2166
0
    return (isc__nm_streamdns_verify_tls_peer_result_string(
2167
0
      handle));
2168
0
    break;
2169
0
  default:
2170
0
    break;
2171
0
  }
2172
2173
0
  return (NULL);
2174
0
}
2175
2176
typedef struct settlsctx_data {
2177
  isc_nmsocket_t *listener;
2178
  isc_tlsctx_t *tlsctx;
2179
} settlsctx_data_t;
2180
2181
static void
2182
0
settlsctx_cb(void *arg) {
2183
0
  settlsctx_data_t *data = arg;
2184
0
  const uint32_t tid = isc_tid();
2185
0
  isc_nmsocket_t *listener = data->listener;
2186
0
  isc_tlsctx_t *tlsctx = data->tlsctx;
2187
0
  isc__networker_t *worker = &listener->worker->netmgr->workers[tid];
2188
2189
0
  isc_mem_put(worker->loop->mctx, data, sizeof(*data));
2190
2191
0
  REQUIRE(listener->type == isc_nm_tlslistener);
2192
2193
0
  isc__nm_async_tls_set_tlsctx(listener, tlsctx, tid);
2194
2195
0
  isc__nmsocket_detach(&listener);
2196
0
  isc_tlsctx_free(&tlsctx);
2197
0
}
2198
2199
static void
2200
0
set_tlsctx_workers(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx) {
2201
0
  const size_t nworkers =
2202
0
    (size_t)isc_loopmgr_nloops(listener->worker->netmgr->loopmgr);
2203
  /* Update the TLS context reference for every worker thread. */
2204
0
  for (size_t i = 0; i < nworkers; i++) {
2205
0
    isc__networker_t *worker =
2206
0
      &listener->worker->netmgr->workers[i];
2207
0
    settlsctx_data_t *data = isc_mem_cget(worker->loop->mctx, 1,
2208
0
                  sizeof(*data));
2209
2210
0
    isc__nmsocket_attach(listener, &data->listener);
2211
0
    isc_tlsctx_attach(tlsctx, &data->tlsctx);
2212
2213
0
    isc_async_run(worker->loop, settlsctx_cb, data);
2214
0
  }
2215
0
}
2216
2217
void
2218
0
isc_nmsocket_set_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx) {
2219
0
  REQUIRE(VALID_NMSOCK(listener));
2220
0
  REQUIRE(tlsctx != NULL);
2221
2222
0
  switch (listener->type) {
2223
0
#if HAVE_LIBNGHTTP2
2224
0
  case isc_nm_httplistener:
2225
    /*
2226
     * We handle HTTP listener sockets differently, as they rely
2227
     * on underlying TLS sockets for networking. The TLS context
2228
     * will get passed to these underlying sockets via the call to
2229
     * isc__nm_http_set_tlsctx().
2230
     */
2231
0
    isc__nm_http_set_tlsctx(listener, tlsctx);
2232
0
    break;
2233
0
#endif /* HAVE_LIBNGHTTP2 */
2234
0
  case isc_nm_tlslistener:
2235
0
    set_tlsctx_workers(listener, tlsctx);
2236
0
    break;
2237
0
  case isc_nm_streamdnslistener:
2238
0
    isc__nm_streamdns_set_tlsctx(listener, tlsctx);
2239
0
    break;
2240
0
  default:
2241
0
    UNREACHABLE();
2242
0
    break;
2243
0
  };
2244
0
}
2245
2246
void
2247
isc_nmsocket_set_max_streams(isc_nmsocket_t *listener,
2248
0
           const uint32_t max_streams) {
2249
0
  REQUIRE(VALID_NMSOCK(listener));
2250
0
  switch (listener->type) {
2251
0
#if HAVE_LIBNGHTTP2
2252
0
  case isc_nm_httplistener:
2253
0
    isc__nm_http_set_max_streams(listener, max_streams);
2254
0
    break;
2255
0
#endif /* HAVE_LIBNGHTTP2 */
2256
0
  default:
2257
0
    UNUSED(max_streams);
2258
0
    break;
2259
0
  };
2260
0
  return;
2261
0
}
2262
2263
void
2264
0
isc__nmsocket_log_tls_session_reuse(isc_nmsocket_t *sock, isc_tls_t *tls) {
2265
0
  const int log_level = ISC_LOG_DEBUG(1);
2266
0
  char client_sabuf[ISC_SOCKADDR_FORMATSIZE];
2267
0
  char local_sabuf[ISC_SOCKADDR_FORMATSIZE];
2268
2269
0
  REQUIRE(tls != NULL);
2270
2271
0
  if (!isc_log_wouldlog(isc_lctx, log_level)) {
2272
0
    return;
2273
0
  };
2274
2275
0
  isc_sockaddr_format(&sock->peer, client_sabuf, sizeof(client_sabuf));
2276
0
  isc_sockaddr_format(&sock->iface, local_sabuf, sizeof(local_sabuf));
2277
0
  isc__nmsocket_log(sock, log_level, "TLS %s session %s for %s on %s",
2278
0
        SSL_is_server(tls) ? "server" : "client",
2279
0
        SSL_session_reused(tls) ? "resumed" : "created",
2280
0
        client_sabuf, local_sabuf);
2281
0
}
2282
2283
static void
2284
0
isc__networker_destroy(isc__networker_t *worker) {
2285
0
  isc_nm_t *netmgr = worker->netmgr;
2286
0
  worker->netmgr = NULL;
2287
2288
0
  isc__netmgr_log(netmgr, ISC_LOG_DEBUG(1),
2289
0
      "Destroying network manager worker on loop %p(%d)",
2290
0
      worker->loop, isc_tid());
2291
2292
0
  isc_loop_detach(&worker->loop);
2293
2294
0
  isc_mempool_destroy(&worker->uvreq_pool);
2295
2296
0
  isc_mem_putanddetach(&worker->mctx, worker->recvbuf,
2297
0
           ISC_NETMGR_RECVBUF_SIZE);
2298
0
  isc_nm_detach(&netmgr);
2299
0
}
2300
2301
ISC_REFCOUNT_IMPL(isc__networker, isc__networker_destroy);
2302
2303
void
2304
0
isc__netmgr_log(const isc_nm_t *netmgr, int level, const char *fmt, ...) {
2305
0
  char msgbuf[2048];
2306
0
  va_list ap;
2307
2308
0
  if (!isc_log_wouldlog(isc_lctx, level)) {
2309
0
    return;
2310
0
  }
2311
2312
0
  va_start(ap, fmt);
2313
0
  vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
2314
0
  va_end(ap);
2315
2316
0
  isc_log_write(isc_lctx, ISC_LOGCATEGORY_DEFAULT, ISC_LOGMODULE_NETMGR,
2317
0
          level, "netmgr %p: %s", netmgr, msgbuf);
2318
0
}
2319
2320
void
2321
0
isc__nmsocket_log(const isc_nmsocket_t *sock, int level, const char *fmt, ...) {
2322
0
  char msgbuf[2048];
2323
0
  va_list ap;
2324
2325
0
  if (!isc_log_wouldlog(isc_lctx, level)) {
2326
0
    return;
2327
0
  }
2328
2329
0
  va_start(ap, fmt);
2330
0
  vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
2331
0
  va_end(ap);
2332
2333
0
  isc_log_write(isc_lctx, ISC_LOGCATEGORY_DEFAULT, ISC_LOGMODULE_NETMGR,
2334
0
          level, "socket %p: %s", sock, msgbuf);
2335
0
}
2336
2337
void
2338
isc__nmhandle_log(const isc_nmhandle_t *handle, int level, const char *fmt,
2339
0
      ...) {
2340
0
  char msgbuf[2048];
2341
0
  va_list ap;
2342
2343
0
  if (!isc_log_wouldlog(isc_lctx, level)) {
2344
0
    return;
2345
0
  }
2346
2347
0
  va_start(ap, fmt);
2348
0
  vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
2349
0
  va_end(ap);
2350
2351
0
  isc__nmsocket_log(handle->sock, level, "handle %p: %s", handle, msgbuf);
2352
0
}
2353
2354
void
2355
0
isc__nmhandle_set_manual_timer(isc_nmhandle_t *handle, const bool manual) {
2356
0
  REQUIRE(VALID_NMHANDLE(handle));
2357
0
  REQUIRE(VALID_NMSOCK(handle->sock));
2358
2359
0
  isc_nmsocket_t *sock = handle->sock;
2360
2361
0
  switch (sock->type) {
2362
0
  case isc_nm_tcpsocket:
2363
0
    isc__nmhandle_tcp_set_manual_timer(handle, manual);
2364
0
    return;
2365
0
  case isc_nm_tlssocket:
2366
0
    isc__nmhandle_tls_set_manual_timer(handle, manual);
2367
0
    return;
2368
0
  default:
2369
0
    break;
2370
0
  };
2371
2372
0
  UNREACHABLE();
2373
0
}
2374
2375
void
2376
isc__nmhandle_get_selected_alpn(isc_nmhandle_t *handle,
2377
        const unsigned char **alpn,
2378
0
        unsigned int *alpnlen) {
2379
0
  REQUIRE(VALID_NMHANDLE(handle));
2380
0
  REQUIRE(VALID_NMSOCK(handle->sock));
2381
2382
0
  isc_nmsocket_t *sock = handle->sock;
2383
2384
0
  switch (sock->type) {
2385
0
  case isc_nm_tlssocket:
2386
0
    isc__nmhandle_tls_get_selected_alpn(handle, alpn, alpnlen);
2387
0
    return;
2388
0
  default:
2389
0
    break;
2390
0
  };
2391
0
}
2392
2393
isc_result_t
2394
0
isc_nmhandle_set_tcp_nodelay(isc_nmhandle_t *handle, const bool value) {
2395
0
  REQUIRE(VALID_NMHANDLE(handle));
2396
0
  REQUIRE(VALID_NMSOCK(handle->sock));
2397
2398
0
  isc_result_t result = ISC_R_FAILURE;
2399
0
  isc_nmsocket_t *sock = handle->sock;
2400
2401
0
  switch (sock->type) {
2402
0
  case isc_nm_tcpsocket: {
2403
0
    uv_os_fd_t tcp_fd = (uv_os_fd_t)-1;
2404
0
    (void)uv_fileno((uv_handle_t *)&sock->uv_handle.tcp, &tcp_fd);
2405
0
    RUNTIME_CHECK(tcp_fd != (uv_os_fd_t)-1);
2406
0
    result = isc__nm_socket_tcp_nodelay((uv_os_sock_t)tcp_fd,
2407
0
                value);
2408
0
  } break;
2409
0
  case isc_nm_tlssocket:
2410
0
    result = isc__nmhandle_tls_set_tcp_nodelay(handle, value);
2411
0
    break;
2412
0
  default:
2413
0
    UNREACHABLE();
2414
0
    break;
2415
0
  };
2416
2417
0
  return (result);
2418
0
}
2419
2420
isc_sockaddr_t
2421
0
isc_nmsocket_getaddr(isc_nmsocket_t *sock) {
2422
0
  REQUIRE(VALID_NMSOCK(sock));
2423
0
  return (sock->iface);
2424
0
}
2425
2426
#if ISC_NETMGR_TRACE
2427
/*
2428
 * Dump all active sockets in netmgr. We output to stderr
2429
 * as the logger might be already shut down.
2430
 */
2431
2432
static const char *
2433
nmsocket_type_totext(isc_nmsocket_type type) {
2434
  switch (type) {
2435
  case isc_nm_udpsocket:
2436
    return ("isc_nm_udpsocket");
2437
  case isc_nm_udplistener:
2438
    return ("isc_nm_udplistener");
2439
  case isc_nm_tcpsocket:
2440
    return ("isc_nm_tcpsocket");
2441
  case isc_nm_tcplistener:
2442
    return ("isc_nm_tcplistener");
2443
  case isc_nm_tlssocket:
2444
    return ("isc_nm_tlssocket");
2445
  case isc_nm_tlslistener:
2446
    return ("isc_nm_tlslistener");
2447
  case isc_nm_httplistener:
2448
    return ("isc_nm_httplistener");
2449
  case isc_nm_httpsocket:
2450
    return ("isc_nm_httpsocket");
2451
  case isc_nm_streamdnslistener:
2452
    return ("isc_nm_streamdnslistener");
2453
  case isc_nm_streamdnssocket:
2454
    return ("isc_nm_streamdnssocket");
2455
  default:
2456
    UNREACHABLE();
2457
  }
2458
}
2459
2460
static void
2461
nmhandle_dump(isc_nmhandle_t *handle) {
2462
  fprintf(stderr, "Active handle %p, refs %" PRIuFAST32 "\n", handle,
2463
    isc_refcount_current(&handle->references));
2464
  fprintf(stderr, "Created by:\n");
2465
  isc_backtrace_symbols_fd(handle->backtrace, handle->backtrace_size,
2466
         STDERR_FILENO);
2467
  fprintf(stderr, "\n\n");
2468
}
2469
2470
static void
2471
nmsocket_dump(isc_nmsocket_t *sock) {
2472
  isc_nmhandle_t *handle = NULL;
2473
2474
  fprintf(stderr, "\n=================\n");
2475
  fprintf(stderr, "Active %s socket %p, type %s, refs %" PRIuFAST32 "\n",
2476
    sock->client ? "client" : "server", sock,
2477
    nmsocket_type_totext(sock->type),
2478
    isc_refcount_current(&sock->references));
2479
  fprintf(stderr,
2480
    "Parent %p, listener %p, server %p, statichandle = "
2481
    "%p\n",
2482
    sock->parent, sock->listener, sock->server, sock->statichandle);
2483
  fprintf(stderr, "Flags:%s%s%s%s%s\n", sock->active ? " active" : "",
2484
    sock->closing ? " closing" : "",
2485
    sock->destroying ? " destroying" : "",
2486
    sock->connecting ? " connecting" : "",
2487
    sock->accepting ? " accepting" : "");
2488
  fprintf(stderr, "Created by:\n");
2489
  isc_backtrace_symbols_fd(sock->backtrace, sock->backtrace_size,
2490
         STDERR_FILENO);
2491
  fprintf(stderr, "\n");
2492
2493
  for (handle = ISC_LIST_HEAD(sock->active_handles); handle != NULL;
2494
       handle = ISC_LIST_NEXT(handle, active_link))
2495
  {
2496
    static bool first = true;
2497
    if (first) {
2498
      fprintf(stderr, "Active handles:\n");
2499
      first = false;
2500
    }
2501
    nmhandle_dump(handle);
2502
  }
2503
2504
  fprintf(stderr, "\n");
2505
}
2506
2507
void
2508
isc__nm_dump_active(isc__networker_t *worker) {
2509
  isc_nmsocket_t *sock = NULL;
2510
  bool first = true;
2511
2512
  for (sock = ISC_LIST_HEAD(worker->active_sockets); sock != NULL;
2513
       sock = ISC_LIST_NEXT(sock, active_link))
2514
  {
2515
    if (first) {
2516
      fprintf(stderr, "Outstanding sockets\n");
2517
      first = false;
2518
    }
2519
    nmsocket_dump(sock);
2520
  }
2521
}
2522
#endif