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:
@@ -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
|
||||
|
Reference in New Issue
Block a user