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

Gracefully handle uv_read_start() failures

Under specific rare timing circumstances the uv_read_start() could
fail with UV_EINVAL when the connection is reset between the connect (or
accept) and the uv_read_start() call on the nmworker loop.  Handle such
situation gracefully by propagating the errors from uv_read_start() into
upper layers, so the socket can be internally closed().
This commit is contained in:
Ondřej Surý
2022-06-14 09:17:08 +02:00
parent 520cf01d56
commit b432d5d3bc
6 changed files with 73 additions and 30 deletions

View File

@@ -2161,39 +2161,42 @@ isc__nm_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) {
worker->recvbuf_inuse = true;
}
void
isc_result_t
isc__nm_start_reading(isc_nmsocket_t *sock) {
isc_result_t result = ISC_R_SUCCESS;
int r;
if (atomic_load(&sock->reading)) {
return;
return (ISC_R_SUCCESS);
}
switch (sock->type) {
case isc_nm_udpsocket:
r = uv_udp_recv_start(&sock->uv_handle.udp, isc__nm_alloc_cb,
isc__nm_udp_read_cb);
UV_RUNTIME_CHECK(uv_udp_recv_start, r);
break;
case isc_nm_tcpsocket:
r = uv_read_start(&sock->uv_handle.stream, isc__nm_alloc_cb,
isc__nm_tcp_read_cb);
UV_RUNTIME_CHECK(uv_read_start, r);
break;
case isc_nm_tcpdnssocket:
r = uv_read_start(&sock->uv_handle.stream, isc__nm_alloc_cb,
isc__nm_tcpdns_read_cb);
UV_RUNTIME_CHECK(uv_read_start, r);
break;
case isc_nm_tlsdnssocket:
r = uv_read_start(&sock->uv_handle.stream, isc__nm_alloc_cb,
isc__nm_tlsdns_read_cb);
UV_RUNTIME_CHECK(uv_read_start, r);
break;
default:
UNREACHABLE();
}
atomic_store(&sock->reading, true);
if (r != 0) {
result = isc_uverr2result(r);
} else {
atomic_store(&sock->reading, true);
}
return (result);
}
void
@@ -2254,7 +2257,7 @@ processbuffer(isc_nmsocket_t *sock) {
* Stop reading if this is a client socket. In this case we'll be
* called again later by isc__nm_resume_processing().
*/
void
isc_result_t
isc__nm_process_sock_buffer(isc_nmsocket_t *sock) {
for (;;) {
int_fast32_t ah = atomic_load(&sock->ah);
@@ -2265,7 +2268,10 @@ isc__nm_process_sock_buffer(isc_nmsocket_t *sock) {
* Don't reset the timer until we have a
* full DNS message.
*/
isc__nm_start_reading(sock);
result = isc__nm_start_reading(sock);
if (result != ISC_R_SUCCESS) {
return (result);
}
/*
* Start the timer only if there are no externally used
* active handles, there's always one active handle
@@ -2275,11 +2281,11 @@ isc__nm_process_sock_buffer(isc_nmsocket_t *sock) {
if (ah == 1) {
isc__nmsocket_timer_start(sock);
}
return;
goto done;
case ISC_R_CANCELED:
isc__nmsocket_timer_stop(sock);
isc__nm_stop_reading(sock);
return;
goto done;
case ISC_R_SUCCESS:
/*
* Stop the timer on the successful message read, this
@@ -2290,13 +2296,15 @@ isc__nm_process_sock_buffer(isc_nmsocket_t *sock) {
if (atomic_load(&sock->client)) {
isc__nm_stop_reading(sock);
return;
goto done;
}
break;
default:
UNREACHABLE();
}
}
done:
return (ISC_R_SUCCESS);
}
void