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.
This commit is contained in:
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user