]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Update the set of HTTP endpoints on reconfiguration
authorArtem Boldariev <artem@boldariev.com>
Wed, 22 Jun 2022 16:31:18 +0000 (19:31 +0300)
committerArtem Boldariev <artem@boldariev.com>
Tue, 28 Jun 2022 12:42:38 +0000 (15:42 +0300)
This commit ensures that on reconfiguration the set of HTTP
endpoints (=paths) is being updated within HTTP listeners.

lib/isc/include/isc/netmgr.h
lib/isc/netmgr/http.c
lib/isc/netmgr/netmgr-int.h
lib/isc/netmgr/netmgr.c
lib/ns/interfacemgr.c

index 6333bfc5698229320d6d0633da2fcb952134a9b8..75e66f6713cbdc7b0b322b63d774ba959d6e7a7f 100644 (file)
@@ -638,8 +638,7 @@ isc_nm_http_set_endpoints(isc_nmsocket_t      *listener,
  * during reconfiguration.
  *
  * Requires:
- * \li 'listener' is a pointer to a valid network manager listener socket
- object with TLS support;
+ * \li 'listener' is a pointer to a valid network manager HTTP listener socket;
  * \li 'eps' is a valid pointer to an HTTP endpoints set.
  */
 
index 8acc4baa99bc4fcff6aa059c4a8d649297a171b7..6d58906b892cccdfb668db9c93b89df6c044e613 100644 (file)
@@ -179,6 +179,9 @@ typedef struct isc_http_send_req {
        isc__nm_http_pending_callbacks_t pending_write_callbacks;
 } isc_http_send_req_t;
 
+#define HTTP_ENDPOINTS_MAGIC   ISC_MAGIC('H', 'T', 'E', 'P')
+#define VALID_HTTP_ENDPOINTS(t) ISC_MAGIC_VALID(t, HTTP_ENDPOINTS_MAGIC)
+
 static bool
 http_send_outgoing(isc_nm_http_session_t *session, isc_nmhandle_t *httphandle,
                   isc_nm_cb_t cb, void *cbarg);
@@ -225,6 +228,16 @@ static isc_nm_httphandler_t *
 http_endpoints_find(const char *request_path,
                    const isc_nm_http_endpoints_t *restrict eps);
 
+static void
+http_init_listener_endpoints(isc_nmsocket_t *listener,
+                            isc_nm_http_endpoints_t *epset);
+
+static void
+http_cleanup_listener_endpoints(isc_nmsocket_t *listener);
+
+static isc_nm_http_endpoints_t *
+http_get_listener_endpoints(isc_nmsocket_t *listener, const int tid);
+
 static bool
 http_session_active(isc_nm_http_session_t *session) {
        REQUIRE(VALID_HTTP2_SESSION(session));
@@ -1655,14 +1668,15 @@ server_on_begin_headers_callback(nghttp2_session *ngsession,
 
 static isc_nm_httphandler_t *
 find_server_request_handler(const char *request_path,
-                           const isc_nmsocket_t *serversocket) {
+                           isc_nmsocket_t *serversocket, const int tid) {
        isc_nm_httphandler_t *handler = NULL;
 
        REQUIRE(VALID_NMSOCK(serversocket));
 
        if (atomic_load(&serversocket->listening)) {
                handler = http_endpoints_find(
-                       request_path, serversocket->h2.listener_endpoints);
+                       request_path,
+                       http_get_listener_endpoints(serversocket, tid));
        }
        return (handler);
 }
@@ -1692,7 +1706,8 @@ server_handle_path_header(isc_nmsocket_t *socket, const uint8_t *value,
        }
 
        handler = find_server_request_handler(socket->h2.request_path,
-                                             socket->h2.session->serversocket);
+                                             socket->h2.session->serversocket,
+                                             socket->tid);
        if (handler != NULL) {
                socket->h2.cb = handler->cb;
                socket->h2.cbarg = handler->cbarg;
@@ -2487,7 +2502,7 @@ isc_nm_listenhttp(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface,
        isc_nmsocket_set_max_streams(sock, max_concurrent_streams);
 
        atomic_store(&eps->in_use, true);
-       isc_nm_http_endpoints_attach(eps, &sock->h2.listener_endpoints);
+       http_init_listener_endpoints(sock, eps);
 
        if (ctx != NULL) {
                result = isc_nm_listentls(mgr, workers, iface,
@@ -2530,6 +2545,7 @@ isc_nm_http_endpoints_new(isc_mem_t *mctx) {
        ISC_LIST_INIT(eps->handlers);
        isc_refcount_init(&eps->references, 1);
        atomic_init(&eps->in_use, false);
+       eps->magic = HTTP_ENDPOINTS_MAGIC;
 
        return eps;
 }
@@ -2543,9 +2559,10 @@ isc_nm_http_endpoints_detach(isc_nm_http_endpoints_t **restrict epsp) {
 
        REQUIRE(epsp != NULL);
        eps = *epsp;
-       REQUIRE(eps != NULL);
+       REQUIRE(VALID_HTTP_ENDPOINTS(eps));
 
        if (isc_refcount_decrement(&eps->references) > 1) {
+               *epsp = NULL;
                return;
        }
 
@@ -2573,6 +2590,8 @@ isc_nm_http_endpoints_detach(isc_nm_http_endpoints_t **restrict epsp) {
                httpcbarg = next;
        }
 
+       eps->magic = 0;
+
        isc_mem_putanddetach(&mctx, eps, sizeof(*eps));
        *epsp = NULL;
 }
@@ -2580,6 +2599,7 @@ isc_nm_http_endpoints_detach(isc_nm_http_endpoints_t **restrict epsp) {
 void
 isc_nm_http_endpoints_attach(isc_nm_http_endpoints_t *source,
                             isc_nm_http_endpoints_t **targetp) {
+       REQUIRE(VALID_HTTP_ENDPOINTS(source));
        REQUIRE(targetp != NULL && *targetp == NULL);
 
        isc_refcount_increment(&source->references);
@@ -2592,6 +2612,8 @@ http_endpoints_find(const char *request_path,
                    const isc_nm_http_endpoints_t *restrict eps) {
        isc_nm_httphandler_t *handler = NULL;
 
+       REQUIRE(VALID_HTTP_ENDPOINTS(eps));
+
        if (request_path == NULL || *request_path == '\0') {
                return (NULL);
        }
@@ -2637,7 +2659,7 @@ isc_nm_http_endpoints_add(isc_nm_http_endpoints_t *restrict eps,
        isc_nm_httpcbarg_t *restrict httpcbarg = NULL;
        bool newhandler = false;
 
-       REQUIRE(eps != NULL);
+       REQUIRE(VALID_HTTP_ENDPOINTS(eps));
        REQUIRE(isc_nm_http_path_isvalid(uri));
        REQUIRE(atomic_load(&eps->in_use) == false);
 
@@ -2966,6 +2988,90 @@ isc__nm_http_set_max_streams(isc_nmsocket_t *listener,
        atomic_store(&listener->h2.max_concurrent_streams, max_streams);
 }
 
+void
+isc_nm_http_set_endpoints(isc_nmsocket_t *listener,
+                         isc_nm_http_endpoints_t *eps) {
+       REQUIRE(VALID_NMSOCK(listener));
+       REQUIRE(listener->type == isc_nm_httplistener);
+       REQUIRE(VALID_HTTP_ENDPOINTS(eps));
+
+       atomic_store(&eps->in_use, true);
+
+       for (size_t i = 0; i < isc_nm_getnworkers(listener->mgr); i++) {
+               isc__netievent__http_eps_t *ievent =
+                       isc__nm_get_netievent_httpendpoints(listener->mgr,
+                                                           listener, eps);
+               isc__nm_enqueue_ievent(&listener->mgr->workers[i],
+                                      (isc__netievent_t *)ievent);
+       }
+}
+
+void
+isc__nm_async_httpendpoints(isc__networker_t *worker, isc__netievent_t *ev0) {
+       isc__netievent__http_eps_t *ievent = (isc__netievent__http_eps_t *)ev0;
+       const int tid = isc_nm_tid();
+       isc_nmsocket_t *listener = ievent->sock;
+       isc_nm_http_endpoints_t *eps = ievent->endpoints;
+       UNUSED(worker);
+
+       isc_nm_http_endpoints_detach(&listener->h2.listener_endpoints[tid]);
+       isc_nm_http_endpoints_attach(eps,
+                                    &listener->h2.listener_endpoints[tid]);
+}
+
+static void
+http_init_listener_endpoints(isc_nmsocket_t *listener,
+                            isc_nm_http_endpoints_t *epset) {
+       size_t nworkers;
+
+       REQUIRE(VALID_NMSOCK(listener));
+       REQUIRE(VALID_NM(listener->mgr));
+       REQUIRE(VALID_HTTP_ENDPOINTS(epset));
+
+       nworkers = (size_t)isc_nm_getnworkers(listener->mgr);
+       INSIST(nworkers > 0);
+
+       listener->h2.listener_endpoints =
+               isc_mem_get(listener->mgr->mctx,
+                           sizeof(isc_nm_http_endpoints_t *) * nworkers);
+       listener->h2.n_listener_endpoints = nworkers;
+       for (size_t i = 0; i < nworkers; i++) {
+               listener->h2.listener_endpoints[i] = NULL;
+               isc_nm_http_endpoints_attach(
+                       epset, &listener->h2.listener_endpoints[i]);
+       }
+}
+
+static void
+http_cleanup_listener_endpoints(isc_nmsocket_t *listener) {
+       REQUIRE(VALID_NM(listener->mgr));
+
+       if (listener->h2.listener_endpoints == NULL) {
+               return;
+       }
+
+       for (size_t i = 0; i < listener->h2.n_listener_endpoints; i++) {
+               isc_nm_http_endpoints_detach(
+                       &listener->h2.listener_endpoints[i]);
+       }
+       isc_mem_put(listener->mgr->mctx, listener->h2.listener_endpoints,
+                   sizeof(isc_nm_http_endpoints_t *) *
+                           listener->h2.n_listener_endpoints);
+       listener->h2.n_listener_endpoints = 0;
+}
+
+static isc_nm_http_endpoints_t *
+http_get_listener_endpoints(isc_nmsocket_t *listener, const int tid) {
+       isc_nm_http_endpoints_t *eps;
+       REQUIRE(VALID_NMSOCK(listener));
+       REQUIRE(tid >= 0);
+       REQUIRE((size_t)tid < listener->h2.n_listener_endpoints);
+
+       eps = listener->h2.listener_endpoints[tid];
+       INSIST(eps != NULL);
+       return (eps);
+}
+
 static const bool base64url_validation_table[256] = {
        false, false, false, false, false, false, false, false, false, false,
        false, false, false, false, false, false, false, false, false, false,
@@ -3119,8 +3225,7 @@ isc__nm_http_cleanup_data(isc_nmsocket_t *sock) {
                if (sock->type == isc_nm_httplistener &&
                    sock->h2.listener_endpoints != NULL) {
                        /* Delete all handlers */
-                       isc_nm_http_endpoints_detach(
-                               &sock->h2.listener_endpoints);
+                       http_cleanup_listener_endpoints(sock);
                }
 
                if (sock->h2.request_path != NULL) {
index 6d5251bba386943d536ff62b7081d97bc596ce47..8ea7155223d5ea45a02237679ff72fbaf796ff3d 100644 (file)
@@ -313,6 +313,7 @@ typedef enum isc__netievent_type {
 
        netievent_httpclose,
        netievent_httpsend,
+       netievent_httpendpoints,
 
        netievent_shutdown,
        netievent_stop,
@@ -695,6 +696,42 @@ typedef struct isc__netievent__tlsctx {
                isc__nm_put_netievent(nm, ievent);                             \
        }
 
+#ifdef HAVE_LIBNGHTTP2
+typedef struct isc__netievent__http_eps {
+       NETIEVENT__SOCKET;
+       isc_nm_http_endpoints_t *endpoints;
+} isc__netievent__http_eps_t;
+
+#define NETIEVENT_SOCKET_HTTP_EPS_TYPE(type) \
+       typedef isc__netievent__http_eps_t isc__netievent_##type##_t;
+
+#define NETIEVENT_SOCKET_HTTP_EPS_DECL(type)                     \
+       isc__netievent_##type##_t *isc__nm_get_netievent_##type( \
+               isc_nm_t *nm, isc_nmsocket_t *sock,              \
+               isc_nm_http_endpoints_t *endpoints);             \
+       void isc__nm_put_netievent_##type(isc_nm_t *nm,          \
+                                         isc__netievent_##type##_t *ievent);
+
+#define NETIEVENT_SOCKET_HTTP_EPS_DEF(type)                                    \
+       isc__netievent_##type##_t *isc__nm_get_netievent_##type(               \
+               isc_nm_t *nm, isc_nmsocket_t *sock,                            \
+               isc_nm_http_endpoints_t *endpoints) {                          \
+               isc__netievent_##type##_t *ievent =                            \
+                       isc__nm_get_netievent(nm, netievent_##type);           \
+               isc__nmsocket_attach(sock, &ievent->sock);                     \
+               isc_nm_http_endpoints_attach(endpoints, &ievent->endpoints);   \
+                                                                               \
+               return (ievent);                                               \
+       }                                                                      \
+                                                                               \
+       void isc__nm_put_netievent_##type(isc_nm_t *nm,                        \
+                                         isc__netievent_##type##_t *ievent) { \
+               isc_nm_http_endpoints_detach(&ievent->endpoints);              \
+               isc__nmsocket_detach(&ievent->sock);                           \
+               isc__nm_put_netievent(nm, ievent);                             \
+       }
+#endif /* HAVE_LIBNGHTTP2 */
+
 typedef union {
        isc__netievent_t ni;
        isc__netievent__socket_t nis;
@@ -703,6 +740,9 @@ typedef union {
        isc__netievent__socket_quota_t nisq;
        isc__netievent_tlsconnect_t nitc;
        isc__netievent__tlsctx_t nitls;
+#ifdef HAVE_LIBNGHTTP2
+       isc__netievent__http_eps_t nihttpeps;
+#endif /* HAVE_LIBNGHTTP2 */
 } isc__netievent_storage_t;
 
 /*
@@ -846,6 +886,7 @@ typedef struct isc_nm_httphandler {
 } isc_nm_httphandler_t;
 
 struct isc_nm_http_endpoints {
+       uint32_t magic;
        isc_mem_t *mctx;
 
        ISC_LIST(isc_nm_httphandler_t) handlers;
@@ -891,7 +932,8 @@ typedef struct isc_nmsocket_h2 {
        void *cbarg;
        LINK(struct isc_nmsocket_h2) link;
 
-       isc_nm_http_endpoints_t *listener_endpoints;
+       isc_nm_http_endpoints_t **listener_endpoints;
+       size_t n_listener_endpoints;
 
        bool response_submitted;
        struct {
@@ -1796,6 +1838,9 @@ isc__nm_async_httpstop(isc__networker_t *worker, isc__netievent_t *ev0);
 void
 isc__nm_async_httpclose(isc__networker_t *worker, isc__netievent_t *ev0);
 
+void
+isc__nm_async_httpendpoints(isc__networker_t *worker, isc__netievent_t *ev0);
+
 bool
 isc__nm_parse_httpquery(const char *query_string, const char **start,
                        size_t *len);
@@ -1971,9 +2016,12 @@ NETIEVENT_SOCKET_HANDLE_TYPE(tlsdnscancel);
 NETIEVENT_SOCKET_QUOTA_TYPE(tlsdnsaccept);
 NETIEVENT_SOCKET_TYPE(tlsdnscycle);
 
+#ifdef HAVE_LIBNGHTTP2
 NETIEVENT_SOCKET_TYPE(httpstop);
 NETIEVENT_SOCKET_REQ_TYPE(httpsend);
 NETIEVENT_SOCKET_TYPE(httpclose);
+NETIEVENT_SOCKET_HTTP_EPS_TYPE(httpendpoints);
+#endif /* HAVE_LIBNGHTTP2 */
 
 NETIEVENT_SOCKET_REQ_TYPE(tcpconnect);
 NETIEVENT_SOCKET_REQ_TYPE(tcpsend);
@@ -2041,9 +2089,12 @@ NETIEVENT_SOCKET_HANDLE_DECL(tlsdnscancel);
 NETIEVENT_SOCKET_QUOTA_DECL(tlsdnsaccept);
 NETIEVENT_SOCKET_DECL(tlsdnscycle);
 
+#ifdef HAVE_LIBNGHTTP2
 NETIEVENT_SOCKET_DECL(httpstop);
 NETIEVENT_SOCKET_REQ_DECL(httpsend);
 NETIEVENT_SOCKET_DECL(httpclose);
+NETIEVENT_SOCKET_HTTP_EPS_DECL(httpendpoints);
+#endif /* HAVE_LIBNGHTTP2 */
 
 NETIEVENT_SOCKET_REQ_DECL(tcpconnect);
 NETIEVENT_SOCKET_REQ_DECL(tcpsend);
index 3285adbe7d845376efd65817008cf724a4e12cb9..5921f86bab2223694eecee40c01c1051ab479b94 100644 (file)
@@ -921,6 +921,7 @@ process_netievent(isc__networker_t *worker, isc__netievent_t *ievent) {
                NETIEVENT_CASE(httpstop);
                NETIEVENT_CASE(httpsend);
                NETIEVENT_CASE(httpclose);
+               NETIEVENT_CASE(httpendpoints);
 #endif
                NETIEVENT_CASE(settlsctx);
 
@@ -1034,9 +1035,12 @@ NETIEVENT_SOCKET_QUOTA_DEF(tlsdnsaccept);
 NETIEVENT_SOCKET_DEF(tlsdnscycle);
 NETIEVENT_SOCKET_DEF(tlsdnsshutdown);
 
+#ifdef HAVE_LIBNGHTTP2
 NETIEVENT_SOCKET_DEF(httpstop);
 NETIEVENT_SOCKET_REQ_DEF(httpsend);
 NETIEVENT_SOCKET_DEF(httpclose);
+NETIEVENT_SOCKET_HTTP_EPS_DEF(httpendpoints);
+#endif /* HAVE_LIBNGHTTP2 */
 
 NETIEVENT_SOCKET_REQ_DEF(tcpconnect);
 NETIEVENT_SOCKET_REQ_DEF(tcpsend);
index 8604e62032c2f58f45aa55202aad7dc94a2075a7..aff010cc7e87f48f84dca51e2a3112242e2435bf 100644 (file)
@@ -570,6 +570,24 @@ ns_interface_listentls(ns_interface_t *ifp, isc_tlsctx_t *sslctx) {
        return (result);
 }
 
+#ifdef HAVE_LIBNGHTTP2
+static isc_result_t
+load_http_endpoints(isc_nm_http_endpoints_t *epset, ns_interface_t *ifp,
+                   char **eps, size_t neps) {
+       isc_result_t result = ISC_R_FAILURE;
+
+       for (size_t i = 0; i < neps; i++) {
+               result = isc_nm_http_endpoints_add(epset, eps[i],
+                                                  ns__client_request, ifp);
+               if (result != ISC_R_SUCCESS) {
+                       break;
+               }
+       }
+
+       return (result);
+}
+#endif /* HAVE_LIBNGHTTP2 */
+
 static isc_result_t
 ns_interface_listenhttp(ns_interface_t *ifp, isc_tlsctx_t *sslctx, char **eps,
                        size_t neps, uint32_t max_clients,
@@ -582,13 +600,7 @@ ns_interface_listenhttp(ns_interface_t *ifp, isc_tlsctx_t *sslctx, char **eps,
 
        epset = isc_nm_http_endpoints_new(ifp->mgr->mctx);
 
-       for (size_t i = 0; i < neps; i++) {
-               result = isc_nm_http_endpoints_add(epset, eps[i],
-                                                  ns__client_request, ifp);
-               if (result != ISC_R_SUCCESS) {
-                       break;
-               }
-       }
+       result = load_http_endpoints(epset, ifp, eps, neps);
 
        if (result == ISC_R_SUCCESS) {
                quota = isc_mem_get(ifp->mgr->mctx, sizeof(*quota));
@@ -946,7 +958,9 @@ replace_listener_tlsctx(ns_interface_t *ifp, isc_tlsctx_t *newctx) {
 #ifdef HAVE_LIBNGHTTP2
 static void
 update_http_settings(ns_interface_t *ifp, ns_listenelt_t *le) {
+       isc_result_t result;
        isc_nmsocket_t *listener;
+       isc_nm_http_endpoints_t *epset;
 
        REQUIRE(le->is_http);
 
@@ -961,6 +975,17 @@ update_http_settings(ns_interface_t *ifp, ns_listenelt_t *le) {
        }
 
        isc_nmsocket_set_max_streams(listener, le->max_concurrent_streams);
+
+       epset = isc_nm_http_endpoints_new(ifp->mgr->mctx);
+
+       result = load_http_endpoints(epset, ifp, le->http_endpoints,
+                                    le->http_endpoints_number);
+
+       if (result == ISC_R_SUCCESS) {
+               isc_nm_http_set_endpoints(listener, epset);
+       }
+
+       isc_nm_http_endpoints_detach(&epset);
 }
 #endif /* HAVE_LIBNGHTTP2 */