2019-11-05 13:55:54 -08:00
|
|
|
/*
|
|
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
|
|
|
*
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
2020-09-14 16:20:40 -07:00
|
|
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
2019-11-05 13:55:54 -08:00
|
|
|
*
|
|
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
|
|
* information regarding copyright ownership.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <uv.h>
|
|
|
|
|
|
|
|
#include <isc/atomic.h>
|
|
|
|
#include <isc/buffer.h>
|
|
|
|
#include <isc/condition.h>
|
|
|
|
#include <isc/magic.h>
|
|
|
|
#include <isc/mem.h>
|
|
|
|
#include <isc/netmgr.h>
|
|
|
|
#include <isc/random.h>
|
|
|
|
#include <isc/refcount.h>
|
|
|
|
#include <isc/region.h>
|
|
|
|
#include <isc/result.h>
|
|
|
|
#include <isc/sockaddr.h>
|
|
|
|
#include <isc/thread.h>
|
|
|
|
#include <isc/util.h>
|
|
|
|
|
|
|
|
#include "netmgr-int.h"
|
2020-02-12 13:59:18 +01:00
|
|
|
#include "uv-compat.h"
|
2019-11-05 13:55:54 -08:00
|
|
|
|
2019-11-08 10:52:49 -08:00
|
|
|
#define TCPDNS_CLIENTS_PER_CONN 23
|
|
|
|
/*%<
|
|
|
|
*
|
|
|
|
* Maximum number of simultaneous handles in flight supported for a single
|
|
|
|
* connected TCPDNS socket. This value was chosen arbitrarily, and may be
|
|
|
|
* changed in the future.
|
|
|
|
*/
|
|
|
|
|
2020-02-14 08:14:03 +01:00
|
|
|
static void
|
2020-04-15 19:26:49 -07:00
|
|
|
dnslisten_readcb(isc_nmhandle_t *handle, isc_result_t eresult,
|
|
|
|
isc_region_t *region, void *arg);
|
2019-11-05 13:55:54 -08:00
|
|
|
|
2020-02-14 08:14:03 +01:00
|
|
|
static void
|
|
|
|
resume_processing(void *arg);
|
2019-11-08 10:52:49 -08:00
|
|
|
|
2020-03-02 12:10:26 +01:00
|
|
|
static void
|
|
|
|
tcpdns_close_direct(isc_nmsocket_t *sock);
|
|
|
|
|
2019-11-05 13:55:54 -08:00
|
|
|
static inline size_t
|
2020-02-13 14:44:37 -08:00
|
|
|
dnslen(unsigned char *base) {
|
2019-11-05 13:55:54 -08:00
|
|
|
return ((base[0] << 8) + (base[1]));
|
|
|
|
}
|
|
|
|
|
2019-11-19 11:56:00 +01:00
|
|
|
/*
|
|
|
|
* Regular TCP buffer, should suffice in most cases.
|
|
|
|
*/
|
2019-11-05 13:55:54 -08:00
|
|
|
#define NM_REG_BUF 4096
|
2019-11-19 11:56:00 +01:00
|
|
|
/*
|
|
|
|
* Two full DNS packets with lengths.
|
|
|
|
* netmgr receives 64k at most so there's no risk
|
|
|
|
* of overrun.
|
|
|
|
*/
|
2020-02-12 13:59:18 +01:00
|
|
|
#define NM_BIG_BUF (65535 + 2) * 2
|
2019-11-05 13:55:54 -08:00
|
|
|
static inline void
|
2020-02-13 14:44:37 -08:00
|
|
|
alloc_dnsbuf(isc_nmsocket_t *sock, size_t len) {
|
2019-11-05 13:55:54 -08:00
|
|
|
REQUIRE(len <= NM_BIG_BUF);
|
|
|
|
|
|
|
|
if (sock->buf == NULL) {
|
|
|
|
/* We don't have the buffer at all */
|
|
|
|
size_t alloc_len = len < NM_REG_BUF ? NM_REG_BUF : NM_BIG_BUF;
|
2019-11-08 10:52:49 -08:00
|
|
|
sock->buf = isc_mem_allocate(sock->mgr->mctx, alloc_len);
|
2019-11-05 13:55:54 -08:00
|
|
|
sock->buf_size = alloc_len;
|
|
|
|
} else {
|
|
|
|
/* We have the buffer but it's too small */
|
|
|
|
sock->buf = isc_mem_reallocate(sock->mgr->mctx, sock->buf,
|
|
|
|
NM_BIG_BUF);
|
|
|
|
sock->buf_size = NM_BIG_BUF;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-19 11:56:00 +01:00
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
timer_close_cb(uv_handle_t *handle) {
|
2020-02-12 13:59:18 +01:00
|
|
|
isc_nmsocket_t *sock = (isc_nmsocket_t *)uv_handle_get_data(handle);
|
2020-06-10 11:32:39 +02:00
|
|
|
|
|
|
|
REQUIRE(VALID_NMSOCK(sock));
|
|
|
|
|
2020-06-09 17:07:16 -07:00
|
|
|
atomic_store(&sock->closed, true);
|
|
|
|
tcpdns_close_direct(sock);
|
2019-11-19 11:56:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
dnstcp_readtimeout(uv_timer_t *timer) {
|
2019-12-03 00:07:59 -08:00
|
|
|
isc_nmsocket_t *sock =
|
2020-02-12 13:59:18 +01:00
|
|
|
(isc_nmsocket_t *)uv_handle_get_data((uv_handle_t *)timer);
|
2019-11-20 22:33:35 +01:00
|
|
|
|
2019-11-19 11:56:00 +01:00
|
|
|
REQUIRE(VALID_NMSOCK(sock));
|
2019-12-07 23:43:52 +01:00
|
|
|
REQUIRE(sock->tid == isc_nm_tid());
|
2020-06-10 11:32:39 +02:00
|
|
|
|
|
|
|
/* Close the TCP connection; its closure should fire ours. */
|
2020-11-09 12:33:37 -08:00
|
|
|
if (sock->outerhandle != NULL) {
|
|
|
|
isc_nmhandle_detach(&sock->outerhandle);
|
|
|
|
}
|
2019-11-19 11:56:00 +01:00
|
|
|
}
|
|
|
|
|
2019-11-05 13:55:54 -08:00
|
|
|
/*
|
2019-11-25 18:36:14 -03:00
|
|
|
* Accept callback for TCP-DNS connection.
|
2019-11-05 13:55:54 -08:00
|
|
|
*/
|
2020-06-17 12:09:10 -07:00
|
|
|
static isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
dnslisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
|
2020-02-12 13:59:18 +01:00
|
|
|
isc_nmsocket_t *dnslistensock = (isc_nmsocket_t *)cbarg;
|
2019-11-05 13:55:54 -08:00
|
|
|
isc_nmsocket_t *dnssock = NULL;
|
2020-09-03 13:31:27 -07:00
|
|
|
isc_nmhandle_t *readhandle = NULL;
|
2020-09-11 10:53:31 +02:00
|
|
|
isc_nm_accept_cb_t accept_cb;
|
|
|
|
void *accept_cbarg;
|
2019-11-05 13:55:54 -08:00
|
|
|
|
|
|
|
REQUIRE(VALID_NMSOCK(dnslistensock));
|
|
|
|
REQUIRE(dnslistensock->type == isc_nm_tcpdnslistener);
|
|
|
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
2020-06-17 12:09:10 -07:00
|
|
|
return (result);
|
2019-11-05 13:55:54 -08:00
|
|
|
}
|
|
|
|
|
2020-09-11 10:53:31 +02:00
|
|
|
accept_cb = dnslistensock->accept_cb;
|
|
|
|
accept_cbarg = dnslistensock->accept_cbarg;
|
|
|
|
|
|
|
|
if (accept_cb != NULL) {
|
|
|
|
result = accept_cb(handle, ISC_R_SUCCESS, accept_cbarg);
|
2020-06-17 12:09:10 -07:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return (result);
|
|
|
|
}
|
2019-11-25 18:36:14 -03:00
|
|
|
}
|
|
|
|
|
2019-11-05 13:55:54 -08:00
|
|
|
/* We need to create a 'wrapper' dnssocket for this connection */
|
|
|
|
dnssock = isc_mem_get(handle->sock->mgr->mctx, sizeof(*dnssock));
|
2020-02-12 13:59:18 +01:00
|
|
|
isc__nmsocket_init(dnssock, handle->sock->mgr, isc_nm_tcpdnssocket,
|
|
|
|
handle->sock->iface);
|
2019-11-05 13:55:54 -08:00
|
|
|
|
|
|
|
dnssock->extrahandlesize = dnslistensock->extrahandlesize;
|
2020-06-04 14:54:36 -07:00
|
|
|
isc__nmsocket_attach(dnslistensock, &dnssock->listener);
|
2020-06-04 23:13:54 -07:00
|
|
|
|
2020-06-09 17:07:16 -07:00
|
|
|
isc__nmsocket_attach(dnssock, &dnssock->self);
|
|
|
|
|
2020-09-03 13:31:27 -07:00
|
|
|
isc_nmhandle_attach(handle, &dnssock->outerhandle);
|
2020-06-04 23:13:54 -07:00
|
|
|
|
2019-11-05 13:55:54 -08:00
|
|
|
dnssock->peer = handle->sock->peer;
|
2019-11-20 22:33:35 +01:00
|
|
|
dnssock->read_timeout = handle->sock->mgr->init;
|
2019-11-19 11:56:00 +01:00
|
|
|
dnssock->tid = isc_nm_tid();
|
2019-11-08 10:52:49 -08:00
|
|
|
dnssock->closehandle_cb = resume_processing;
|
2019-11-05 13:55:54 -08:00
|
|
|
|
2019-11-19 11:56:00 +01:00
|
|
|
uv_timer_init(&dnssock->mgr->workers[isc_nm_tid()].loop,
|
|
|
|
&dnssock->timer);
|
|
|
|
dnssock->timer.data = dnssock;
|
|
|
|
dnssock->timer_initialized = true;
|
|
|
|
uv_timer_start(&dnssock->timer, dnstcp_readtimeout,
|
|
|
|
dnssock->read_timeout, 0);
|
2020-11-02 15:55:12 +01:00
|
|
|
dnssock->timer_running = true;
|
2020-06-17 12:09:10 -07:00
|
|
|
|
2020-09-03 13:31:27 -07:00
|
|
|
/*
|
|
|
|
* Add a reference to handle to keep it from being freed by
|
|
|
|
* the caller. It will be detached in dnslisted_readcb() when
|
|
|
|
* the connection is closed or there is no more data to be read.
|
|
|
|
*/
|
|
|
|
isc_nmhandle_attach(handle, &readhandle);
|
2020-10-21 12:52:09 +02:00
|
|
|
isc_nm_read(readhandle, dnslisten_readcb, dnssock);
|
2020-06-09 17:07:16 -07:00
|
|
|
isc__nmsocket_detach(&dnssock);
|
2020-06-17 12:09:10 -07:00
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
2019-11-05 13:55:54 -08:00
|
|
|
}
|
|
|
|
|
2019-11-19 11:56:00 +01:00
|
|
|
/*
|
|
|
|
* Process a single packet from the incoming buffer.
|
|
|
|
*
|
|
|
|
* Return ISC_R_SUCCESS and attach 'handlep' to a handle if something
|
|
|
|
* was processed; return ISC_R_NOMORE if there isn't a full message
|
|
|
|
* to be processed.
|
|
|
|
*
|
|
|
|
* The caller will need to unreference the handle.
|
|
|
|
*/
|
|
|
|
static isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
processbuffer(isc_nmsocket_t *dnssock, isc_nmhandle_t **handlep) {
|
2019-11-19 11:56:00 +01:00
|
|
|
size_t len;
|
2019-11-08 10:52:49 -08:00
|
|
|
|
2019-11-19 11:56:00 +01:00
|
|
|
REQUIRE(VALID_NMSOCK(dnssock));
|
2020-09-18 12:27:40 +02:00
|
|
|
REQUIRE(dnssock->tid == isc_nm_tid());
|
2019-11-19 11:56:00 +01:00
|
|
|
REQUIRE(handlep != NULL && *handlep == NULL);
|
2019-11-08 10:52:49 -08:00
|
|
|
|
2019-11-19 11:56:00 +01:00
|
|
|
/*
|
|
|
|
* If we don't even have the length yet, we can't do
|
|
|
|
* anything.
|
|
|
|
*/
|
|
|
|
if (dnssock->buf_len < 2) {
|
|
|
|
return (ISC_R_NOMORE);
|
2019-11-08 10:52:49 -08:00
|
|
|
}
|
|
|
|
|
2019-11-19 11:56:00 +01:00
|
|
|
/*
|
|
|
|
* Process the first packet from the buffer, leaving
|
|
|
|
* the rest (if any) for later.
|
|
|
|
*/
|
|
|
|
len = dnslen(dnssock->buf);
|
|
|
|
if (len <= dnssock->buf_len - 2) {
|
2020-09-03 13:31:27 -07:00
|
|
|
isc_nmhandle_t *dnshandle = NULL;
|
|
|
|
isc_nmsocket_t *listener = NULL;
|
2020-09-11 10:53:31 +02:00
|
|
|
isc_nm_recv_cb_t cb = NULL;
|
|
|
|
void *cbarg = NULL;
|
2020-09-03 13:31:27 -07:00
|
|
|
|
2020-06-10 11:32:39 +02:00
|
|
|
if (atomic_load(&dnssock->client) &&
|
|
|
|
dnssock->statichandle != NULL) {
|
2020-09-03 13:31:27 -07:00
|
|
|
isc_nmhandle_attach(dnssock->statichandle, &dnshandle);
|
2020-06-10 11:32:39 +02:00
|
|
|
} else {
|
|
|
|
dnshandle = isc__nmhandle_get(dnssock, NULL, NULL);
|
|
|
|
}
|
|
|
|
|
2020-09-03 13:31:27 -07:00
|
|
|
listener = dnssock->listener;
|
2020-09-11 10:53:31 +02:00
|
|
|
if (listener != NULL) {
|
|
|
|
cb = listener->recv_cb;
|
|
|
|
cbarg = listener->recv_cbarg;
|
|
|
|
} else if (dnssock->recv_cb != NULL) {
|
|
|
|
cb = dnssock->recv_cb;
|
|
|
|
cbarg = dnssock->recv_cbarg;
|
2020-06-10 11:32:39 +02:00
|
|
|
/*
|
|
|
|
* We need to clear the read callback *before*
|
|
|
|
* calling it, because it might make another
|
|
|
|
* call to isc_nm_read() and set up a new callback.
|
|
|
|
*/
|
|
|
|
isc__nmsocket_clearcb(dnssock);
|
2020-09-11 10:53:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (cb != NULL) {
|
2020-06-10 11:32:39 +02:00
|
|
|
cb(dnshandle, ISC_R_SUCCESS,
|
|
|
|
&(isc_region_t){ .base = dnssock->buf + 2,
|
|
|
|
.length = len },
|
|
|
|
cbarg);
|
2020-01-15 14:53:42 +01:00
|
|
|
}
|
2019-11-08 10:52:49 -08:00
|
|
|
|
2019-11-19 11:56:00 +01:00
|
|
|
len += 2;
|
2019-11-08 10:52:49 -08:00
|
|
|
dnssock->buf_len -= len;
|
|
|
|
if (len > 0) {
|
|
|
|
memmove(dnssock->buf, dnssock->buf + len,
|
|
|
|
dnssock->buf_len);
|
|
|
|
}
|
|
|
|
|
2019-11-19 11:56:00 +01:00
|
|
|
*handlep = dnshandle;
|
|
|
|
return (ISC_R_SUCCESS);
|
2019-11-08 10:52:49 -08:00
|
|
|
}
|
2019-11-19 11:56:00 +01:00
|
|
|
|
|
|
|
return (ISC_R_NOMORE);
|
2019-11-08 10:52:49 -08:00
|
|
|
}
|
|
|
|
|
2019-11-05 13:55:54 -08:00
|
|
|
/*
|
2020-09-03 13:31:27 -07:00
|
|
|
* We've got a read on our underlying socket. Check whether
|
|
|
|
* we have a complete DNS packet and, if so, call the callback.
|
2019-11-05 13:55:54 -08:00
|
|
|
*/
|
|
|
|
static void
|
2020-04-15 19:26:49 -07:00
|
|
|
dnslisten_readcb(isc_nmhandle_t *handle, isc_result_t eresult,
|
|
|
|
isc_region_t *region, void *arg) {
|
2020-02-12 13:59:18 +01:00
|
|
|
isc_nmsocket_t *dnssock = (isc_nmsocket_t *)arg;
|
2020-02-13 14:44:37 -08:00
|
|
|
unsigned char *base = NULL;
|
|
|
|
bool done = false;
|
|
|
|
size_t len;
|
2019-11-05 13:55:54 -08:00
|
|
|
|
|
|
|
REQUIRE(VALID_NMSOCK(dnssock));
|
2020-09-18 12:27:40 +02:00
|
|
|
REQUIRE(dnssock->tid == isc_nm_tid());
|
2019-11-05 13:55:54 -08:00
|
|
|
REQUIRE(VALID_NMHANDLE(handle));
|
2020-11-02 15:55:12 +01:00
|
|
|
|
|
|
|
if (!isc__nmsocket_active(dnssock) || atomic_load(&dnssock->closing) ||
|
|
|
|
dnssock->outerhandle == NULL ||
|
|
|
|
(dnssock->listener != NULL &&
|
|
|
|
!isc__nmsocket_active(dnssock->listener)) ||
|
|
|
|
atomic_load(&dnssock->mgr->closing))
|
2020-10-31 21:08:53 +01:00
|
|
|
{
|
2020-11-02 15:55:12 +01:00
|
|
|
if (eresult == ISC_R_SUCCESS) {
|
|
|
|
eresult = ISC_R_CANCELED;
|
|
|
|
}
|
2020-10-31 21:08:53 +01:00
|
|
|
}
|
2019-11-05 13:55:54 -08:00
|
|
|
|
2020-04-15 19:26:49 -07:00
|
|
|
if (region == NULL || eresult != ISC_R_SUCCESS) {
|
2020-11-02 15:55:12 +01:00
|
|
|
isc_nm_recv_cb_t cb = dnssock->recv_cb;
|
|
|
|
void *cbarg = dnssock->recv_cbarg;
|
|
|
|
|
2019-11-05 13:55:54 -08:00
|
|
|
/* Connection closed */
|
2020-09-05 11:07:40 -07:00
|
|
|
atomic_store(&dnssock->result, eresult);
|
2020-11-02 15:55:12 +01:00
|
|
|
isc__nmsocket_clearcb(dnssock);
|
|
|
|
if (atomic_load(&dnssock->client) && cb != NULL) {
|
|
|
|
cb(dnssock->statichandle, eresult, NULL, cbarg);
|
2020-09-05 11:07:40 -07:00
|
|
|
}
|
2020-11-02 15:55:12 +01:00
|
|
|
|
2020-06-09 17:07:16 -07:00
|
|
|
if (dnssock->self != NULL) {
|
|
|
|
isc__nmsocket_detach(&dnssock->self);
|
|
|
|
}
|
2020-06-20 15:03:05 -07:00
|
|
|
if (dnssock->outerhandle != NULL) {
|
2020-11-02 15:55:12 +01:00
|
|
|
isc__nmsocket_clearcb(dnssock->outerhandle->sock);
|
2020-09-03 13:31:27 -07:00
|
|
|
isc_nmhandle_detach(&dnssock->outerhandle);
|
2020-06-20 15:03:05 -07:00
|
|
|
}
|
2020-11-02 15:55:12 +01:00
|
|
|
if (dnssock->listener != NULL) {
|
|
|
|
isc__nmsocket_detach(&dnssock->listener);
|
|
|
|
}
|
2020-09-05 11:07:40 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Server connections will hold two handle references when
|
|
|
|
* shut down, but client (tcpdnsconnect) connections have
|
|
|
|
* only one.
|
|
|
|
*/
|
|
|
|
if (!atomic_load(&dnssock->client)) {
|
|
|
|
isc_nmhandle_detach(&handle);
|
|
|
|
}
|
2019-11-05 13:55:54 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
base = region->base;
|
|
|
|
len = region->length;
|
|
|
|
|
2019-11-19 11:56:00 +01:00
|
|
|
if (dnssock->buf_len + len > dnssock->buf_size) {
|
|
|
|
alloc_dnsbuf(dnssock, dnssock->buf_len + len);
|
2019-11-08 10:52:49 -08:00
|
|
|
}
|
2019-11-19 11:56:00 +01:00
|
|
|
memmove(dnssock->buf + dnssock->buf_len, base, len);
|
|
|
|
dnssock->buf_len += len;
|
2019-11-08 10:52:49 -08:00
|
|
|
|
2019-11-20 22:33:35 +01:00
|
|
|
dnssock->read_timeout = (atomic_load(&dnssock->keepalive)
|
2020-02-12 13:59:18 +01:00
|
|
|
? dnssock->mgr->keepalive
|
|
|
|
: dnssock->mgr->idle);
|
2019-11-20 22:33:35 +01:00
|
|
|
|
2019-11-19 11:56:00 +01:00
|
|
|
do {
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_result_t result;
|
2019-11-19 11:56:00 +01:00
|
|
|
isc_nmhandle_t *dnshandle = NULL;
|
2019-11-08 10:52:49 -08:00
|
|
|
|
2019-11-19 11:56:00 +01:00
|
|
|
result = processbuffer(dnssock, &dnshandle);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
2019-11-08 10:52:49 -08:00
|
|
|
/*
|
2019-11-19 11:56:00 +01:00
|
|
|
* There wasn't anything in the buffer to process.
|
2019-11-08 10:52:49 -08:00
|
|
|
*/
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-11-19 11:56:00 +01:00
|
|
|
/*
|
|
|
|
* We have a packet: stop timeout timers
|
|
|
|
*/
|
2020-06-04 23:13:54 -07:00
|
|
|
atomic_store(&dnssock->outerhandle->sock->processing, true);
|
2020-03-05 22:56:31 +01:00
|
|
|
if (dnssock->timer_initialized) {
|
|
|
|
uv_timer_stop(&dnssock->timer);
|
|
|
|
}
|
2019-11-05 13:55:54 -08:00
|
|
|
|
2020-06-10 11:32:39 +02:00
|
|
|
if (atomic_load(&dnssock->sequential) ||
|
2020-09-11 10:53:31 +02:00
|
|
|
dnssock->recv_cb == NULL) {
|
2019-11-05 13:55:54 -08:00
|
|
|
/*
|
2020-09-03 13:31:27 -07:00
|
|
|
* There are two reasons we might want to pause here:
|
|
|
|
* - We're in sequential mode and we've received
|
2020-06-10 11:32:39 +02:00
|
|
|
* a whole packet, so we're done until it's been
|
2020-09-03 13:31:27 -07:00
|
|
|
* processed; or
|
|
|
|
* - We no longer have a read callback.
|
2019-11-05 13:55:54 -08:00
|
|
|
*/
|
2020-07-01 16:17:09 -07:00
|
|
|
isc_nm_pauseread(dnssock->outerhandle);
|
2019-11-19 11:56:00 +01:00
|
|
|
done = true;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* We're pipelining, so we now resume processing
|
|
|
|
* packets until the clients-per-connection limit
|
|
|
|
* is reached (as determined by the number of
|
|
|
|
* active handles on the socket). When the limit
|
|
|
|
* is reached, pause reading.
|
|
|
|
*/
|
|
|
|
if (atomic_load(&dnssock->ah) >=
|
2020-02-12 13:59:18 +01:00
|
|
|
TCPDNS_CLIENTS_PER_CONN) {
|
2020-07-01 16:17:09 -07:00
|
|
|
isc_nm_pauseread(dnssock->outerhandle);
|
2019-11-19 11:56:00 +01:00
|
|
|
done = true;
|
|
|
|
}
|
2019-11-05 13:55:54 -08:00
|
|
|
}
|
|
|
|
|
2020-09-03 13:31:27 -07:00
|
|
|
isc_nmhandle_detach(&dnshandle);
|
2019-11-19 11:56:00 +01:00
|
|
|
} while (!done);
|
2019-11-05 13:55:54 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* isc_nm_listentcpdns listens for connections and accepts
|
|
|
|
* them immediately, then calls the cb for each incoming DNS packet
|
|
|
|
* (with 2-byte length stripped) - just like for UDP packet.
|
|
|
|
*/
|
|
|
|
isc_result_t
|
2020-02-12 13:59:18 +01:00
|
|
|
isc_nm_listentcpdns(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
|
2020-06-17 12:09:10 -07:00
|
|
|
void *cbarg, isc_nm_accept_cb_t accept_cb,
|
|
|
|
void *accept_cbarg, size_t extrahandlesize, int backlog,
|
|
|
|
isc_quota_t *quota, isc_nmsocket_t **sockp) {
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_nmsocket_t *dnslistensock = isc_mem_get(mgr->mctx,
|
|
|
|
sizeof(*dnslistensock));
|
2019-11-05 13:55:54 -08:00
|
|
|
isc_result_t result;
|
|
|
|
|
|
|
|
REQUIRE(VALID_NM(mgr));
|
|
|
|
|
2020-01-05 01:02:12 -08:00
|
|
|
isc__nmsocket_init(dnslistensock, mgr, isc_nm_tcpdnslistener, iface);
|
2020-09-11 10:53:31 +02:00
|
|
|
dnslistensock->recv_cb = cb;
|
|
|
|
dnslistensock->recv_cbarg = cbarg;
|
|
|
|
dnslistensock->accept_cb = accept_cb;
|
2019-11-25 18:36:14 -03:00
|
|
|
dnslistensock->accept_cbarg = accept_cbarg;
|
2019-11-05 13:55:54 -08:00
|
|
|
dnslistensock->extrahandlesize = extrahandlesize;
|
|
|
|
|
2020-06-10 11:32:39 +02:00
|
|
|
/*
|
|
|
|
* dnslistensock will be a DNS 'wrapper' around a connected
|
|
|
|
* stream. We set dnslistensock->outer to a socket listening
|
|
|
|
* for a TCP connection.
|
|
|
|
*/
|
2020-02-12 13:59:18 +01:00
|
|
|
result = isc_nm_listentcp(mgr, iface, dnslisten_acceptcb, dnslistensock,
|
|
|
|
extrahandlesize, backlog, quota,
|
|
|
|
&dnslistensock->outer);
|
2019-12-02 13:54:44 +01:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
atomic_store(&dnslistensock->listening, true);
|
|
|
|
*sockp = dnslistensock;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
} else {
|
|
|
|
atomic_store(&dnslistensock->closed, true);
|
2020-06-04 14:54:36 -07:00
|
|
|
isc__nmsocket_detach(&dnslistensock);
|
2019-12-02 13:54:44 +01:00
|
|
|
return (result);
|
|
|
|
}
|
2019-11-05 13:55:54 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2020-10-02 09:28:29 +02:00
|
|
|
isc__nm_async_tcpdnsstop(isc__networker_t *worker, isc__netievent_t *ev0) {
|
|
|
|
isc__netievent_tcpstop_t *ievent = (isc__netievent_tcpdnsstop_t *)ev0;
|
|
|
|
isc_nmsocket_t *sock = ievent->sock;
|
|
|
|
|
|
|
|
UNUSED(worker);
|
|
|
|
|
|
|
|
REQUIRE(isc__nm_in_netthread());
|
2019-11-05 13:55:54 -08:00
|
|
|
REQUIRE(VALID_NMSOCK(sock));
|
|
|
|
REQUIRE(sock->type == isc_nm_tcpdnslistener);
|
2020-10-02 09:28:29 +02:00
|
|
|
REQUIRE(sock->tid == isc_nm_tid());
|
2019-11-05 13:55:54 -08:00
|
|
|
|
|
|
|
atomic_store(&sock->listening, false);
|
|
|
|
atomic_store(&sock->closed, true);
|
2020-10-02 09:28:29 +02:00
|
|
|
|
2020-06-20 15:03:05 -07:00
|
|
|
isc__nmsocket_clearcb(sock);
|
2019-11-05 13:55:54 -08:00
|
|
|
|
|
|
|
if (sock->outer != NULL) {
|
2020-06-04 23:13:54 -07:00
|
|
|
isc__nm_tcp_stoplistening(sock->outer);
|
2020-06-04 14:54:36 -07:00
|
|
|
isc__nmsocket_detach(&sock->outer);
|
2019-11-05 13:55:54 -08:00
|
|
|
}
|
2020-10-02 09:28:29 +02:00
|
|
|
|
|
|
|
isc__nmsocket_detach(&sock);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
isc__nm_tcpdns_stoplistening(isc_nmsocket_t *sock) {
|
|
|
|
REQUIRE(VALID_NMSOCK(sock));
|
|
|
|
REQUIRE(sock->type == isc_nm_tcpdnslistener);
|
|
|
|
|
|
|
|
isc__netievent_tcpdnsstop_t *ievent =
|
|
|
|
isc__nm_get_ievent(sock->mgr, netievent_tcpdnsstop);
|
|
|
|
isc__nmsocket_attach(sock, &ievent->sock);
|
|
|
|
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
|
|
|
|
(isc__netievent_t *)ievent);
|
2019-11-05 13:55:54 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_nm_tcpdns_sequential(isc_nmhandle_t *handle) {
|
2019-11-05 13:55:54 -08:00
|
|
|
REQUIRE(VALID_NMHANDLE(handle));
|
|
|
|
|
|
|
|
if (handle->sock->type != isc_nm_tcpdnssocket ||
|
2020-06-04 23:13:54 -07:00
|
|
|
handle->sock->outerhandle == NULL)
|
|
|
|
{
|
2019-11-05 13:55:54 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We don't want pipelining on this connection. That means
|
2019-11-08 10:52:49 -08:00
|
|
|
* that we need to pause after reading each request, and
|
|
|
|
* resume only after the request has been processed. This
|
|
|
|
* is done in resume_processing(), which is the socket's
|
|
|
|
* closehandle_cb callback, called whenever a handle
|
|
|
|
* is released.
|
2019-11-05 13:55:54 -08:00
|
|
|
*/
|
2020-07-01 16:17:09 -07:00
|
|
|
isc_nm_pauseread(handle->sock->outerhandle);
|
2019-11-05 13:55:54 -08:00
|
|
|
atomic_store(&handle->sock->sequential, true);
|
|
|
|
}
|
|
|
|
|
2019-11-20 22:33:35 +01:00
|
|
|
void
|
2020-11-02 19:58:05 -08:00
|
|
|
isc_nm_tcpdns_keepalive(isc_nmhandle_t *handle, bool value) {
|
2019-11-20 22:33:35 +01:00
|
|
|
REQUIRE(VALID_NMHANDLE(handle));
|
|
|
|
|
|
|
|
if (handle->sock->type != isc_nm_tcpdnssocket ||
|
2020-06-04 23:13:54 -07:00
|
|
|
handle->sock->outerhandle == NULL)
|
|
|
|
{
|
2019-11-20 22:33:35 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-11-02 19:58:05 -08:00
|
|
|
atomic_store(&handle->sock->keepalive, value);
|
|
|
|
atomic_store(&handle->sock->outerhandle->sock->keepalive, value);
|
2019-11-20 22:33:35 +01:00
|
|
|
}
|
|
|
|
|
2019-11-08 10:52:49 -08:00
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
resume_processing(void *arg) {
|
2020-02-12 13:59:18 +01:00
|
|
|
isc_nmsocket_t *sock = (isc_nmsocket_t *)arg;
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_result_t result;
|
2019-11-08 10:52:49 -08:00
|
|
|
|
|
|
|
REQUIRE(VALID_NMSOCK(sock));
|
2019-11-19 11:56:00 +01:00
|
|
|
REQUIRE(sock->tid == isc_nm_tid());
|
2019-11-08 10:52:49 -08:00
|
|
|
|
2020-06-04 23:13:54 -07:00
|
|
|
if (sock->type != isc_nm_tcpdnssocket || sock->outerhandle == NULL) {
|
2019-11-08 10:52:49 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-11-19 11:56:00 +01:00
|
|
|
if (atomic_load(&sock->ah) == 0) {
|
|
|
|
/* Nothing is active; sockets can timeout now */
|
2020-06-04 23:13:54 -07:00
|
|
|
atomic_store(&sock->outerhandle->sock->processing, false);
|
2020-03-05 22:56:31 +01:00
|
|
|
if (sock->timer_initialized) {
|
|
|
|
uv_timer_start(&sock->timer, dnstcp_readtimeout,
|
|
|
|
sock->read_timeout, 0);
|
2020-11-02 15:55:12 +01:00
|
|
|
sock->timer_running = true;
|
2020-03-05 22:56:31 +01:00
|
|
|
}
|
2019-11-19 11:56:00 +01:00
|
|
|
}
|
|
|
|
|
2019-11-08 10:52:49 -08:00
|
|
|
/*
|
2019-11-19 11:56:00 +01:00
|
|
|
* For sequential sockets: Process what's in the buffer, or
|
|
|
|
* if there aren't any messages buffered, resume reading.
|
2019-11-08 10:52:49 -08:00
|
|
|
*/
|
2019-11-20 22:33:35 +01:00
|
|
|
if (atomic_load(&sock->sequential)) {
|
2019-11-19 11:56:00 +01:00
|
|
|
isc_nmhandle_t *handle = NULL;
|
|
|
|
|
|
|
|
result = processbuffer(sock, &handle);
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
2020-06-04 23:13:54 -07:00
|
|
|
atomic_store(&sock->outerhandle->sock->processing,
|
|
|
|
true);
|
2020-03-05 22:56:31 +01:00
|
|
|
if (sock->timer_initialized) {
|
|
|
|
uv_timer_stop(&sock->timer);
|
|
|
|
}
|
2020-09-03 13:31:27 -07:00
|
|
|
isc_nmhandle_detach(&handle);
|
2020-06-04 23:13:54 -07:00
|
|
|
} else if (sock->outerhandle != NULL) {
|
2020-10-21 12:52:09 +02:00
|
|
|
isc_nm_resumeread(sock->outerhandle);
|
2019-11-19 11:56:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
2019-11-08 10:52:49 -08:00
|
|
|
}
|
2019-11-19 11:56:00 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* For pipelined sockets: If we're under the clients-per-connection
|
|
|
|
* limit, resume processing until we reach the limit again.
|
|
|
|
*/
|
|
|
|
do {
|
|
|
|
isc_nmhandle_t *dnshandle = NULL;
|
|
|
|
|
|
|
|
result = processbuffer(sock, &dnshandle);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
/*
|
|
|
|
* Nothing in the buffer; resume reading.
|
|
|
|
*/
|
2020-06-04 23:13:54 -07:00
|
|
|
if (sock->outerhandle != NULL) {
|
2020-07-01 16:17:09 -07:00
|
|
|
isc_nm_resumeread(sock->outerhandle);
|
2019-11-19 11:56:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-03-05 22:56:31 +01:00
|
|
|
if (sock->timer_initialized) {
|
|
|
|
uv_timer_stop(&sock->timer);
|
|
|
|
}
|
2020-06-04 23:13:54 -07:00
|
|
|
atomic_store(&sock->outerhandle->sock->processing, true);
|
2020-09-03 13:31:27 -07:00
|
|
|
isc_nmhandle_detach(&dnshandle);
|
2019-11-19 11:56:00 +01:00
|
|
|
} while (atomic_load(&sock->ah) < TCPDNS_CLIENTS_PER_CONN);
|
2019-11-08 10:52:49 -08:00
|
|
|
}
|
|
|
|
|
2019-11-05 13:55:54 -08:00
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
tcpdnssend_cb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
|
2020-06-22 16:45:47 -07:00
|
|
|
isc__nm_uvreq_t *req = (isc__nm_uvreq_t *)cbarg;
|
|
|
|
|
|
|
|
UNUSED(handle);
|
2019-11-05 13:55:54 -08:00
|
|
|
|
2020-06-22 16:45:47 -07:00
|
|
|
req->cb.send(req->handle, result, req->cbarg);
|
|
|
|
isc_mem_put(req->sock->mgr->mctx, req->uvbuf.base, req->uvbuf.len);
|
|
|
|
isc__nm_uvreq_put(&req, req->handle->sock);
|
2020-09-03 13:31:27 -07:00
|
|
|
isc_nmhandle_detach(&handle);
|
2020-06-22 16:45:47 -07:00
|
|
|
}
|
2019-11-05 13:55:54 -08:00
|
|
|
|
2020-11-02 15:55:12 +01:00
|
|
|
/*
|
|
|
|
* The socket is closing, outerhandle has been detached, listener is
|
|
|
|
* inactive, or the netmgr is closing: any operation on it should abort
|
|
|
|
* with ISC_R_CANCELED.
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
inactive(isc_nmsocket_t *sock) {
|
|
|
|
return (!isc__nmsocket_active(sock) || atomic_load(&sock->closing) ||
|
|
|
|
sock->outerhandle == NULL ||
|
|
|
|
(sock->listener != NULL &&
|
|
|
|
!isc__nmsocket_active(sock->listener)) ||
|
|
|
|
atomic_load(&sock->mgr->closing));
|
|
|
|
}
|
|
|
|
|
2020-06-22 16:45:47 -07:00
|
|
|
void
|
|
|
|
isc__nm_async_tcpdnssend(isc__networker_t *worker, isc__netievent_t *ev0) {
|
|
|
|
isc__netievent_tcpdnssend_t *ievent =
|
|
|
|
(isc__netievent_tcpdnssend_t *)ev0;
|
|
|
|
isc__nm_uvreq_t *req = ievent->req;
|
|
|
|
isc_nmsocket_t *sock = ievent->sock;
|
2020-11-02 15:55:12 +01:00
|
|
|
isc_nmhandle_t *sendhandle = NULL;
|
|
|
|
isc_region_t r;
|
2020-06-22 16:45:47 -07:00
|
|
|
|
2020-11-02 15:55:12 +01:00
|
|
|
REQUIRE(VALID_NMSOCK(sock));
|
|
|
|
REQUIRE(VALID_UVREQ(req));
|
2020-06-22 16:45:47 -07:00
|
|
|
REQUIRE(worker->id == sock->tid);
|
2020-09-18 12:27:40 +02:00
|
|
|
REQUIRE(sock->tid == isc_nm_tid());
|
2020-11-02 15:55:12 +01:00
|
|
|
REQUIRE(sock->type == isc_nm_tcpdnssocket);
|
2020-06-22 16:45:47 -07:00
|
|
|
|
2020-11-02 15:55:12 +01:00
|
|
|
if (inactive(sock)) {
|
2020-10-21 12:52:09 +02:00
|
|
|
req->cb.send(req->handle, ISC_R_CANCELED, req->cbarg);
|
2020-11-02 15:55:12 +01:00
|
|
|
isc_mem_put(sock->mgr->mctx, req->uvbuf.base, req->uvbuf.len);
|
2020-10-21 12:52:09 +02:00
|
|
|
isc__nm_uvreq_put(&req, req->handle->sock);
|
2020-11-02 15:55:12 +01:00
|
|
|
return;
|
2020-06-22 16:45:47 -07:00
|
|
|
}
|
2020-11-02 15:55:12 +01:00
|
|
|
|
|
|
|
r.base = (unsigned char *)req->uvbuf.base;
|
|
|
|
r.length = req->uvbuf.len;
|
|
|
|
isc_nmhandle_attach(sock->outerhandle, &sendhandle);
|
|
|
|
isc_nm_send(sendhandle, &r, tcpdnssend_cb, req);
|
2019-11-05 13:55:54 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* isc__nm_tcp_send sends buf to a peer on a socket.
|
|
|
|
*/
|
2020-10-21 12:52:09 +02:00
|
|
|
void
|
2019-11-05 13:55:54 -08:00
|
|
|
isc__nm_tcpdns_send(isc_nmhandle_t *handle, isc_region_t *region,
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_nm_cb_t cb, void *cbarg) {
|
2020-06-22 16:45:47 -07:00
|
|
|
isc__nm_uvreq_t *uvreq = NULL;
|
2019-11-05 13:55:54 -08:00
|
|
|
|
|
|
|
REQUIRE(VALID_NMHANDLE(handle));
|
|
|
|
|
|
|
|
isc_nmsocket_t *sock = handle->sock;
|
|
|
|
|
|
|
|
REQUIRE(VALID_NMSOCK(sock));
|
|
|
|
REQUIRE(sock->type == isc_nm_tcpdnssocket);
|
|
|
|
|
2020-11-02 15:55:12 +01:00
|
|
|
if (inactive(sock)) {
|
2020-10-21 12:52:09 +02:00
|
|
|
cb(handle, ISC_R_CANCELED, cbarg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-06-22 16:45:47 -07:00
|
|
|
uvreq = isc__nm_uvreq_get(sock->mgr, sock);
|
2020-09-03 13:31:27 -07:00
|
|
|
isc_nmhandle_attach(handle, &uvreq->handle);
|
2020-06-22 16:45:47 -07:00
|
|
|
uvreq->cb.send = cb;
|
|
|
|
uvreq->cbarg = cbarg;
|
2019-11-05 13:55:54 -08:00
|
|
|
|
2020-06-22 16:45:47 -07:00
|
|
|
uvreq->uvbuf.base = isc_mem_get(sock->mgr->mctx, region->length + 2);
|
|
|
|
uvreq->uvbuf.len = region->length + 2;
|
|
|
|
*(uint16_t *)uvreq->uvbuf.base = htons(region->length);
|
|
|
|
memmove(uvreq->uvbuf.base + 2, region->base, region->length);
|
2019-11-05 13:55:54 -08:00
|
|
|
|
2020-11-02 15:55:12 +01:00
|
|
|
isc__netievent_tcpdnssend_t *ievent = NULL;
|
2019-11-05 13:55:54 -08:00
|
|
|
|
2020-11-02 15:55:12 +01:00
|
|
|
ievent = isc__nm_get_ievent(sock->mgr, netievent_tcpdnssend);
|
|
|
|
ievent->req = uvreq;
|
|
|
|
ievent->sock = sock;
|
2020-06-22 16:45:47 -07:00
|
|
|
|
2020-11-02 15:55:12 +01:00
|
|
|
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
|
|
|
|
(isc__netievent_t *)ievent);
|
2019-11-05 13:55:54 -08:00
|
|
|
}
|
|
|
|
|
2019-12-06 22:25:52 +01:00
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
tcpdns_close_direct(isc_nmsocket_t *sock) {
|
2019-12-07 23:43:52 +01:00
|
|
|
REQUIRE(sock->tid == isc_nm_tid());
|
2020-06-09 17:07:16 -07:00
|
|
|
|
2020-11-02 15:55:12 +01:00
|
|
|
if (sock->timer_running) {
|
|
|
|
uv_timer_stop(&sock->timer);
|
|
|
|
sock->timer_running = false;
|
|
|
|
}
|
|
|
|
|
2019-12-06 22:25:52 +01:00
|
|
|
/* We don't need atomics here, it's all in single network thread */
|
2020-06-20 15:03:05 -07:00
|
|
|
if (sock->self != NULL) {
|
|
|
|
isc__nmsocket_detach(&sock->self);
|
|
|
|
} else if (sock->timer_initialized) {
|
2020-03-02 12:10:26 +01:00
|
|
|
/*
|
|
|
|
* We need to fire the timer callback to clean it up,
|
|
|
|
* it will then call us again (via detach) so that we
|
|
|
|
* can finally close the socket.
|
|
|
|
*/
|
2019-12-06 22:25:52 +01:00
|
|
|
sock->timer_initialized = false;
|
|
|
|
uv_timer_stop(&sock->timer);
|
2020-02-12 13:59:18 +01:00
|
|
|
uv_close((uv_handle_t *)&sock->timer, timer_close_cb);
|
2020-03-02 12:10:26 +01:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* At this point we're certain that there are no external
|
|
|
|
* references, we can close everything.
|
|
|
|
*/
|
2020-06-04 23:13:54 -07:00
|
|
|
if (sock->outerhandle != NULL) {
|
2020-06-20 15:03:05 -07:00
|
|
|
isc__nmsocket_clearcb(sock->outerhandle->sock);
|
2020-09-03 13:31:27 -07:00
|
|
|
isc_nmhandle_detach(&sock->outerhandle);
|
2020-03-02 12:10:26 +01:00
|
|
|
}
|
|
|
|
if (sock->listener != NULL) {
|
2020-06-04 14:54:36 -07:00
|
|
|
isc__nmsocket_detach(&sock->listener);
|
2020-03-02 12:10:26 +01:00
|
|
|
}
|
|
|
|
atomic_store(&sock->closed, true);
|
2020-06-04 23:13:54 -07:00
|
|
|
isc__nmsocket_prep_destroy(sock);
|
2019-12-06 22:25:52 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
isc__nm_tcpdns_close(isc_nmsocket_t *sock) {
|
2019-12-06 22:25:52 +01:00
|
|
|
REQUIRE(VALID_NMSOCK(sock));
|
|
|
|
REQUIRE(sock->type == isc_nm_tcpdnssocket);
|
|
|
|
|
2020-11-02 15:55:12 +01:00
|
|
|
if (!atomic_compare_exchange_strong(&sock->closing, &(bool){ false },
|
|
|
|
true)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-12-06 22:25:52 +01:00
|
|
|
if (sock->tid == isc_nm_tid()) {
|
|
|
|
tcpdns_close_direct(sock);
|
|
|
|
} else {
|
|
|
|
isc__netievent_tcpdnsclose_t *ievent =
|
|
|
|
isc__nm_get_ievent(sock->mgr, netievent_tcpdnsclose);
|
|
|
|
|
|
|
|
ievent->sock = sock;
|
|
|
|
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
|
2020-02-12 13:59:18 +01:00
|
|
|
(isc__netievent_t *)ievent);
|
2019-12-06 22:25:52 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
isc__nm_async_tcpdnsclose(isc__networker_t *worker, isc__netievent_t *ev0) {
|
2019-12-06 22:25:52 +01:00
|
|
|
isc__netievent_tcpdnsclose_t *ievent =
|
2020-02-12 13:59:18 +01:00
|
|
|
(isc__netievent_tcpdnsclose_t *)ev0;
|
2020-11-02 15:55:12 +01:00
|
|
|
isc_nmsocket_t *sock = ievent->sock;
|
2019-12-06 22:25:52 +01:00
|
|
|
|
2020-11-02 15:55:12 +01:00
|
|
|
REQUIRE(VALID_NMSOCK(sock));
|
|
|
|
REQUIRE(sock->tid == isc_nm_tid());
|
|
|
|
|
|
|
|
UNUSED(worker);
|
2019-12-06 22:25:52 +01:00
|
|
|
|
|
|
|
tcpdns_close_direct(ievent->sock);
|
2019-11-05 13:55:54 -08:00
|
|
|
}
|
2020-09-05 11:07:40 -07:00
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
isc_mem_t *mctx;
|
|
|
|
isc_nm_cb_t cb;
|
|
|
|
void *cbarg;
|
|
|
|
size_t extrahandlesize;
|
|
|
|
} tcpconnect_t;
|
|
|
|
|
|
|
|
static void
|
|
|
|
tcpdnsconnect_cb(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
|
|
|
|
tcpconnect_t *conn = (tcpconnect_t *)arg;
|
|
|
|
isc_nm_cb_t cb = conn->cb;
|
|
|
|
void *cbarg = conn->cbarg;
|
|
|
|
size_t extrahandlesize = conn->extrahandlesize;
|
|
|
|
isc_nmsocket_t *dnssock = NULL;
|
2020-11-04 20:59:31 +01:00
|
|
|
isc_nmhandle_t *readhandle = NULL;
|
2020-09-05 11:07:40 -07:00
|
|
|
|
|
|
|
REQUIRE(result != ISC_R_SUCCESS || VALID_NMHANDLE(handle));
|
|
|
|
|
|
|
|
isc_mem_putanddetach(&conn->mctx, conn, sizeof(*conn));
|
|
|
|
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
cb(NULL, result, cbarg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
dnssock = isc_mem_get(handle->sock->mgr->mctx, sizeof(*dnssock));
|
|
|
|
isc__nmsocket_init(dnssock, handle->sock->mgr, isc_nm_tcpdnssocket,
|
|
|
|
handle->sock->iface);
|
|
|
|
|
|
|
|
dnssock->extrahandlesize = extrahandlesize;
|
|
|
|
isc_nmhandle_attach(handle, &dnssock->outerhandle);
|
|
|
|
|
|
|
|
dnssock->peer = handle->sock->peer;
|
|
|
|
dnssock->read_timeout = handle->sock->mgr->init;
|
|
|
|
dnssock->tid = isc_nm_tid();
|
|
|
|
|
|
|
|
atomic_init(&dnssock->client, true);
|
2020-11-04 20:59:31 +01:00
|
|
|
|
|
|
|
readhandle = isc__nmhandle_get(dnssock, NULL, NULL);
|
|
|
|
|
|
|
|
INSIST(dnssock->statichandle != NULL);
|
|
|
|
INSIST(dnssock->statichandle == readhandle);
|
|
|
|
INSIST(readhandle->sock == dnssock);
|
|
|
|
INSIST(dnssock->recv_cb == NULL);
|
2020-09-05 11:07:40 -07:00
|
|
|
|
|
|
|
uv_timer_init(&dnssock->mgr->workers[isc_nm_tid()].loop,
|
|
|
|
&dnssock->timer);
|
|
|
|
dnssock->timer.data = dnssock;
|
|
|
|
dnssock->timer_initialized = true;
|
|
|
|
uv_timer_start(&dnssock->timer, dnstcp_readtimeout,
|
|
|
|
dnssock->read_timeout, 0);
|
2020-11-02 15:55:12 +01:00
|
|
|
dnssock->timer_running = true;
|
2020-09-05 11:07:40 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The connection is now established; we start reading immediately,
|
|
|
|
* before we've been asked to. We'll read and buffer at most one
|
|
|
|
* packet.
|
|
|
|
*/
|
|
|
|
isc_nm_read(handle, dnslisten_readcb, dnssock);
|
2020-11-04 20:59:31 +01:00
|
|
|
cb(readhandle, ISC_R_SUCCESS, cbarg);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The sock is now attached to the handle.
|
|
|
|
*/
|
2020-09-05 11:07:40 -07:00
|
|
|
isc__nmsocket_detach(&dnssock);
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
|
|
|
|
isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
|
|
|
|
size_t extrahandlesize) {
|
|
|
|
tcpconnect_t *conn = isc_mem_get(mgr->mctx, sizeof(tcpconnect_t));
|
|
|
|
|
|
|
|
*conn = (tcpconnect_t){ .cb = cb,
|
|
|
|
.cbarg = cbarg,
|
|
|
|
.extrahandlesize = extrahandlesize };
|
|
|
|
isc_mem_attach(mgr->mctx, &conn->mctx);
|
|
|
|
return (isc_nm_tcpconnect(mgr, local, peer, tcpdnsconnect_cb, conn,
|
|
|
|
timeout, 0));
|
|
|
|
}
|
|
|
|
|
2020-11-02 15:55:12 +01:00
|
|
|
void
|
2020-09-05 11:07:40 -07:00
|
|
|
isc__nm_tcpdns_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
|
|
|
|
isc_nmsocket_t *sock = handle->sock;
|
|
|
|
isc__netievent_tcpdnsread_t *ievent = NULL;
|
|
|
|
isc_nmhandle_t *eventhandle = NULL;
|
|
|
|
|
|
|
|
REQUIRE(handle == sock->statichandle);
|
|
|
|
REQUIRE(sock->recv_cb == NULL);
|
|
|
|
REQUIRE(sock->tid == isc_nm_tid());
|
|
|
|
REQUIRE(atomic_load(&sock->client));
|
|
|
|
|
2020-11-02 15:55:12 +01:00
|
|
|
if (inactive(sock)) {
|
|
|
|
cb(handle, ISC_R_NOTCONNECTED, NULL, cbarg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-09-05 11:07:40 -07:00
|
|
|
/*
|
|
|
|
* This MUST be done asynchronously, no matter which thread we're
|
|
|
|
* in. The callback function for isc_nm_read() often calls
|
|
|
|
* isc_nm_read() again; if we tried to do that synchronously
|
|
|
|
* we'd clash in processbuffer() and grow the stack indefinitely.
|
|
|
|
*/
|
|
|
|
ievent = isc__nm_get_ievent(sock->mgr, netievent_tcpdnsread);
|
|
|
|
ievent->sock = sock;
|
|
|
|
|
|
|
|
sock->recv_cb = cb;
|
|
|
|
sock->recv_cbarg = cbarg;
|
|
|
|
|
2020-11-02 19:58:05 -08:00
|
|
|
sock->read_timeout = (atomic_load(&sock->keepalive)
|
|
|
|
? sock->mgr->keepalive
|
|
|
|
: sock->mgr->idle);
|
|
|
|
|
2020-09-05 11:07:40 -07:00
|
|
|
/*
|
|
|
|
* Add a reference to the handle to keep it from being freed by
|
|
|
|
* the caller; it will be detached in in isc__nm_async_tcpdnsread().
|
|
|
|
*/
|
|
|
|
isc_nmhandle_attach(handle, &eventhandle);
|
|
|
|
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
|
|
|
|
(isc__netievent_t *)ievent);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
isc__nm_async_tcpdnsread(isc__networker_t *worker, isc__netievent_t *ev0) {
|
|
|
|
isc_result_t result;
|
|
|
|
isc__netievent_tcpdnsread_t *ievent =
|
|
|
|
(isc__netievent_tcpdnsclose_t *)ev0;
|
|
|
|
isc_nmsocket_t *sock = ievent->sock;
|
|
|
|
isc_nmhandle_t *handle = NULL, *newhandle = NULL;
|
|
|
|
|
|
|
|
REQUIRE(VALID_NMSOCK(sock));
|
|
|
|
REQUIRE(worker->id == sock->tid);
|
|
|
|
REQUIRE(sock->tid == isc_nm_tid());
|
|
|
|
|
|
|
|
handle = sock->statichandle;
|
|
|
|
|
2020-11-02 15:55:12 +01:00
|
|
|
if (inactive(sock)) {
|
|
|
|
isc_nm_recv_cb_t cb = sock->recv_cb;
|
|
|
|
void *cbarg = sock->recv_cbarg;
|
|
|
|
|
|
|
|
isc__nmsocket_clearcb(sock);
|
|
|
|
if (cb != NULL) {
|
|
|
|
cb(handle, ISC_R_NOTCONNECTED, NULL, cbarg);
|
2020-09-05 11:07:40 -07:00
|
|
|
}
|
2020-11-02 15:55:12 +01:00
|
|
|
|
2020-09-05 11:07:40 -07:00
|
|
|
isc_nmhandle_detach(&handle);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Maybe we have a packet already?
|
|
|
|
*/
|
|
|
|
result = processbuffer(sock, &newhandle);
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
atomic_store(&sock->outerhandle->sock->processing, true);
|
|
|
|
if (sock->timer_initialized) {
|
|
|
|
uv_timer_stop(&sock->timer);
|
|
|
|
}
|
|
|
|
isc_nmhandle_detach(&newhandle);
|
|
|
|
} else if (sock->outerhandle != NULL) {
|
|
|
|
/* Restart reading, wait for the callback */
|
|
|
|
atomic_store(&sock->outerhandle->sock->processing, false);
|
|
|
|
if (sock->timer_initialized) {
|
|
|
|
uv_timer_start(&sock->timer, dnstcp_readtimeout,
|
|
|
|
sock->read_timeout, 0);
|
2020-11-02 15:55:12 +01:00
|
|
|
sock->timer_running = true;
|
2020-09-05 11:07:40 -07:00
|
|
|
}
|
|
|
|
isc_nm_resumeread(sock->outerhandle);
|
|
|
|
} else {
|
|
|
|
isc_nm_recv_cb_t cb = sock->recv_cb;
|
|
|
|
void *cbarg = sock->recv_cbarg;
|
|
|
|
|
|
|
|
isc__nmsocket_clearcb(sock);
|
|
|
|
cb(handle, ISC_R_NOTCONNECTED, NULL, cbarg);
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_nmhandle_detach(&handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
isc__nm_tcpdns_cancelread(isc_nmhandle_t *handle) {
|
|
|
|
isc_nmsocket_t *sock = NULL;
|
|
|
|
isc__netievent_tcpdnscancel_t *ievent = NULL;
|
|
|
|
|
|
|
|
REQUIRE(VALID_NMHANDLE(handle));
|
|
|
|
|
|
|
|
sock = handle->sock;
|
|
|
|
|
|
|
|
REQUIRE(sock->type == isc_nm_tcpdnssocket);
|
|
|
|
|
|
|
|
ievent = isc__nm_get_ievent(sock->mgr, netievent_tcpdnscancel);
|
|
|
|
ievent->sock = sock;
|
|
|
|
isc_nmhandle_attach(handle, &ievent->handle);
|
|
|
|
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
|
|
|
|
(isc__netievent_t *)ievent);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
isc__nm_async_tcpdnscancel(isc__networker_t *worker, isc__netievent_t *ev0) {
|
|
|
|
isc__netievent_tcpdnscancel_t *ievent =
|
|
|
|
(isc__netievent_tcpdnscancel_t *)ev0;
|
|
|
|
isc_nmsocket_t *sock = ievent->sock;
|
|
|
|
isc_nmhandle_t *handle = ievent->handle;
|
|
|
|
|
|
|
|
REQUIRE(VALID_NMSOCK(sock));
|
|
|
|
REQUIRE(worker->id == sock->tid);
|
|
|
|
REQUIRE(sock->tid == isc_nm_tid());
|
|
|
|
|
|
|
|
if (atomic_load(&sock->client)) {
|
|
|
|
isc_nm_recv_cb_t cb;
|
|
|
|
void *cbarg = NULL;
|
|
|
|
|
|
|
|
cb = sock->recv_cb;
|
|
|
|
cbarg = sock->recv_cbarg;
|
|
|
|
isc__nmsocket_clearcb(sock);
|
|
|
|
|
|
|
|
if (cb != NULL) {
|
|
|
|
cb(handle, ISC_R_EOF, NULL, cbarg);
|
|
|
|
}
|
|
|
|
|
|
|
|
isc__nm_tcp_cancelread(sock->outerhandle);
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_nmhandle_detach(&handle);
|
|
|
|
}
|
2020-11-02 19:58:05 -08:00
|
|
|
|
|
|
|
void
|
|
|
|
isc__nm_tcpdns_settimeout(isc_nmhandle_t *handle, uint32_t timeout) {
|
|
|
|
isc_nmsocket_t *sock = NULL;
|
|
|
|
|
|
|
|
REQUIRE(VALID_NMHANDLE(handle));
|
|
|
|
|
|
|
|
sock = handle->sock;
|
|
|
|
|
|
|
|
if (sock->outerhandle != NULL) {
|
|
|
|
isc__nm_tcp_settimeout(sock->outerhandle, timeout);
|
|
|
|
}
|
|
|
|
|
|
|
|
sock->read_timeout = timeout;
|
|
|
|
if (sock->timer_running) {
|
|
|
|
uv_timer_start(&sock->timer, dnstcp_readtimeout,
|
|
|
|
sock->read_timeout, 0);
|
|
|
|
}
|
|
|
|
}
|