Coverage Report

Created: 2026-07-30 06:31

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