From d2e13ddf225af1cc285742ab3f6aa3c594810045 Mon Sep 17 00:00:00 2001 From: Artem Boldariev Date: Wed, 22 Jun 2022 19:31:18 +0300 Subject: [PATCH] Update the set of HTTP endpoints on reconfiguration This commit ensures that on reconfiguration the set of HTTP endpoints (=paths) is being updated within HTTP listeners. --- lib/isc/include/isc/netmgr.h | 3 +- lib/isc/netmgr/http.c | 121 ++++++++++++++++++++++++++++++++--- lib/isc/netmgr/netmgr-int.h | 53 ++++++++++++++- lib/isc/netmgr/netmgr.c | 4 ++ lib/ns/interfacemgr.c | 39 +++++++++-- 5 files changed, 202 insertions(+), 18 deletions(-) diff --git a/lib/isc/include/isc/netmgr.h b/lib/isc/include/isc/netmgr.h index 6333bfc569..75e66f6713 100644 --- a/lib/isc/include/isc/netmgr.h +++ b/lib/isc/include/isc/netmgr.h @@ -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. */ diff --git a/lib/isc/netmgr/http.c b/lib/isc/netmgr/http.c index 8acc4baa99..6d58906b89 100644 --- a/lib/isc/netmgr/http.c +++ b/lib/isc/netmgr/http.c @@ -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) { diff --git a/lib/isc/netmgr/netmgr-int.h b/lib/isc/netmgr/netmgr-int.h index 6d5251bba3..8ea7155223 100644 --- a/lib/isc/netmgr/netmgr-int.h +++ b/lib/isc/netmgr/netmgr-int.h @@ -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); diff --git a/lib/isc/netmgr/netmgr.c b/lib/isc/netmgr/netmgr.c index 3285adbe7d..5921f86bab 100644 --- a/lib/isc/netmgr/netmgr.c +++ b/lib/isc/netmgr/netmgr.c @@ -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); diff --git a/lib/ns/interfacemgr.c b/lib/ns/interfacemgr.c index 8604e62032..aff010cc7e 100644 --- a/lib/ns/interfacemgr.c +++ b/lib/ns/interfacemgr.c @@ -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 */