mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-31 22:45:39 +00:00
netmgr: don't send to an inactive (closing) udp socket
We had a race in which n UDP socket could have been already closing by libuv but we still sent data to it. Mark socket as not-active when stopping listening and verify that socket is not active when trying to send data to it.
This commit is contained in:
@@ -603,6 +603,13 @@ isc__nmsocket_prep_destroy(isc_nmsocket_t *sock);
|
|||||||
* if there are no remaining references or active handles.
|
* if there are no remaining references or active handles.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
bool
|
||||||
|
isc__nmsocket_active(isc_nmsocket_t *sock);
|
||||||
|
/*%<
|
||||||
|
* Check is socket 'sock' is active - by checking either sock->active or
|
||||||
|
* sock->parent->active;
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
isc__nm_async_closecb(isc__networker_t *worker, isc__netievent_t *ev0);
|
isc__nm_async_closecb(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||||
/*%<
|
/*%<
|
||||||
|
@@ -681,7 +681,7 @@ isc__nm_enqueue_ievent(isc__networker_t *worker, isc__netievent_t *event) {
|
|||||||
uv_async_send(&worker->async);
|
uv_async_send(&worker->async);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
bool
|
||||||
isc__nmsocket_active(isc_nmsocket_t *sock) {
|
isc__nmsocket_active(isc_nmsocket_t *sock) {
|
||||||
REQUIRE(VALID_NMSOCK(sock));
|
REQUIRE(VALID_NMSOCK(sock));
|
||||||
if (sock->parent != NULL) {
|
if (sock->parent != NULL) {
|
||||||
|
@@ -179,14 +179,18 @@ stop_udp_child(isc_nmsocket_t *sock) {
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
stoplistening(isc_nmsocket_t *sock) {
|
stoplistening(isc_nmsocket_t *sock) {
|
||||||
|
INSIST(sock->type == isc_nm_udplistener);
|
||||||
/*
|
/*
|
||||||
* Socket is already closing; there's nothing to do.
|
* Socket is already closing; there's nothing to do.
|
||||||
*/
|
*/
|
||||||
if (uv_is_closing((uv_handle_t *) &sock->uv_handle.udp)) {
|
if (!isc__nmsocket_active(sock)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
INSIST(sock->type == isc_nm_udplistener);
|
* Mark it inactive now so that all sends will be ignored
|
||||||
|
* and we won't try to stop listening again.
|
||||||
|
*/
|
||||||
|
atomic_store(&sock->active, false);
|
||||||
|
|
||||||
for (int i = 0; i < sock->nchildren; i++) {
|
for (int i = 0; i < sock->nchildren; i++) {
|
||||||
isc__netievent_udpstop_t *event = NULL;
|
isc__netievent_udpstop_t *event = NULL;
|
||||||
@@ -375,6 +379,11 @@ isc__nm_udp_send(isc_nmhandle_t *handle, isc_region_t *region,
|
|||||||
return (ISC_R_UNEXPECTED);
|
return (ISC_R_UNEXPECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isc__nmsocket_active(sock)) {
|
||||||
|
isc_nmhandle_unref(handle);
|
||||||
|
return (ISC_R_CANCELED);
|
||||||
|
}
|
||||||
|
|
||||||
if (isc__nm_in_netthread()) {
|
if (isc__nm_in_netthread()) {
|
||||||
ntid = isc_nm_tid();
|
ntid = isc_nm_tid();
|
||||||
} else {
|
} else {
|
||||||
@@ -425,7 +434,7 @@ isc__nm_async_udpsend(isc__networker_t *worker, isc__netievent_t *ev0) {
|
|||||||
|
|
||||||
REQUIRE(worker->id == ievent->sock->tid);
|
REQUIRE(worker->id == ievent->sock->tid);
|
||||||
|
|
||||||
if (atomic_load(&ievent->sock->active)) {
|
if (isc__nmsocket_active(ievent->sock)) {
|
||||||
udp_send_direct(ievent->sock, ievent->req, &ievent->peer);
|
udp_send_direct(ievent->sock, ievent->req, &ievent->peer);
|
||||||
} else {
|
} else {
|
||||||
ievent->req->cb.send(ievent->req->handle,
|
ievent->req->cb.send(ievent->req->handle,
|
||||||
|
Reference in New Issue
Block a user