From: Evan Hunt Date: Thu, 2 Dec 2021 20:04:42 +0000 (-0800) Subject: prevent a shutdown hang on non-matching TCP responses X-Git-Tag: v9.17.22~48^2~3 X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=5f82fc11a9cf2f847540df256584933f6402bfa2;p=thirdparty%2Fbind9.git prevent a shutdown hang on non-matching TCP responses When a non-matching DNS response is received by the resolver, it calls dns_dispatch_getnext() to resume reading. This is necessary for UDP but not for TCP, because TCP connections automatically resume reading after any valid DNS response. This commit adds a 'tcpreading' flag to TCP dispatches, so that `dispatch_getnext()` can be called multiple times without subsequent calls having any effect. --- diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index d5cbd07dcfd..ac0afb51dde 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -125,6 +125,7 @@ struct dns_dispatch { isc_mutex_t lock; /*%< locks all below */ isc_socktype_t socktype; atomic_uint_fast32_t state; + atomic_bool tcpreading; isc_refcount_t references; unsigned int shutdown_out : 1; @@ -752,6 +753,8 @@ tcp_recv(isc_nmhandle_t *handle, isc_result_t result, isc_region_t *region, REQUIRE(VALID_DISPATCH(disp)); + atomic_store(&disp->tcpreading, false); + qid = disp->mgr->qid; ISC_LIST_INIT(resps); @@ -1531,11 +1534,14 @@ dispatch_getnext(dns_dispatch_t *disp, dns_dispentry_t *resp, int32_t timeout) { break; case isc_socktype_tcp: - dns_dispatch_attach(disp, &(dns_dispatch_t *){ NULL }); - if (timeout > 0) { - isc_nmhandle_settimeout(disp->handle, timeout); + if (atomic_compare_exchange_strong(&disp->tcpreading, + &(bool){ false }, true)) { + dns_dispatch_attach(disp, &(dns_dispatch_t *){ NULL }); + if (timeout > 0) { + isc_nmhandle_settimeout(disp->handle, timeout); + } + isc_nm_read(disp->handle, tcp_recv, disp); } - isc_nm_read(disp->handle, tcp_recv, disp); break; default: