From 72724b258c1c86c638630559d7142723d595d69d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= <ondrej@isc.org>
Date: Thu, 3 Nov 2022 17:42:12 +0100
Subject: [PATCH] Propagate the shutdown event to the recursing ns_client(s)

Send the ns_query_cancel() on the recursing clients when we initiate the
named shutdown for faster shutdown.

When we are shutting down the resolver, we cancel all the outstanding
fetches, and the ISC_R_CANCEL events doesn't propagate to the ns_client
callback.

In the future, the better solution how to fix this would be to look at
the shutdown paths and let them all propagate from bottom (loopmgr) to
top (f.e. ns_client).

(cherry picked from commit d861d403bb9a7912e29a06aba6caf6d502839f1b)
---
 lib/ns/client.c            | 13 +++++++++++++
 lib/ns/include/ns/client.h | 10 ++++++++--
 lib/ns/interfacemgr.c      |  1 +
 lib/ns/win32/libns.def     |  1 +
 4 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/lib/ns/client.c b/lib/ns/client.c
index 6bd5ddfdefb..d4ce000be87 100644
--- a/lib/ns/client.c
+++ b/lib/ns/client.c
@@ -2518,6 +2518,19 @@ cleanup_reclock:
 	return (result);
 }
 
+void
+ns_clientmgr_shutdown(ns_clientmgr_t *manager) {
+	REQUIRE(VALID_MANAGER(manager));
+
+	LOCK(&manager->reclock);
+	for (ns_client_t *client = ISC_LIST_HEAD(manager->recursing);
+	     client != NULL; client = ISC_LIST_NEXT(client, rlink))
+	{
+		ns_query_cancel(client);
+	}
+	UNLOCK(&manager->reclock);
+}
+
 void
 ns_clientmgr_destroy(ns_clientmgr_t **managerp) {
 	isc_result_t result;
diff --git a/lib/ns/include/ns/client.h b/lib/ns/include/ns/client.h
index 9d152c6bbe8..d1e2fde4073 100644
--- a/lib/ns/include/ns/client.h
+++ b/lib/ns/include/ns/client.h
@@ -354,12 +354,18 @@ ns_clientmgr_create(isc_mem_t *mctx, ns_server_t *sctx, isc_taskmgr_t *taskmgr,
  */
 
 void
-ns_clientmgr_destroy(ns_clientmgr_t **managerp);
+ns_clientmgr_shutdown(ns_clientmgr_t *manager);
 /*%<
- * Destroy a client manager and all ns_client_t objects
+ * Shutdown a client manager and all ns_client_t objects
  * managed by it.
  */
 
+void
+ns_clientmgr_destroy(ns_clientmgr_t **managerp);
+/*%<
+ * Destroy a client manager.
+ */
+
 isc_sockaddr_t *
 ns_client_getsockaddr(ns_client_t *client);
 /*%<
diff --git a/lib/ns/interfacemgr.c b/lib/ns/interfacemgr.c
index 687359058b0..216e274a54e 100644
--- a/lib/ns/interfacemgr.c
+++ b/lib/ns/interfacemgr.c
@@ -574,6 +574,7 @@ ns_interface_shutdown(ns_interface_t *ifp) {
 		isc_nmsocket_close(&ifp->tcplistensocket);
 	}
 	if (ifp->clientmgr != NULL) {
+		ns_clientmgr_shutdown(ifp->clientmgr);
 		ns_clientmgr_destroy(&ifp->clientmgr);
 	}
 }
diff --git a/lib/ns/win32/libns.def b/lib/ns/win32/libns.def
index eadd940a9ce..50edf86730b 100644
--- a/lib/ns/win32/libns.def
+++ b/lib/ns/win32/libns.def
@@ -42,6 +42,7 @@ ns_client_shuttingdown
 ns_client_sourceip
 ns_clientmgr_create
 ns_clientmgr_destroy
+ns_clientmgr_shutdown
 ns_hook_add
 ns_hooktable_create
 ns_hooktable_free
-- 
2.23.0