2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-31 14:35:26 +00:00

Add TCP, TCPDNS and TLSDNS write timer

When the outgoing TCP write buffers are full because the other party is
not reading the data, the uv_write() could wait indefinitely on the
uv_loop and never calling the callback.  Add a new write timer that uses
the `tcp-idle-timeout` value to interrupt the TCP connection when we are
not able to send data for defined period of time.
This commit is contained in:
Ondřej Surý
2022-02-09 11:21:04 +01:00
parent cd3b58622c
commit 408b362169
6 changed files with 215 additions and 30 deletions

View File

@@ -144,6 +144,10 @@ tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
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) {
isc__nm_closesocket(sock->fd);
@@ -533,6 +537,10 @@ isc__nm_async_tcplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
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);
LOCK(&sock->parent->lock);
r = uv_tcp_open(&sock->uv_handle.tcp, sock->fd);
@@ -979,6 +987,10 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) {
UV_RUNTIME_CHECK(uv_timer_init, r);
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) {
result = isc__nm_uverr2result(r);
@@ -1072,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);
@@ -1082,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));
@@ -1130,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) {
@@ -1193,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);
@@ -1206,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);
@@ -1258,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));
@@ -1279,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->read_timer, sock);
uv_close((uv_handle_t *)&sock->read_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