diff --git a/lib/isc/include/isc/netmgr.h b/lib/isc/include/isc/netmgr.h index 8dc8360662..b8e67b6135 100644 --- a/lib/isc/include/isc/netmgr.h +++ b/lib/isc/include/isc/netmgr.h @@ -674,8 +674,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 79f21c19cf..e604ee7d63 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)); @@ -1654,14 +1667,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); } @@ -1691,7 +1705,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, isc_sockaddr_t *iface, int backlog, 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, iface, httplisten_acceptcb, sock, @@ -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); @@ -2968,6 +2990,93 @@ 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) { + size_t nworkers; + + REQUIRE(VALID_NMSOCK(listener)); + REQUIRE(listener->type == isc_nm_httplistener); + REQUIRE(VALID_HTTP_ENDPOINTS(eps)); + + atomic_store(&eps->in_use, true); + + nworkers = (size_t)listener->mgr->nworkers; + for (size_t i = 0; i < nworkers; 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)listener->mgr->nworkers; + 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, @@ -3121,8 +3230,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 973af0e985..624530a35c 100644 --- a/lib/isc/netmgr/netmgr-int.h +++ b/lib/isc/netmgr/netmgr-int.h @@ -319,6 +319,7 @@ typedef enum isc__netievent_type { netievent_httpclose, netievent_httpsend, + netievent_httpendpoints, netievent_shutdown, netievent_stop, @@ -702,6 +703,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; @@ -710,6 +747,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; /* @@ -854,6 +894,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; @@ -899,7 +940,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 { @@ -1812,6 +1854,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); @@ -2005,9 +2050,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); @@ -2076,9 +2124,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 2eaa7d1dd0..cc7263d914 100644 --- a/lib/isc/netmgr/netmgr.c +++ b/lib/isc/netmgr/netmgr.c @@ -955,6 +955,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); @@ -1068,9 +1069,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 72e0f47867..1bd684126f 100644 --- a/lib/ns/interfacemgr.c +++ b/lib/ns/interfacemgr.c @@ -568,6 +568,25 @@ 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, + sizeof(ns_client_t)); + 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, @@ -580,14 +599,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, - sizeof(ns_client_t)); - 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)); @@ -944,7 +956,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); @@ -959,6 +973,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 */