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

Fix the streaming read callback shutdown logic

When shutting down TCP sockets, the read callback calling logic was
flawed, it would call either one less callback or one extra.  Fix the
logic in the way:

1. When isc_nm_read() has been called but isc_nm_read_stop() hasn't on
   the handle, the read callback will be called with ISC_R_CANCELED to
   cancel active reading from the socket/handle.

2. When isc_nm_read() has been called and isc_nm_read_stop() has been
   called on the on the handle, the read callback will be called with
   ISC_R_SHUTTINGDOWN to signal that the dormant (not-reading) socket
   is being shut down.

3. The .reading and .recv_read flags are little bit tricky.  The
   .reading flag indicates if the outer layer is reading the data (that
   would be uv_tcp_t for TCP and isc_nmsocket_t (TCP) for TLSStream),
   the .recv_read flag indicates whether somebody is interested in the
   data read from the socket.

   Usually, you would expect that the .reading should be false when
   .recv_read is false, but it gets even more tricky with TLSStream as
   the TLS protocol might need to read from the socket even when sending
   data.

   Fix the usage of the .recv_read and .reading flags in the TLSStream
   to their true meaning - which mostly consist of using .recv_read
   everywhere and then wrapping isc_nm_read() and isc_nm_read_stop()
   with the .reading flag.

4. The TLS failed read helper has been modified to resemble the TCP code
   as much as possible, clearing and re-setting the .recv_read flag in
   the TCP timeout code has been fixed and .recv_read is now cleared
   when isc_nm_read_stop() has been called on the streaming socket.

5. The use of Network Manager in the named_controlconf, isccc_ccmsg, and
   isc_httpd units have been greatly simplified due to the improved design.

6. More unit tests for TCP and TLS testing the shutdown conditions have
   been added.

Co-authored-by: Ondřej Surý <ondrej@isc.org>
Co-authored-by: Artem Boldariev <artem@isc.org>
This commit is contained in:
Ondřej Surý
2023-04-13 17:27:50 +02:00
parent 4fcbb078c1
commit 3b10814569
26 changed files with 977 additions and 806 deletions

View File

@@ -580,15 +580,6 @@ nmsocket_maybe_destroy(isc_nmsocket_t *sock FLARG) {
}
}
void
isc_nmhandle_close(isc_nmhandle_t *handle) {
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
isc__nmsocket_clearcb(handle->sock);
isc__nm_failed_read_cb(handle->sock, ISC_R_EOF, false);
}
void
isc___nmsocket_prep_destroy(isc_nmsocket_t *sock FLARG) {
REQUIRE(sock->parent == NULL);
@@ -904,19 +895,6 @@ isc___nmhandle_get(isc_nmsocket_t *sock, isc_sockaddr_t const *peer,
return (handle);
}
void
isc__nmhandle_attach(isc_nmhandle_t *handle, isc_nmhandle_t **handlep FLARG) {
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(handlep != NULL && *handlep == NULL);
NETMGR_TRACE_LOG("isc__nmhandle_attach():handle %p->references = "
"%" PRIuFAST32 "\n",
handle, isc_refcount_current(&handle->references) + 1);
isc_refcount_increment(&handle->references);
*handlep = handle;
}
bool
isc_nmhandle_is_stream(isc_nmhandle_t *handle) {
REQUIRE(VALID_NMHANDLE(handle));
@@ -1003,26 +981,11 @@ nmhandle_destroy(isc_nmhandle_t *handle) {
handle);
}
void
isc__nmhandle_detach(isc_nmhandle_t **handlep FLARG) {
isc_nmhandle_t *handle = NULL;
REQUIRE(handlep != NULL);
REQUIRE(VALID_NMHANDLE(*handlep));
handle = *handlep;
*handlep = NULL;
REQUIRE(handle->sock->tid == isc_tid());
NETMGR_TRACE_LOG("isc__nmhandle_detach():%p->references = %" PRIuFAST32
"\n",
handle, isc_refcount_current(&handle->references) - 1);
if (isc_refcount_decrement(&handle->references) == 1) {
nmhandle_destroy(handle);
}
}
#if ISC_NETMGR_TRACE
ISC_REFCOUNT_TRACE_IMPL(isc_nmhandle, nmhandle_destroy)
#else
ISC_REFCOUNT_IMPL(isc_nmhandle, nmhandle_destroy);
#endif
void *
isc_nmhandle_getdata(isc_nmhandle_t *handle) {
@@ -1117,7 +1080,6 @@ isc__nmsocket_connecttimeout_cb(uv_timer_t *timer) {
*/
REQUIRE(!sock->timedout);
sock->timedout = true;
isc__nmsocket_clearcb(sock);
isc__nmsocket_shutdown(sock);
}
@@ -1168,13 +1130,10 @@ isc__nmsocket_readtimeout_cb(uv_timer_t *timer) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_tid());
REQUIRE(sock->reading);
if (sock->client) {
uv_timer_stop(timer);
sock->recv_read = false;
if (sock->recv_cb != NULL) {
isc__nm_uvreq_t *req = isc__nm_get_read_req(sock, NULL);
isc__nm_readcb(sock, req, ISC_R_TIMEDOUT, false);
@@ -1182,7 +1141,7 @@ isc__nmsocket_readtimeout_cb(uv_timer_t *timer) {
if (!isc__nmsocket_timer_running(sock)) {
isc__nmsocket_clearcb(sock);
isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false);
isc__nm_failed_read_cb(sock, ISC_R_TIMEDOUT, false);
}
} else {
isc__nm_failed_read_cb(sock, ISC_R_TIMEDOUT, false);
@@ -1285,7 +1244,7 @@ isc__nmsocket_timer_stop(isc_nmsocket_t *sock) {
}
isc__nm_uvreq_t *
isc__nm_get_read_req(isc_nmsocket_t *sock, isc_sockaddr_t *sockaddr) {
isc___nm_get_read_req(isc_nmsocket_t *sock, isc_sockaddr_t *sockaddr FLARG) {
isc__nm_uvreq_t *req = NULL;
req = isc__nm_uvreq_get(sock);
@@ -1295,16 +1254,32 @@ isc__nm_get_read_req(isc_nmsocket_t *sock, isc_sockaddr_t *sockaddr) {
switch (sock->type) {
case isc_nm_tcpsocket:
case isc_nm_tlssocket:
#if ISC_NETMGR_TRACE
isc_nmhandle__attach(sock->statichandle,
&req->handle FLARG_PASS);
#else
isc_nmhandle_attach(sock->statichandle, &req->handle);
#endif
break;
case isc_nm_streamdnssocket:
#if ISC_NETMGR_TRACE
isc_nmhandle__attach(sock->recv_handle,
&req->handle FLARG_PASS);
#else
isc_nmhandle_attach(sock->recv_handle, &req->handle);
#endif
break;
default:
if (sock->client && sock->statichandle != NULL) {
#if ISC_NETMGR_TRACE
isc_nmhandle__attach(sock->statichandle,
&req->handle FLARG_PASS);
#else
isc_nmhandle_attach(sock->statichandle, &req->handle);
#endif
} else {
req->handle = isc__nmhandle_get(sock, sockaddr, NULL);
req->handle = isc___nmhandle_get(sock, sockaddr,
NULL FLARG_PASS);
}
break;
}
@@ -1357,7 +1332,7 @@ isc__nm_start_reading(isc_nmsocket_t *sock) {
isc_result_t result = ISC_R_SUCCESS;
int r;
if (sock->reading) {
if (uv_is_active(&sock->uv_handle.handle)) {
return (ISC_R_SUCCESS);
}
@@ -1375,8 +1350,6 @@ isc__nm_start_reading(isc_nmsocket_t *sock) {
}
if (r != 0) {
result = isc_uverr2result(r);
} else {
sock->reading = true;
}
return (result);
@@ -1386,7 +1359,7 @@ void
isc__nm_stop_reading(isc_nmsocket_t *sock) {
int r;
if (!sock->reading) {
if (!uv_is_active(&sock->uv_handle.handle)) {
return;
}
@@ -1402,7 +1375,6 @@ isc__nm_stop_reading(isc_nmsocket_t *sock) {
default:
UNREACHABLE();
}
sock->reading = false;
}
bool
@@ -1578,7 +1550,11 @@ isc___nm_uvreq_put(isc__nm_uvreq_t **reqp FLARG) {
ISC_LIST_UNLINK(sock->active_uvreqs, req, active_link);
if (handle != NULL) {
isc__nmhandle_detach(&handle FLARG_PASS);
#if ISC_NETMGR_TRACE
isc_nmhandle__detach(&handle, func, file, line);
#else
isc_nmhandle_detach(&handle);
#endif
}
isc_mempool_put(sock->worker->uvreq_pool, req);
@@ -1659,20 +1635,37 @@ isc_nm_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
}
}
void
isc_nm_cancelread(isc_nmhandle_t *handle) {
static void
cancelread_cb(void *arg) {
isc_nmhandle_t *handle = arg;
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
REQUIRE(handle->sock->tid == isc_tid());
REQUIRE(handle->sock->tid == isc_tid());
switch (handle->sock->type) {
case isc_nm_udpsocket:
isc__nm_udp_cancelread(handle);
break;
case isc_nm_streamdnssocket:
isc__nm_streamdns_cancelread(handle);
case isc_nm_httpsocket:
isc__nm_failed_read_cb(handle->sock, ISC_R_CANCELED, false);
break;
default:
UNREACHABLE();
}
isc_nmhandle_detach(&handle);
}
void
isc_nm_cancelread(isc_nmhandle_t *handle) {
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
/* Running this directly could cause a dead-lock */
isc_nmhandle_ref(handle);
isc_async_run(handle->sock->worker->loop, cancelread_cb, handle);
}
void
@@ -1693,6 +1686,15 @@ isc_nm_read_stop(isc_nmhandle_t *handle) {
}
}
void
isc_nmhandle_close(isc_nmhandle_t *handle) {
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
isc__nmsocket_clearcb(handle->sock);
isc__nmsocket_prep_destroy(handle->sock);
}
void
isc_nm_stoplistening(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
@@ -2505,8 +2507,7 @@ nmsocket_dump(isc_nmsocket_t *sock) {
"Parent %p, listener %p, server %p, statichandle = "
"%p\n",
sock->parent, sock->listener, sock->server, sock->statichandle);
fprintf(stderr, "Flags:%s%s%s%s%s\n",
atomic_load_acquire(&sock->active) ? " active" : "",
fprintf(stderr, "Flags:%s%s%s%s%s\n", sock->active ? " active" : "",
sock->closing ? " closing" : "",
sock->destroying ? " destroying" : "",
sock->connecting ? " connecting" : "",