2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-30 05:57:52 +00:00

Merge branch '3132-add-send-timeout' into 'main'

Add timeout when writing TCP data

Closes #3132

See merge request isc-projects/bind9!5848
This commit is contained in:
Ondřej Surý 2022-02-17 08:45:17 +00:00
commit ae4cd57ed5
14 changed files with 345 additions and 69 deletions

View File

@ -1,3 +1,7 @@
5807. [bug] Add a TCP "write" timer, and time out writing
connections after the "tcp-idle-timeout" period
has elapsed. [GL #3132]
5806. [bug] An error in checking the "blackhole" ACL could cause
DNS requests sent by named to fail if the
destination address or prefix was specifically

View File

@ -20,6 +20,11 @@ copy_setports ns1/named.conf.in ns1/named.conf
# tcp-initial-timeout interval
#
$PYTHON -c "
print('large IN TXT', end=' ')
for a in range(128):
print('\"%s\"' % ('A' * 240), end=' ')
print('')
for a in range(150000):
print('%s IN NS a' % (a))
print('%s IN NS b' % (a))" > ns1/large.db

View File

@ -51,7 +51,7 @@ def test_initial_timeout(port):
try:
(sbytes, stime) = dns.query.send_tcp(sock, msg, timeout())
(response, rtime) = dns.query.receive_tcp(sock, timeout())
except ConnectionResetError as e:
except ConnectionError as e:
raise EOFError from e
@ -83,7 +83,7 @@ def test_idle_timeout(port):
try:
(sbytes, stime) = dns.query.send_tcp(sock, msg, timeout())
(response, rtime) = dns.query.receive_tcp(sock, timeout())
except ConnectionResetError as e:
except ConnectionError as e:
raise EOFError from e
@ -152,7 +152,7 @@ def test_pipelining_timeout(port):
try:
(sbytes, stime) = dns.query.send_tcp(sock, msg, timeout())
(response, rtime) = dns.query.receive_tcp(sock, timeout())
except ConnectionResetError as e:
except ConnectionError as e:
raise EOFError from e
@ -190,3 +190,33 @@ def test_long_axfr(port):
if soa is not None:
break
assert soa is not None
@pytest.mark.dnspython
@pytest.mark.dnspython2
def test_send_timeout(port):
import dns.query
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.connect(("10.53.0.1", port))
# Send and receive single large RDATA over TCP
msg = create_msg("large.example.", "TXT")
(sbytes, stime) = dns.query.send_tcp(sock, msg, timeout())
(response, rtime) = dns.query.receive_tcp(sock, timeout())
# Send and receive 28 large (~32k) DNS queries that should
# fill the default maximum 208k TCP send buffer
for n in range(28):
(sbytes, stime) = dns.query.send_tcp(sock, msg, timeout())
# configure idle interval is 5 seconds, sleep 6 to make sure we are
# above the interval
time.sleep(6)
with pytest.raises(EOFError):
try:
(sbytes, stime) = dns.query.send_tcp(sock, msg, timeout())
(response, rtime) = dns.query.receive_tcp(sock, timeout())
except ConnectionError as e:
raise EOFError from e

View File

@ -70,3 +70,9 @@ Bug Fixes
to ``none``. ``blackhole`` worked correctly when it was left unset, or
if only positive-match elements were included. This has now been fixed.
:gl:`#3157`
- TCP connections could hang indefinitely if the TCP write buffers
were full because of the other party not reading sent data. This has
been fixed by adding a "write" timer. Connections that are hung
while writing will now time out after the ``tcp-idle-timeout`` period
has elapsed. :gl:`#3132`

View File

@ -697,3 +697,6 @@ isc__nm_force_tid(int tid);
* Force the thread ID to 'tid'. This is STRICTLY for use in unit
* tests and should not be used in any production code.
*/
void
isc_nmhandle_setwritetimeout(isc_nmhandle_t *handle, uint64_t write_timeout);

View File

@ -950,10 +950,17 @@ struct isc_nmsocket {
/*%
* TCP read/connect timeout timers.
*/
uv_timer_t timer;
uv_timer_t read_timer;
uint64_t read_timeout;
uint64_t connect_timeout;
/*%
* TCP write timeout timer.
*/
uv_timer_t write_timer;
uint64_t write_timeout;
int64_t writes;
/*% outer socket is for 'wrapped' sockets - e.g. tcpdns in tcp */
isc_nmsocket_t *outer;
@ -2071,12 +2078,25 @@ isc__nm_failed_connect_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req,
void
isc__nm_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result, bool async);
void
isc__nmsocket_connecttimeout_cb(uv_timer_t *timer);
void
isc__nm_accept_connection_log(isc_result_t result, bool can_log_quota);
/*
* Timeout callbacks
*/
void
isc__nmsocket_connecttimeout_cb(uv_timer_t *timer);
void
isc__nmsocket_readtimeout_cb(uv_timer_t *timer);
void
isc__nmsocket_writetimeout_cb(uv_timer_t *timer);
/*%<
*
* 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.
*/
#define STREAM_CLIENTS_PER_CONN 23
#define UV_RUNTIME_CHECK(func, ret) \

View File

@ -604,6 +604,14 @@ isc_nm_maxudp(isc_nm_t *mgr, uint32_t maxudp) {
atomic_store(&mgr->maxudp, maxudp);
}
void
isc_nmhandle_setwritetimeout(isc_nmhandle_t *handle, uint64_t write_timeout) {
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
handle->sock->write_timeout = write_timeout;
}
void
isc_nm_settimeouts(isc_nm_t *mgr, uint32_t init, uint32_t idle,
uint32_t keepalive, uint32_t advertised) {
@ -1977,7 +1985,7 @@ isc__nm_failed_connect_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req,
REQUIRE(req->cb.connect != NULL);
isc__nmsocket_timer_stop(sock);
uv_handle_set_data((uv_handle_t *)&sock->timer, sock);
uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock);
INSIST(atomic_compare_exchange_strong(&sock->connecting,
&(bool){ true }, false));
@ -2070,7 +2078,21 @@ isc__nm_accept_connection_log(isc_result_t result, bool can_log_quota) {
isc_result_totext(result));
}
static void
void
isc__nmsocket_writetimeout_cb(uv_timer_t *timer) {
isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)timer);
int r = uv_timer_stop(&sock->write_timer);
UV_RUNTIME_CHECK(uv_timer_stop, r);
/* The shutdown will be handled in the respective close functions */
r = uv_tcp_close_reset(&sock->uv_handle.tcp, NULL);
UV_RUNTIME_CHECK(uv_tcp_close_reset, r);
isc__nmsocket_shutdown(sock);
}
void
isc__nmsocket_readtimeout_cb(uv_timer_t *timer) {
isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)timer);
@ -2108,7 +2130,7 @@ isc__nmsocket_timer_restart(isc_nmsocket_t *sock) {
return;
}
r = uv_timer_start(&sock->timer,
r = uv_timer_start(&sock->read_timer,
isc__nmsocket_connecttimeout_cb,
sock->connect_timeout + 10, 0);
UV_RUNTIME_CHECK(uv_timer_start, r);
@ -2120,7 +2142,8 @@ isc__nmsocket_timer_restart(isc_nmsocket_t *sock) {
return;
}
r = uv_timer_start(&sock->timer, isc__nmsocket_readtimeout_cb,
r = uv_timer_start(&sock->read_timer,
isc__nmsocket_readtimeout_cb,
sock->read_timeout, 0);
UV_RUNTIME_CHECK(uv_timer_start, r);
}
@ -2130,7 +2153,7 @@ bool
isc__nmsocket_timer_running(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
return (uv_is_active((uv_handle_t *)&sock->timer));
return (uv_is_active((uv_handle_t *)&sock->read_timer));
}
void
@ -2152,7 +2175,7 @@ isc__nmsocket_timer_stop(isc_nmsocket_t *sock) {
/* uv_timer_stop() is idempotent, no need to check if running */
r = uv_timer_stop(&sock->timer);
r = uv_timer_stop(&sock->read_timer);
UV_RUNTIME_CHECK(uv_timer_stop, r);
}
@ -2404,7 +2427,7 @@ isc_nmhandle_cleartimeout(isc_nmhandle_t *handle) {
default:
handle->sock->read_timeout = 0;
if (uv_is_active((uv_handle_t *)&handle->sock->timer)) {
if (uv_is_active((uv_handle_t *)&handle->sock->read_timer)) {
isc__nmsocket_timer_stop(handle->sock);
}
}
@ -2446,6 +2469,8 @@ isc_nmhandle_keepalive(isc_nmhandle_t *handle, bool value) {
atomic_store(&sock->keepalive, value);
sock->read_timeout = value ? atomic_load(&sock->mgr->keepalive)
: atomic_load(&sock->mgr->idle);
sock->write_timeout = value ? atomic_load(&sock->mgr->keepalive)
: atomic_load(&sock->mgr->idle);
break;
#if HAVE_LIBNGHTTP2
case isc_nm_tlssocket:

View File

@ -140,8 +140,13 @@ tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
UV_RUNTIME_CHECK(uv_tcp_init, r);
uv_handle_set_data(&sock->uv_handle.handle, sock);
r = uv_timer_init(&worker->loop, &sock->timer);
r = uv_timer_init(&worker->loop, &sock->read_timer);
UV_RUNTIME_CHECK(uv_timer_init, r);
uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock);
r = uv_timer_init(&worker->loop, &sock->write_timer);
UV_RUNTIME_CHECK(uv_timer_init, r);
uv_handle_set_data((uv_handle_t *)&sock->write_timer, sock);
r = uv_tcp_open(&sock->uv_handle.tcp, sock->fd);
if (r != 0) {
@ -170,7 +175,8 @@ tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
}
isc__nm_incstats(sock, STATID_CONNECT);
uv_handle_set_data((uv_handle_t *)&sock->timer, &req->uv_req.connect);
uv_handle_set_data((uv_handle_t *)&sock->read_timer,
&req->uv_req.connect);
isc__nmsocket_timer_start(sock);
atomic_store(&sock->connected, true);
@ -231,7 +237,7 @@ tcp_connect_cb(uv_connect_t *uvreq, int status) {
REQUIRE(sock->tid == isc_nm_tid());
isc__nmsocket_timer_stop(sock);
uv_handle_set_data((uv_handle_t *)&sock->timer, sock);
uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock);
if (!atomic_load(&sock->connecting)) {
return;
@ -527,10 +533,13 @@ isc__nm_async_tcplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
/* This keeps the socket alive after everything else is gone */
isc__nmsocket_attach(sock, &(isc_nmsocket_t *){ NULL });
r = uv_timer_init(&worker->loop, &sock->timer);
r = uv_timer_init(&worker->loop, &sock->read_timer);
UV_RUNTIME_CHECK(uv_timer_init, r);
uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock);
uv_handle_set_data((uv_handle_t *)&sock->timer, sock);
r = uv_timer_init(&worker->loop, &sock->write_timer);
UV_RUNTIME_CHECK(uv_timer_init, r);
uv_handle_set_data((uv_handle_t *)&sock->write_timer, sock);
LOCK(&sock->parent->lock);
@ -974,9 +983,13 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) {
UV_RUNTIME_CHECK(uv_tcp_init, r);
uv_handle_set_data(&csock->uv_handle.handle, csock);
r = uv_timer_init(&worker->loop, &csock->timer);
r = uv_timer_init(&worker->loop, &csock->read_timer);
UV_RUNTIME_CHECK(uv_timer_init, r);
uv_handle_set_data((uv_handle_t *)&csock->timer, csock);
uv_handle_set_data((uv_handle_t *)&csock->read_timer, csock);
r = uv_timer_init(&worker->loop, &csock->write_timer);
UV_RUNTIME_CHECK(uv_timer_init, r);
uv_handle_set_data((uv_handle_t *)&csock->write_timer, csock);
r = uv_accept(&ssock->uv_handle.stream, &csock->uv_handle.stream);
if (r != 0) {
@ -1071,6 +1084,13 @@ isc__nm_tcp_send(isc_nmhandle_t *handle, const isc_region_t *region,
uvreq->cb.send = cb;
uvreq->cbarg = cbarg;
if (sock->write_timeout == 0) {
sock->write_timeout =
(atomic_load(&sock->keepalive)
? atomic_load(&sock->mgr->keepalive)
: atomic_load(&sock->mgr->idle));
}
ievent = isc__nm_get_netievent_tcpsend(sock->mgr, sock, uvreq);
isc__nm_maybe_enqueue_ievent(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
@ -1081,11 +1101,17 @@ isc__nm_tcp_send(isc_nmhandle_t *handle, const isc_region_t *region,
static void
tcp_send_cb(uv_write_t *req, int status) {
isc__nm_uvreq_t *uvreq = (isc__nm_uvreq_t *)req->data;
REQUIRE(VALID_UVREQ(uvreq));
REQUIRE(VALID_NMHANDLE(uvreq->handle));
isc_nmsocket_t *sock = uvreq->sock;
if (--sock->writes == 0) {
int r = uv_timer_stop(&sock->write_timer);
UV_RUNTIME_CHECK(uv_timer_stop, r);
}
if (status < 0) {
isc__nm_incstats(sock, STATID_SENDFAIL);
failed_send_cb(sock, uvreq, isc__nm_uverr2result(status));
@ -1129,6 +1155,11 @@ tcp_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
return (ISC_R_CANCELED);
}
r = uv_timer_start(&sock->write_timer, isc__nmsocket_writetimeout_cb,
sock->write_timeout, 0);
UV_RUNTIME_CHECK(uv_timer_start, r);
RUNTIME_CHECK(sock->writes++ >= 0);
r = uv_write(&req->uv_req.write, &sock->uv_handle.stream, &req->uvbuf,
1, tcp_send_cb);
if (r < 0) {
@ -1192,7 +1223,7 @@ tcp_close_cb(uv_handle_t *handle) {
}
static void
timer_close_cb(uv_handle_t *handle) {
read_timer_close_cb(uv_handle_t *handle) {
isc_nmsocket_t *sock = uv_handle_get_data(handle);
uv_handle_set_data(handle, NULL);
@ -1205,6 +1236,17 @@ timer_close_cb(uv_handle_t *handle) {
}
}
static void
write_timer_close_cb(uv_handle_t *timer) {
isc_nmsocket_t *sock = uv_handle_get_data(timer);
uv_handle_set_data(timer, NULL);
REQUIRE(VALID_NMSOCK(sock));
uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock);
uv_close((uv_handle_t *)&sock->read_timer, read_timer_close_cb);
}
static void
stop_tcp_child(isc_nmsocket_t *sock) {
REQUIRE(sock->type == isc_nm_tcpsocket);
@ -1257,6 +1299,8 @@ stop_tcp_parent(isc_nmsocket_t *sock) {
static void
tcp_close_direct(isc_nmsocket_t *sock) {
int r;
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
REQUIRE(atomic_load(&sock->closing));
@ -1278,8 +1322,10 @@ tcp_close_direct(isc_nmsocket_t *sock) {
isc__nmsocket_timer_stop(sock);
isc__nm_stop_reading(sock);
uv_handle_set_data((uv_handle_t *)&sock->timer, sock);
uv_close((uv_handle_t *)&sock->timer, timer_close_cb);
r = uv_timer_stop(&sock->write_timer);
UV_RUNTIME_CHECK(uv_timer_stop, r);
uv_handle_set_data((uv_handle_t *)&sock->write_timer, sock);
uv_close((uv_handle_t *)&sock->write_timer, write_timer_close_cb);
}
void
@ -1401,7 +1447,7 @@ isc__nm_async_tcpcancel(isc__networker_t *worker, isc__netievent_t *ev0) {
REQUIRE(sock->tid == isc_nm_tid());
UNUSED(worker);
uv_timer_stop(&sock->timer);
uv_timer_stop(&sock->read_timer);
isc__nm_tcp_failed_read_cb(sock, ISC_R_EOF);
}

View File

@ -37,13 +37,6 @@
#include "netmgr-int.h"
#include "uv-compat.h"
/*%<
*
* 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.
*/
static atomic_uint_fast32_t last_tcpdnsquota_log = ATOMIC_VAR_INIT(0);
static bool
@ -105,8 +98,13 @@ tcpdns_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
UV_RUNTIME_CHECK(uv_tcp_init, r);
uv_handle_set_data(&sock->uv_handle.handle, sock);
r = uv_timer_init(&worker->loop, &sock->timer);
r = uv_timer_init(&worker->loop, &sock->read_timer);
UV_RUNTIME_CHECK(uv_timer_init, r);
uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock);
r = uv_timer_init(&worker->loop, &sock->write_timer);
UV_RUNTIME_CHECK(uv_timer_init, r);
uv_handle_set_data((uv_handle_t *)&sock->write_timer, sock);
if (isc__nm_closing(sock)) {
result = ISC_R_SHUTTINGDOWN;
@ -144,7 +142,8 @@ tcpdns_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
}
isc__nm_incstats(sock, STATID_CONNECT);
uv_handle_set_data((uv_handle_t *)&sock->timer, &req->uv_req.connect);
uv_handle_set_data((uv_handle_t *)&sock->read_timer,
&req->uv_req.connect);
isc__nmsocket_timer_start(sock);
atomic_store(&sock->connected, true);
@ -205,7 +204,7 @@ tcpdns_connect_cb(uv_connect_t *uvreq, int status) {
REQUIRE(sock->tid == isc_nm_tid());
isc__nmsocket_timer_stop(sock);
uv_handle_set_data((uv_handle_t *)&sock->timer, sock);
uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock);
if (!atomic_load(&sock->connecting)) {
return;
@ -497,9 +496,13 @@ isc__nm_async_tcpdnslisten(isc__networker_t *worker, isc__netievent_t *ev0) {
/* This keeps the socket alive after everything else is gone */
isc__nmsocket_attach(sock, &(isc_nmsocket_t *){ NULL });
r = uv_timer_init(&worker->loop, &sock->timer);
r = uv_timer_init(&worker->loop, &sock->read_timer);
UV_RUNTIME_CHECK(uv_timer_init, r);
uv_handle_set_data((uv_handle_t *)&sock->timer, sock);
uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock);
r = uv_timer_init(&worker->loop, &sock->write_timer);
UV_RUNTIME_CHECK(uv_timer_init, r);
uv_handle_set_data((uv_handle_t *)&sock->write_timer, sock);
LOCK(&sock->parent->lock);
@ -966,9 +969,13 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) {
UV_RUNTIME_CHECK(uv_tcp_init, r);
uv_handle_set_data(&csock->uv_handle.handle, csock);
r = uv_timer_init(&worker->loop, &csock->timer);
r = uv_timer_init(&worker->loop, &csock->read_timer);
UV_RUNTIME_CHECK(uv_timer_init, r);
uv_handle_set_data((uv_handle_t *)&csock->timer, csock);
uv_handle_set_data((uv_handle_t *)&csock->read_timer, csock);
r = uv_timer_init(&worker->loop, &csock->write_timer);
UV_RUNTIME_CHECK(uv_timer_init, r);
uv_handle_set_data((uv_handle_t *)&csock->write_timer, csock);
r = uv_accept(&ssock->uv_handle.stream, &csock->uv_handle.stream);
if (r != 0) {
@ -1086,6 +1093,13 @@ isc__nm_tcpdns_send(isc_nmhandle_t *handle, isc_region_t *region,
uvreq->cb.send = cb;
uvreq->cbarg = cbarg;
if (sock->write_timeout == 0) {
sock->write_timeout =
(atomic_load(&sock->keepalive)
? atomic_load(&sock->mgr->keepalive)
: atomic_load(&sock->mgr->idle));
}
ievent = isc__nm_get_netievent_tcpdnssend(sock->mgr, sock, uvreq);
isc__nm_maybe_enqueue_ievent(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
@ -1103,6 +1117,11 @@ tcpdns_send_cb(uv_write_t *req, int status) {
sock = uvreq->sock;
if (--sock->writes == 0) {
int r = uv_timer_stop(&sock->write_timer);
UV_RUNTIME_CHECK(uv_timer_stop, r);
}
if (status < 0) {
isc__nm_incstats(sock, STATID_SENDFAIL);
isc__nm_failed_send_cb(sock, uvreq,
@ -1169,6 +1188,11 @@ isc__nm_async_tcpdnssend(isc__networker_t *worker, isc__netievent_t *ev0) {
goto fail;
}
r = uv_timer_start(&sock->write_timer, isc__nmsocket_writetimeout_cb,
sock->write_timeout, 0);
UV_RUNTIME_CHECK(uv_timer_start, r);
RUNTIME_CHECK(sock->writes++ >= 0);
r = uv_write(&uvreq->uv_req.write, &sock->uv_handle.stream, bufs, nbufs,
tcpdns_send_cb);
if (r < 0) {
@ -1238,7 +1262,7 @@ tcpdns_close_cb(uv_handle_t *handle) {
}
static void
timer_close_cb(uv_handle_t *timer) {
read_timer_close_cb(uv_handle_t *timer) {
isc_nmsocket_t *sock = uv_handle_get_data(timer);
uv_handle_set_data(timer, NULL);
@ -1253,6 +1277,17 @@ timer_close_cb(uv_handle_t *timer) {
}
}
static void
write_timer_close_cb(uv_handle_t *timer) {
isc_nmsocket_t *sock = uv_handle_get_data(timer);
uv_handle_set_data(timer, NULL);
REQUIRE(VALID_NMSOCK(sock));
uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock);
uv_close((uv_handle_t *)&sock->read_timer, read_timer_close_cb);
}
static void
stop_tcpdns_child(isc_nmsocket_t *sock) {
REQUIRE(sock->type == isc_nm_tcpdnssocket);
@ -1305,6 +1340,7 @@ stop_tcpdns_parent(isc_nmsocket_t *sock) {
static void
tcpdns_close_direct(isc_nmsocket_t *sock) {
int r;
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
REQUIRE(atomic_load(&sock->closing));
@ -1320,8 +1356,10 @@ tcpdns_close_direct(isc_nmsocket_t *sock) {
isc__nmsocket_timer_stop(sock);
isc__nm_stop_reading(sock);
uv_handle_set_data((uv_handle_t *)&sock->timer, sock);
uv_close((uv_handle_t *)&sock->timer, timer_close_cb);
r = uv_timer_stop(&sock->write_timer);
UV_RUNTIME_CHECK(uv_timer_stop, r);
uv_handle_set_data((uv_handle_t *)&sock->write_timer, sock);
uv_close((uv_handle_t *)&sock->write_timer, write_timer_close_cb);
}
void

View File

@ -38,13 +38,6 @@
#include "openssl_shim.h"
#include "uv-compat.h"
/*%<
*
* Maximum number of simultaneous handles in flight supported for a single
* connected TLSDNS socket. This value was chosen arbitrarily, and may be
* changed in the future.
*/
static atomic_uint_fast32_t last_tlsdnsquota_log = ATOMIC_VAR_INIT(0);
static void
@ -121,9 +114,13 @@ tlsdns_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
UV_RUNTIME_CHECK(uv_tcp_init, r);
uv_handle_set_data(&sock->uv_handle.handle, sock);
r = uv_timer_init(&worker->loop, &sock->timer);
r = uv_timer_init(&worker->loop, &sock->read_timer);
UV_RUNTIME_CHECK(uv_timer_init, r);
uv_handle_set_data((uv_handle_t *)&sock->timer, sock);
uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock);
r = uv_timer_init(&worker->loop, &sock->write_timer);
UV_RUNTIME_CHECK(uv_timer_init, r);
uv_handle_set_data((uv_handle_t *)&sock->write_timer, sock);
if (isc__nm_closing(sock)) {
result = ISC_R_SHUTTINGDOWN;
@ -161,7 +158,8 @@ tlsdns_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
}
isc__nm_incstats(sock, STATID_CONNECT);
uv_handle_set_data((uv_handle_t *)&sock->timer, &req->uv_req.connect);
uv_handle_set_data((uv_handle_t *)&sock->read_timer,
&req->uv_req.connect);
isc__nmsocket_timer_start(sock);
atomic_store(&sock->connected, true);
@ -569,9 +567,13 @@ isc__nm_async_tlsdnslisten(isc__networker_t *worker, isc__netievent_t *ev0) {
/* This keeps the socket alive after everything else is gone */
isc__nmsocket_attach(sock, &(isc_nmsocket_t *){ NULL });
r = uv_timer_init(&worker->loop, &sock->timer);
r = uv_timer_init(&worker->loop, &sock->read_timer);
UV_RUNTIME_CHECK(uv_timer_init, r);
uv_handle_set_data((uv_handle_t *)&sock->timer, sock);
uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock);
r = uv_timer_init(&worker->loop, &sock->write_timer);
UV_RUNTIME_CHECK(uv_timer_init, r);
uv_handle_set_data((uv_handle_t *)&sock->write_timer, sock);
LOCK(&sock->parent->lock);
@ -1107,7 +1109,8 @@ tls_cycle_input(isc_nmsocket_t *sock) {
sock->tls.pending_req = NULL;
isc__nmsocket_timer_stop(sock);
uv_handle_set_data((uv_handle_t *)&sock->timer, sock);
uv_handle_set_data((uv_handle_t *)&sock->read_timer,
sock);
INSIST(atomic_compare_exchange_strong(
&sock->connecting, &(bool){ true }, false));
@ -1163,6 +1166,11 @@ tls_write_cb(uv_write_t *req, int status) {
isc__nm_uvreq_t *uvreq = (isc__nm_uvreq_t *)req->data;
isc_nmsocket_t *sock = uvreq->sock;
if (--sock->writes == 0) {
int r = uv_timer_stop(&sock->write_timer);
UV_RUNTIME_CHECK(uv_timer_stop, r);
}
free_senddata(sock);
isc__nm_uvreq_put(&uvreq, sock);
@ -1236,6 +1244,12 @@ tls_cycle_output(isc_nmsocket_t *sock) {
break;
}
r = uv_timer_start(&sock->write_timer,
isc__nmsocket_writetimeout_cb,
sock->write_timeout, 0);
UV_RUNTIME_CHECK(uv_timer_start, r);
RUNTIME_CHECK(sock->writes++ >= 0);
r = uv_write(&req->uv_req.write, &sock->uv_handle.stream,
&req->uvbuf, 1, tls_write_cb);
if (r < 0) {
@ -1476,9 +1490,13 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) {
UV_RUNTIME_CHECK(uv_tcp_init, r);
uv_handle_set_data(&csock->uv_handle.handle, csock);
r = uv_timer_init(&worker->loop, &csock->timer);
r = uv_timer_init(&worker->loop, &csock->read_timer);
UV_RUNTIME_CHECK(uv_timer_init, r);
uv_handle_set_data((uv_handle_t *)&csock->timer, csock);
uv_handle_set_data((uv_handle_t *)&csock->read_timer, csock);
r = uv_timer_init(&worker->loop, &csock->write_timer);
UV_RUNTIME_CHECK(uv_timer_init, r);
uv_handle_set_data((uv_handle_t *)&csock->write_timer, csock);
r = uv_accept(&ssock->uv_handle.stream, &csock->uv_handle.stream);
if (r != 0) {
@ -1627,6 +1645,13 @@ isc__nm_tlsdns_send(isc_nmhandle_t *handle, isc_region_t *region,
uvreq->cb.send = cb;
uvreq->cbarg = cbarg;
if (sock->write_timeout == 0) {
sock->write_timeout =
(atomic_load(&sock->keepalive)
? atomic_load(&sock->mgr->keepalive)
: atomic_load(&sock->mgr->idle));
}
ievent = isc__nm_get_netievent_tlsdnssend(sock->mgr, sock, uvreq);
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
@ -1804,7 +1829,7 @@ tlsdns_close_cb(uv_handle_t *handle) {
}
static void
timer_close_cb(uv_handle_t *handle) {
read_timer_close_cb(uv_handle_t *handle) {
isc_nmsocket_t *sock = uv_handle_get_data(handle);
uv_handle_set_data(handle, NULL);
@ -1819,6 +1844,17 @@ timer_close_cb(uv_handle_t *handle) {
}
}
static void
write_timer_close_cb(uv_handle_t *timer) {
isc_nmsocket_t *sock = uv_handle_get_data(timer);
uv_handle_set_data(timer, NULL);
REQUIRE(VALID_NMSOCK(sock));
uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock);
uv_close((uv_handle_t *)&sock->read_timer, read_timer_close_cb);
}
static void
stop_tlsdns_child(isc_nmsocket_t *sock) {
REQUIRE(sock->type == isc_nm_tlsdnssocket);
@ -1872,6 +1908,8 @@ stop_tlsdns_parent(isc_nmsocket_t *sock) {
static void
tlsdns_close_direct(isc_nmsocket_t *sock) {
int r;
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
REQUIRE(atomic_load(&sock->closing));
@ -1889,8 +1927,10 @@ tlsdns_close_direct(isc_nmsocket_t *sock) {
isc__nmsocket_timer_stop(sock);
isc__nm_stop_reading(sock);
uv_handle_set_data((uv_handle_t *)&sock->timer, sock);
uv_close((uv_handle_t *)&sock->timer, timer_close_cb);
r = uv_timer_stop(&sock->write_timer);
UV_RUNTIME_CHECK(uv_timer_stop, r);
uv_handle_set_data((uv_handle_t *)&sock->write_timer, sock);
uv_close((uv_handle_t *)&sock->write_timer, write_timer_close_cb);
}
void

View File

@ -74,7 +74,10 @@ static void
udp_close_cb(uv_handle_t *handle);
static void
timer_close_cb(uv_handle_t *handle);
read_timer_close_cb(uv_handle_t *handle);
static void
write_timer_close_cb(uv_handle_t *handle);
static void
udp_close_direct(isc_nmsocket_t *sock);
@ -265,9 +268,13 @@ route_connect_direct(isc_nmsocket_t *sock) {
UV_RUNTIME_CHECK(uv_udp_init, r);
uv_handle_set_data(&sock->uv_handle.handle, sock);
r = uv_timer_init(&worker->loop, &sock->timer);
r = uv_timer_init(&worker->loop, &sock->read_timer);
UV_RUNTIME_CHECK(uv_timer_init, r);
uv_handle_set_data((uv_handle_t *)&sock->timer, sock);
uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock);
r = uv_timer_init(&worker->loop, &sock->write_timer);
UV_RUNTIME_CHECK(uv_timer_init, r);
uv_handle_set_data((uv_handle_t *)&sock->write_timer, sock);
if (isc__nm_closing(sock)) {
result = ISC_R_SHUTTINGDOWN;
@ -441,9 +448,13 @@ isc__nm_async_udplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
/* This keeps the socket alive after everything else is gone */
isc__nmsocket_attach(sock, &(isc_nmsocket_t *){ NULL });
r = uv_timer_init(&worker->loop, &sock->timer);
r = uv_timer_init(&worker->loop, &sock->read_timer);
UV_RUNTIME_CHECK(uv_timer_init, r);
uv_handle_set_data((uv_handle_t *)&sock->timer, sock);
uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock);
r = uv_timer_init(&worker->loop, &sock->write_timer);
UV_RUNTIME_CHECK(uv_timer_init, r);
uv_handle_set_data((uv_handle_t *)&sock->write_timer, sock);
LOCK(&sock->parent->lock);
@ -857,9 +868,13 @@ udp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
UV_RUNTIME_CHECK(uv_udp_init, r);
uv_handle_set_data(&sock->uv_handle.handle, sock);
r = uv_timer_init(&worker->loop, &sock->timer);
r = uv_timer_init(&worker->loop, &sock->read_timer);
UV_RUNTIME_CHECK(uv_timer_init, r);
uv_handle_set_data((uv_handle_t *)&sock->timer, sock);
uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock);
r = uv_timer_init(&worker->loop, &sock->write_timer);
UV_RUNTIME_CHECK(uv_timer_init, r);
uv_handle_set_data((uv_handle_t *)&sock->write_timer, sock);
if (isc__nm_closing(sock)) {
result = ISC_R_SHUTTINGDOWN;
@ -1210,7 +1225,7 @@ udp_close_cb(uv_handle_t *handle) {
}
static void
timer_close_cb(uv_handle_t *handle) {
read_timer_close_cb(uv_handle_t *handle) {
isc_nmsocket_t *sock = uv_handle_get_data(handle);
uv_handle_set_data(handle, NULL);
@ -1221,6 +1236,17 @@ timer_close_cb(uv_handle_t *handle) {
}
}
static void
write_timer_close_cb(uv_handle_t *timer) {
isc_nmsocket_t *sock = uv_handle_get_data(timer);
uv_handle_set_data(timer, NULL);
REQUIRE(VALID_NMSOCK(sock));
uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock);
uv_close((uv_handle_t *)&sock->read_timer, read_timer_close_cb);
}
static void
stop_udp_child(isc_nmsocket_t *sock) {
REQUIRE(sock->type == isc_nm_udpsocket);
@ -1273,10 +1299,14 @@ stop_udp_parent(isc_nmsocket_t *sock) {
static void
udp_close_direct(isc_nmsocket_t *sock) {
int r;
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
uv_close((uv_handle_t *)&sock->timer, timer_close_cb);
r = uv_timer_stop(&sock->write_timer);
UV_RUNTIME_CHECK(uv_timer_stop, r);
uv_handle_set_data((uv_handle_t *)&sock->write_timer, sock);
uv_close((uv_handle_t *)&sock->write_timer, write_timer_close_cb);
}
void

View File

@ -42,6 +42,24 @@ isc_uv_udp_connect(uv_udp_t *handle, const struct sockaddr *addr) {
}
#endif /* UV_VERSION_HEX < UV_VERSION(1, 27, 0) */
#if UV_VERSION_HEX < UV_VERSION(1, 32, 0)
int
uv_tcp_close_reset(uv_tcp_t *handle, uv_close_cb close_cb) {
if (setsockopt(handle->io_watcher.fd, SOL_SOCKET, SO_LINGER,
&(struct linger){ 1, 0 }, sizeof(struct linger)) == -1)
{
#if UV_VERSION_HEX >= UV_VERSION(1, 10, 0)
return (uv_translate_sys_error(errno));
#else
return (-errno);
#endif /* UV_VERSION_HEX >= UV_VERSION(1, 10, 0) */
}
uv_close((uv_handle_t *)handle, close_cb);
return (0);
}
#endif /* UV_VERSION_HEX < UV_VERSION(1, 32, 0) */
int
isc_uv_udp_freebind(uv_udp_t *handle, const struct sockaddr *addr,
unsigned int flags) {

View File

@ -23,6 +23,10 @@
#define UV_VERSION(major, minor, patch) ((major << 16) | (minor << 8) | (patch))
#if !defined(UV__ERR)
#define UV__ERR(x) (-(x))
#endif
#if UV_VERSION_HEX < UV_VERSION(1, 19, 0)
static inline void *
uv_handle_get_data(const uv_handle_t *handle) {
@ -45,6 +49,11 @@ uv_req_set_data(uv_req_t *req, void *data) {
}
#endif /* UV_VERSION_HEX < UV_VERSION(1, 19, 0) */
#if UV_VERSION_HEX < UV_VERSION(1, 32, 0)
int
uv_tcp_close_reset(uv_tcp_t *handle, uv_close_cb close_cb);
#endif
#if UV_VERSION_HEX < UV_VERSION(1, 34, 0)
#define uv_sleep(msec) usleep(msec * 1000)
#endif /* UV_VERSION_HEX < UV_VERSION(1, 34, 0) */

View File

@ -437,6 +437,7 @@ connect_send(isc_nmhandle_t *handle) {
isc_nmhandle_t *sendhandle = NULL;
isc_refcount_increment0(&active_csends);
isc_nmhandle_attach(handle, &sendhandle);
isc_nmhandle_setwritetimeout(handle, T_IDLE);
if (atomic_fetch_sub(&nsends, 1) > 1) {
isc_nm_send(sendhandle, (isc_region_t *)&send_msg,
connect_send_cb, NULL);
@ -548,6 +549,7 @@ listen_read_cb(isc_nmhandle_t *handle, isc_result_t eresult,
isc_nmhandle_t *sendhandle = NULL;
isc_nmhandle_attach(handle, &sendhandle);
isc_refcount_increment0(&active_ssends);
isc_nmhandle_setwritetimeout(sendhandle, T_IDLE);
isc_nm_send(sendhandle, (isc_region_t *)&send_msg,
listen_send_cb, cbarg);
}