diff --git a/lib/isc/netmgr/http.c b/lib/isc/netmgr/http.c index 8b005db67c..690be29e92 100644 --- a/lib/isc/netmgr/http.c +++ b/lib/isc/netmgr/http.c @@ -76,10 +76,12 @@ typedef struct http_cstream { struct isc_nm_http_session { unsigned int magic; + isc_refcount_t references; isc_mem_t *mctx; + bool sending; - bool closed; bool reading; + bool closed; nghttp2_session *ngsession; bool client; @@ -127,6 +129,9 @@ server_send_error_response(const isc_http_error_responses_t error, static isc_result_t client_send(isc_nmhandle_t *handle, const isc_region_t *region); +static void +finish_http_session(isc_nm_http_session_t *session); + static bool inactive(isc_nmsocket_t *sock) { return (!isc__nmsocket_active(sock) || atomic_load(&sock->closing) || @@ -134,6 +139,66 @@ inactive(isc_nmsocket_t *sock) { (sock->server != NULL && !isc__nmsocket_active(sock->server))); } +static void +new_session(isc_mem_t *mctx, isc_tlsctx_t *tctx, + isc_nm_http_session_t **sessionp) { + isc_nm_http_session_t *session = NULL; + + REQUIRE(sessionp != NULL && *sessionp == NULL); + REQUIRE(mctx != NULL); + + session = isc_mem_get(mctx, sizeof(isc_nm_http_session_t)); + *session = (isc_nm_http_session_t){ .magic = HTTP2_SESSION_MAGIC, + .free_tlsctx = (tctx != NULL), + .tlsctx = tctx }; + isc_refcount_init(&session->references, 1); + isc_mem_attach(mctx, &session->mctx); + ISC_LIST_INIT(session->cstreams); + + *sessionp = session; +} + +static void +session_attach(isc_nm_http_session_t *source, isc_nm_http_session_t **targetp) { + REQUIRE(VALID_HTTP2_SESSION(source)); + REQUIRE(targetp != NULL && *targetp == NULL); + + isc_refcount_increment(&source->references); + + *targetp = source; +} + +static void +session_detach(isc_nm_http_session_t **sessionp) { + isc_nm_http_session_t *session = NULL; + + REQUIRE(sessionp != NULL); + + session = *sessionp; + *sessionp = NULL; + + REQUIRE(VALID_HTTP2_SESSION(session)); + + if (isc_refcount_decrement(&session->references) > 1) { + return; + } + + finish_http_session(session); + + INSIST(ISC_LIST_EMPTY(session->sstreams)); + INSIST(ISC_LIST_EMPTY(session->cstreams)); + + /* We need an acquire memory barrier here */ + (void)isc_refcount_current(&session->references); + + session->magic = 0; + if (session->free_tlsctx) { + isc_tlsctx_free(&session->tlsctx); + } + isc_mem_putanddetach(&session->mctx, session, + sizeof(isc_nm_http_session_t)); +} + static http_cstream_t * find_http_cstream(int32_t stream_id, isc_nm_http_session_t *session) { http_cstream_t *cstream = NULL; @@ -236,19 +301,6 @@ put_http_cstream(isc_mem_t *mctx, http_cstream_t *stream) { isc_mem_put(mctx, stream, sizeof(http_cstream_t)); } -static void -delete_http_session(isc_nm_http_session_t *session) { - REQUIRE(ISC_LIST_EMPTY(session->sstreams)); - REQUIRE(ISC_LIST_EMPTY(session->cstreams)); - - session->magic = 0; - if (session->free_tlsctx) { - isc_tlsctx_free(&session->tlsctx); - } - isc_mem_putanddetach(&session->mctx, session, - sizeof(isc_nm_http_session_t)); -} - static void finish_http_session(isc_nm_http_session_t *session) { if (session->handle != NULL) { @@ -347,9 +399,8 @@ on_stream_close_callback(nghttp2_session *ngsession, int32_t stream_id, /* * NOTE: calling isc_nm_cancelread() or isc__nmsocket_prep_destroy() - * on a socket will lead to an indirect call to the - * delete_http_session() which will, in turn, perform required - * stream session cleanup. + * on a socket will lead to an indirect call to detach the session, + * which will, in turn, perform required stream cleanup. */ if (session->client) { http_cstream_t *cstream = find_http_cstream(stream_id, session); @@ -797,7 +848,6 @@ transport_connect_cb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { isc_nmsocket_t *transp_sock = NULL; http_cstream_t *cstream = NULL; isc_mem_t *mctx = NULL; - bool freectx; REQUIRE(VALID_NMSOCK(http_sock)); REQUIRE(VALID_NMHANDLE(handle)); @@ -806,7 +856,6 @@ transport_connect_cb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { REQUIRE(VALID_NMSOCK(transp_sock)); - transp_sock->h2.session = NULL; mctx = transp_sock->mgr->mctx; INSIST(http_sock->h2.connect.uri != NULL); @@ -815,16 +864,8 @@ transport_connect_cb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { goto error; } - freectx = (http_sock->tls.ctx != NULL); - - session = isc_mem_get(mctx, sizeof(isc_nm_http_session_t)); - *session = (isc_nm_http_session_t){ .magic = HTTP2_SESSION_MAGIC, - .free_tlsctx = freectx, - .tlsctx = http_sock->tls.ctx, - .handle = NULL, - .client = true }; - isc_mem_attach(mctx, &session->mctx); - ISC_LIST_INIT(session->cstreams); + new_session(mctx, http_sock->tls.ctx, &session); + session->client = true; transp_sock->h2.connect.post = http_sock->h2.connect.post; transp_sock->h2.connect.uri = http_sock->h2.connect.uri; @@ -832,8 +873,8 @@ transport_connect_cb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { http_sock->tls.ctx = NULL; isc_nmhandle_attach(handle, &session->handle); isc__nmsocket_attach(handle->sock, &http_sock->h2.connect.transport); - transp_sock->h2.session = session; - http_sock->h2.session = session; + session_attach(session, &transp_sock->h2.session); + session_attach(session, &http_sock->h2.session); if (session->tlsctx != NULL) { const unsigned char *alpn = NULL; @@ -854,7 +895,7 @@ transport_connect_cb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { initialize_nghttp2_client_session(session); if (!send_client_connection_header(session)) { - transp_sock->h2.session = NULL; + session_detach(&transp_sock->h2.session); goto error; } @@ -867,6 +908,7 @@ transport_connect_cb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { http_call_connect_cb(http_sock, result); http_do_bio(session); isc__nmsocket_detach(&http_sock); + session_detach(&session); return; error: @@ -879,6 +921,10 @@ error: isc_mem_free(mctx, http_sock->h2.connect.uri); } + if (session != NULL) { + session_detach(&session); + } + isc__nmsocket_detach(&http_sock); } @@ -1736,15 +1782,10 @@ httplisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { return (ISC_R_CANCELED); } - session = isc_mem_get(httplistensock->mgr->mctx, - sizeof(isc_nm_http_session_t)); - *session = (isc_nm_http_session_t){ .magic = HTTP2_SESSION_MAGIC, - .free_tlsctx = false, - .client = false }; + new_session(httplistensock->mgr->mctx, NULL, &session); initialize_nghttp2_server_session(session); handle->sock->h2.session = session; - isc_mem_attach(httplistensock->mgr->mctx, &session->mctx); isc_nmhandle_attach(handle, &session->handle); isc__nmsocket_attach(httplistensock, &session->serversocket); session->serversocket = httplistensock; @@ -1901,16 +1942,6 @@ clear_handlers(isc_nmsocket_t *sock) { RWUNLOCK(&sock->h2.lock, isc_rwlocktype_write); } -static void -clear_session(isc_nmsocket_t *sock) { - if (sock->h2.session != NULL) { - isc_nm_http_session_t *session = sock->h2.session; - finish_http_session(session); - delete_http_session(session); - sock->h2.session = NULL; - } -} - void isc__nm_async_httpstop(isc__networker_t *worker, isc__netievent_t *ev0) { isc__netievent_httpstop_t *ievent = (isc__netievent_httpstop_t *)ev0; @@ -2256,7 +2287,9 @@ isc__nm_http_cleanup_data(isc_nmsocket_t *sock) { sock->h2.buf = NULL; } - clear_session(sock); + if (sock->h2.session != NULL) { + session_detach(&sock->h2.session); + } } void diff --git a/lib/isc/netmgr/netmgr-int.h b/lib/isc/netmgr/netmgr-int.h index 76345ec68c..f5fbfba878 100644 --- a/lib/isc/netmgr/netmgr-int.h +++ b/lib/isc/netmgr/netmgr-int.h @@ -157,8 +157,6 @@ isc__nm_dump_active(isc_nm_t *nm); #define isc__nmsocket_prep_destroy(sock) isc___nmsocket_prep_destroy(sock) #endif -typedef struct isc_nm_http_session isc_nm_http_session_t; - /* * Single network event loop worker. */ @@ -196,6 +194,7 @@ typedef struct isc__networker { atomic_load(&(t)->references) > 0) typedef void (*isc__nm_closecb)(isc_nmhandle_t *); +typedef struct isc_nm_http_session isc_nm_http_session_t; struct isc_nmhandle { int magic;