From: Stefan Eissing Date: Mon, 12 Aug 2024 13:42:41 +0000 (+0200) Subject: http2+h3 filters: fix ctx init X-Git-Tag: curl-8_10_0~289 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cb17c069a8ca645efc9b90282526e61481f02a2a;p=thirdparty%2Fcurl.git http2+h3 filters: fix ctx init Members of the filter context, like stream hash and buffers, need to be initialized early and protected by a flag to also avoid double cleanup. This allow the context to be used safely before a connect() is started and the other parts of the context are set up. Closes #14505 --- diff --git a/lib/http2.c b/lib/http2.c index 86f76ab379..6b4aabca70 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -142,6 +142,8 @@ struct cf_h2_ctx { uint32_t goaway_error; /* goaway error code from server */ int32_t remote_max_sid; /* max id processed by server */ int32_t local_max_sid; /* max id processed by us */ + BIT(initialized); + BIT(via_h1_upgrade); BIT(conn_closed); BIT(rcvd_goaway); BIT(sent_goaway); @@ -154,28 +156,38 @@ struct cf_h2_ctx { #define CF_CTX_CALL_DATA(cf) \ ((struct cf_h2_ctx *)(cf)->ctx)->call_data -static void cf_h2_ctx_clear(struct cf_h2_ctx *ctx) +static void h2_stream_hash_free(void *stream); + +static void cf_h2_ctx_init(struct cf_h2_ctx *ctx, bool via_h1_upgrade) { - struct cf_call_data save = ctx->call_data; + Curl_bufcp_init(&ctx->stream_bufcp, H2_CHUNK_SIZE, H2_STREAM_POOL_SPARES); + Curl_bufq_initp(&ctx->inbufq, &ctx->stream_bufcp, H2_NW_RECV_CHUNKS, 0); + Curl_bufq_initp(&ctx->outbufq, &ctx->stream_bufcp, H2_NW_SEND_CHUNKS, 0); + Curl_dyn_init(&ctx->scratch, CURL_MAX_HTTP_HEADER); + Curl_hash_offt_init(&ctx->streams, 63, h2_stream_hash_free); + ctx->remote_max_sid = 2147483647; + ctx->via_h1_upgrade = via_h1_upgrade; + ctx->initialized = TRUE; +} - if(ctx->h2) { - nghttp2_session_del(ctx->h2); +static void cf_h2_ctx_free(struct cf_h2_ctx *ctx) +{ + if(ctx && ctx->initialized) { + Curl_bufq_free(&ctx->inbufq); + Curl_bufq_free(&ctx->outbufq); + Curl_bufcp_free(&ctx->stream_bufcp); + Curl_dyn_free(&ctx->scratch); + Curl_hash_clean(&ctx->streams); + Curl_hash_destroy(&ctx->streams); + memset(ctx, 0, sizeof(*ctx)); } - Curl_bufq_free(&ctx->inbufq); - Curl_bufq_free(&ctx->outbufq); - Curl_bufcp_free(&ctx->stream_bufcp); - Curl_dyn_free(&ctx->scratch); - Curl_hash_clean(&ctx->streams); - Curl_hash_destroy(&ctx->streams); - memset(ctx, 0, sizeof(*ctx)); - ctx->call_data = save; + free(ctx); } -static void cf_h2_ctx_free(struct cf_h2_ctx *ctx) +static void cf_h2_ctx_close(struct cf_h2_ctx *ctx) { - if(ctx) { - cf_h2_ctx_clear(ctx); - free(ctx); + if(ctx->h2) { + nghttp2_session_del(ctx->h2); } } @@ -390,7 +402,7 @@ static void http2_data_done(struct Curl_cfilter *cf, struct Curl_easy *data) struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data); DEBUGASSERT(ctx); - if(!stream) + if(!stream || !ctx->initialized) return; if(ctx->h2) { @@ -489,12 +501,8 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, static int error_callback(nghttp2_session *session, const char *msg, size_t len, void *userp); -/* - * Initialize the cfilter context - */ -static CURLcode cf_h2_ctx_init(struct Curl_cfilter *cf, - struct Curl_easy *data, - bool via_h1_upgrade) +static CURLcode cf_h2_ctx_open(struct Curl_cfilter *cf, + struct Curl_easy *data) { struct cf_h2_ctx *ctx = cf->ctx; struct h2_stream_ctx *stream; @@ -503,12 +511,7 @@ static CURLcode cf_h2_ctx_init(struct Curl_cfilter *cf, nghttp2_session_callbacks *cbs = NULL; DEBUGASSERT(!ctx->h2); - Curl_bufcp_init(&ctx->stream_bufcp, H2_CHUNK_SIZE, H2_STREAM_POOL_SPARES); - Curl_bufq_initp(&ctx->inbufq, &ctx->stream_bufcp, H2_NW_RECV_CHUNKS, 0); - Curl_bufq_initp(&ctx->outbufq, &ctx->stream_bufcp, H2_NW_SEND_CHUNKS, 0); - Curl_dyn_init(&ctx->scratch, CURL_MAX_HTTP_HEADER); - Curl_hash_offt_init(&ctx->streams, 63, h2_stream_hash_free); - ctx->remote_max_sid = 2147483647; + DEBUGASSERT(ctx->initialized); rc = nghttp2_session_callbacks_new(&cbs); if(rc) { @@ -537,7 +540,7 @@ static CURLcode cf_h2_ctx_init(struct Curl_cfilter *cf, } ctx->max_concurrent_streams = DEFAULT_MAX_CONCURRENT_STREAMS; - if(via_h1_upgrade) { + if(ctx->via_h1_upgrade) { /* HTTP/1.1 Upgrade issued. H2 Settings have already been submitted * in the H1 request and we upgrade from there. This stream * is opened implicitly as #1. */ @@ -603,7 +606,7 @@ static CURLcode cf_h2_ctx_init(struct Curl_cfilter *cf, /* all set, traffic will be send on connect */ result = CURLE_OK; CURL_TRC_CF(data, cf, "[0] created h2 session%s", - via_h1_upgrade? " (via h1 upgrade)" : ""); + ctx->via_h1_upgrade? " (via h1 upgrade)" : ""); out: if(cbs) @@ -2450,8 +2453,9 @@ static CURLcode cf_h2_connect(struct Curl_cfilter *cf, *done = FALSE; CF_DATA_SAVE(save, cf, data); + DEBUGASSERT(ctx->initialized); if(!ctx->h2) { - result = cf_h2_ctx_init(cf, data, FALSE); + result = cf_h2_ctx_open(cf, data); if(result) goto out; } @@ -2486,7 +2490,7 @@ static void cf_h2_close(struct Curl_cfilter *cf, struct Curl_easy *data) struct cf_call_data save; CF_DATA_SAVE(save, cf, data); - cf_h2_ctx_clear(ctx); + cf_h2_ctx_close(ctx); CF_DATA_RESTORE(cf, save); cf->connected = FALSE; } @@ -2735,6 +2739,7 @@ static CURLcode http2_cfilter_add(struct Curl_cfilter **pcf, ctx = calloc(1, sizeof(*ctx)); if(!ctx) goto out; + cf_h2_ctx_init(ctx, via_h1_upgrade); result = Curl_cf_create(&cf, &Curl_cft_nghttp2, ctx); if(result) @@ -2742,7 +2747,6 @@ static CURLcode http2_cfilter_add(struct Curl_cfilter **pcf, ctx = NULL; Curl_conn_cf_add(data, conn, sockindex, cf); - result = cf_h2_ctx_init(cf, data, via_h1_upgrade); out: if(result) @@ -2763,6 +2767,7 @@ static CURLcode http2_cfilter_insert_after(struct Curl_cfilter *cf, ctx = calloc(1, sizeof(*ctx)); if(!ctx) goto out; + cf_h2_ctx_init(ctx, via_h1_upgrade); result = Curl_cf_create(&cf_h2, &Curl_cft_nghttp2, ctx); if(result) @@ -2770,7 +2775,6 @@ static CURLcode http2_cfilter_insert_after(struct Curl_cfilter *cf, ctx = NULL; Curl_conn_cf_insert_after(cf, cf_h2); - result = cf_h2_ctx_init(cf_h2, data, via_h1_upgrade); out: if(result) diff --git a/lib/vquic/curl_msh3.c b/lib/vquic/curl_msh3.c index c8466280a2..17e7d402f4 100644 --- a/lib/vquic/curl_msh3.c +++ b/lib/vquic/curl_msh3.c @@ -124,11 +124,33 @@ struct cf_msh3_ctx { bool handshake_complete; bool handshake_succeeded; bool connected; + BIT(initialized); /* Flags written by curl thread */ BIT(verbose); BIT(active); }; +static void h3_stream_hash_free(void *stream); + +static void cf_msh3_ctx_init(struct cf_msh3_ctx *ctx, + const struct Curl_addrinfo *ai) +{ + DEBUGASSERT(!ctx->initialized); + Curl_hash_offt_init(&ctx->streams, 63, h3_stream_hash_free); + Curl_sock_assign_addr(&ctx->addr, ai, TRNSPRT_QUIC); + ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD; + ctx->sock[SP_REMOTE] = CURL_SOCKET_BAD; + ctx->initialized = TRUE; +} + +static void cf_msh3_ctx_free(struct cf_msh3_ctx *ctx) +{ + if(ctx && ctx->initialized) { + Curl_hash_destroy(&ctx->streams); + } + free(ctx); +} + static struct cf_msh3_ctx *h3_get_msh3_ctx(struct Curl_easy *data); /* How to access `call_data` from a cf_msh3 filter */ @@ -798,7 +820,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf, CURLcode result; bool verify; - Curl_hash_offt_init(&ctx->streams, 63, h3_stream_hash_free); + DEBUGASSERT(ctx->initialized); conn_config = Curl_ssl_cf_get_primary_config(cf); if(!conn_config) return CURLE_FAILED_INIT; @@ -925,7 +947,6 @@ static void cf_msh3_close(struct Curl_cfilter *cf, struct Curl_easy *data) MsH3ApiClose(ctx->api); ctx->api = NULL; } - Curl_hash_destroy(&ctx->streams); if(ctx->active) { /* We share our socket at cf->conn->sock[cf->sockindex] when active. @@ -964,10 +985,11 @@ static void cf_msh3_destroy(struct Curl_cfilter *cf, struct Curl_easy *data) CF_DATA_SAVE(save, cf, data); cf_msh3_close(cf, data); - free(cf->ctx); - cf->ctx = NULL; + if(cf->ctx) { + cf_msh3_ctx_free(cf->ctx); + cf->ctx = NULL; + } /* no CF_DATA_RESTORE(cf, save); its gone */ - } static CURLcode cf_msh3_query(struct Curl_cfilter *cf, @@ -1066,9 +1088,7 @@ CURLcode Curl_cf_msh3_create(struct Curl_cfilter **pcf, result = CURLE_OUT_OF_MEMORY; goto out; } - Curl_sock_assign_addr(&ctx->addr, ai, TRNSPRT_QUIC); - ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD; - ctx->sock[SP_REMOTE] = CURL_SOCKET_BAD; + cf_msh3_ctx_init(ctx, ai); result = Curl_cf_create(&cf, &Curl_cft_http3, ctx); @@ -1076,7 +1096,7 @@ out: *pcf = (!result)? cf : NULL; if(result) { Curl_safefree(cf); - Curl_safefree(ctx); + cf_msh3_ctx_free(ctx); } return result; diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index f672bfcaeb..0674e1aa9b 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -138,6 +138,7 @@ struct cf_ngtcp2_ctx { uint64_t used_bidi_streams; /* bidi streams we have opened */ uint64_t max_bidi_streams; /* max bidi streams we can open */ int qlogfd; + BIT(initialized); BIT(shutdown_started); /* queued shutdown packets */ }; @@ -146,6 +147,34 @@ struct cf_ngtcp2_ctx { #define CF_CTX_CALL_DATA(cf) \ ((struct cf_ngtcp2_ctx *)(cf)->ctx)->call_data +static void h3_stream_hash_free(void *stream); + +static void cf_ngtcp2_ctx_init(struct cf_ngtcp2_ctx *ctx) +{ + DEBUGASSERT(!ctx->initialized); + ctx->qlogfd = -1; + ctx->version = NGTCP2_PROTO_VER_MAX; + ctx->max_stream_window = H3_STREAM_WINDOW_SIZE; + ctx->max_idle_ms = CURL_QUIC_MAX_IDLE_MS; + Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE, + H3_STREAM_POOL_SPARES); + Curl_dyn_init(&ctx->scratch, CURL_MAX_HTTP_HEADER); + Curl_hash_offt_init(&ctx->streams, 63, h3_stream_hash_free); + ctx->initialized = TRUE; +} + +static void cf_ngtcp2_ctx_free(struct cf_ngtcp2_ctx *ctx) +{ + if(ctx && ctx->initialized) { + Curl_bufcp_free(&ctx->stream_bufcp); + Curl_dyn_free(&ctx->scratch); + Curl_hash_clean(&ctx->streams); + Curl_hash_destroy(&ctx->streams); + Curl_ssl_peer_cleanup(&ctx->peer); + } + free(ctx); +} + struct pkt_io_ctx; static CURLcode cf_progress_ingress(struct Curl_cfilter *cf, struct Curl_easy *data, @@ -1963,27 +1992,22 @@ static CURLcode cf_ngtcp2_data_event(struct Curl_cfilter *cf, return result; } -static void cf_ngtcp2_ctx_clear(struct cf_ngtcp2_ctx *ctx) +static void cf_ngtcp2_ctx_close(struct cf_ngtcp2_ctx *ctx) { struct cf_call_data save = ctx->call_data; + if(!ctx->initialized) + return; if(ctx->qlogfd != -1) { close(ctx->qlogfd); } + ctx->qlogfd = -1; Curl_vquic_tls_cleanup(&ctx->tls); vquic_ctx_free(&ctx->q); if(ctx->h3conn) nghttp3_conn_del(ctx->h3conn); if(ctx->qconn) ngtcp2_conn_del(ctx->qconn); - Curl_bufcp_free(&ctx->stream_bufcp); - Curl_dyn_free(&ctx->scratch); - Curl_hash_clean(&ctx->streams); - Curl_hash_destroy(&ctx->streams); - Curl_ssl_peer_cleanup(&ctx->peer); - - memset(ctx, 0, sizeof(*ctx)); - ctx->qlogfd = -1; ctx->call_data = save; } @@ -2088,7 +2112,7 @@ static void cf_ngtcp2_close(struct Curl_cfilter *cf, struct Curl_easy *data) CF_DATA_SAVE(save, cf, data); if(ctx && ctx->qconn) { cf_ngtcp2_conn_close(cf, data); - cf_ngtcp2_ctx_clear(ctx); + cf_ngtcp2_ctx_close(ctx); CURL_TRC_CF(data, cf, "close"); } cf->connected = FALSE; @@ -2097,18 +2121,11 @@ static void cf_ngtcp2_close(struct Curl_cfilter *cf, struct Curl_easy *data) static void cf_ngtcp2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data) { - struct cf_ngtcp2_ctx *ctx = cf->ctx; - struct cf_call_data save; - - CF_DATA_SAVE(save, cf, data); CURL_TRC_CF(data, cf, "destroy"); - if(ctx) { - cf_ngtcp2_ctx_clear(ctx); - free(ctx); + if(cf->ctx) { + cf_ngtcp2_ctx_free(cf->ctx); + cf->ctx = NULL; } - cf->ctx = NULL; - /* No CF_DATA_RESTORE(cf, save) possible */ - (void)save; } #ifdef USE_OPENSSL @@ -2190,14 +2207,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf, const struct Curl_sockaddr_ex *sockaddr = NULL; int qfd; - ctx->version = NGTCP2_PROTO_VER_MAX; - ctx->max_stream_window = H3_STREAM_WINDOW_SIZE; - ctx->max_idle_ms = CURL_QUIC_MAX_IDLE_MS; - Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE, - H3_STREAM_POOL_SPARES); - Curl_dyn_init(&ctx->scratch, CURL_MAX_HTTP_HEADER); - Curl_hash_offt_init(&ctx->streams, 63, h3_stream_hash_free); - + DEBUGASSERT(ctx->initialized); result = Curl_ssl_peer_init(&ctx->peer, cf, TRNSPRT_QUIC); if(result) return result; @@ -2512,8 +2522,7 @@ CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf, result = CURLE_OUT_OF_MEMORY; goto out; } - ctx->qlogfd = -1; - cf_ngtcp2_ctx_clear(ctx); + cf_ngtcp2_ctx_init(ctx); result = Curl_cf_create(&cf, &Curl_cft_http3, ctx); if(result) @@ -2534,7 +2543,7 @@ out: if(udp_cf) Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE); Curl_safefree(cf); - Curl_safefree(ctx); + cf_ngtcp2_ctx_free(ctx); } return result; } diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index 46565bee42..31469c8d43 100644 --- a/lib/vquic/curl_osslq.c +++ b/lib/vquic/curl_osslq.c @@ -293,6 +293,7 @@ struct cf_osslq_ctx { struct Curl_hash streams; /* hash `data->id` to `h3_stream_ctx` */ size_t max_stream_window; /* max flow window for one stream */ uint64_t max_idle_ms; /* max idle time for QUIC connection */ + BIT(initialized); BIT(got_first_byte); /* if first byte was received */ BIT(x509_store_setup); /* if x509 store has been set up */ BIT(protocol_shutdown); /* QUIC connection is shut down */ @@ -300,19 +301,35 @@ struct cf_osslq_ctx { BIT(need_send); /* QUIC connection needs to send */ }; -static void cf_osslq_ctx_clear(struct cf_osslq_ctx *ctx) +static void h3_stream_hash_free(void *stream); + +static void cf_osslq_ctx_init(struct cf_osslq_ctx *ctx) +{ + DEBUGASSERT(!ctx->initialized); + Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE, + H3_STREAM_POOL_SPARES); + Curl_hash_offt_init(&ctx->streams, 63, h3_stream_hash_free); + ctx->initialized = TRUE; +} + +static void cf_osslq_ctx_free(struct cf_osslq_ctx *ctx) +{ + if(ctx && ctx->initialized) { + Curl_bufcp_free(&ctx->stream_bufcp); + Curl_hash_clean(&ctx->streams); + Curl_hash_destroy(&ctx->streams); + Curl_ssl_peer_cleanup(&ctx->peer); + } + free(ctx); +} + +static void cf_osslq_ctx_close(struct cf_osslq_ctx *ctx) { struct cf_call_data save = ctx->call_data; cf_osslq_h3conn_cleanup(&ctx->h3); Curl_vquic_tls_cleanup(&ctx->tls); vquic_ctx_free(&ctx->q); - Curl_bufcp_free(&ctx->stream_bufcp); - Curl_hash_clean(&ctx->streams); - Curl_hash_destroy(&ctx->streams); - Curl_ssl_peer_cleanup(&ctx->peer); - - memset(ctx, 0, sizeof(*ctx)); ctx->call_data = save; } @@ -401,7 +418,7 @@ static void cf_osslq_close(struct Curl_cfilter *cf, struct Curl_easy *data) (SSL_SHUTDOWN_FLAG_NO_BLOCK | SSL_SHUTDOWN_FLAG_RAPID), NULL, 0); } - cf_osslq_ctx_clear(ctx); + cf_osslq_ctx_close(ctx); } cf->connected = FALSE; @@ -417,8 +434,7 @@ static void cf_osslq_destroy(struct Curl_cfilter *cf, struct Curl_easy *data) CURL_TRC_CF(data, cf, "destroy"); if(ctx) { CURL_TRC_CF(data, cf, "cf_osslq_destroy()"); - cf_osslq_ctx_clear(ctx); - free(ctx); + cf_osslq_ctx_free(ctx); } cf->ctx = NULL; /* No CF_DATA_RESTORE(cf, save) possible */ @@ -1148,9 +1164,7 @@ static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf, BIO *bio = NULL; BIO_ADDR *baddr = NULL; - Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE, - H3_STREAM_POOL_SPARES); - Curl_hash_offt_init(&ctx->streams, 63, h3_stream_hash_free); + DEBUGASSERT(ctx->initialized); result = Curl_ssl_peer_init(&ctx->peer, cf, TRNSPRT_QUIC); if(result) goto out; @@ -2330,7 +2344,7 @@ CURLcode Curl_cf_osslq_create(struct Curl_cfilter **pcf, result = CURLE_OUT_OF_MEMORY; goto out; } - cf_osslq_ctx_clear(ctx); + cf_osslq_ctx_init(ctx); result = Curl_cf_create(&cf, &Curl_cft_http3, ctx); if(result) @@ -2351,7 +2365,7 @@ out: if(udp_cf) Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE); Curl_safefree(cf); - Curl_safefree(ctx); + cf_osslq_ctx_free(ctx); } return result; } diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index fafbb03ee6..79963ca388 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -100,12 +100,15 @@ struct cf_quiche_ctx { struct bufc_pool stream_bufcp; /* chunk pool for streams */ struct Curl_hash streams; /* hash `data->id` to `stream_ctx` */ curl_off_t data_recvd; + BIT(initialized); BIT(goaway); /* got GOAWAY from server */ BIT(x509_store_setup); /* if x509 store has been set up */ BIT(shutdown_started); /* queued shutdown packets */ }; #ifdef DEBUG_QUICHE +/* initialize debug log callback only once */ +static int debug_log_init = 0; static void quiche_debug_log(const char *line, void *argp) { (void)argp; @@ -113,17 +116,27 @@ static void quiche_debug_log(const char *line, void *argp) } #endif -static void cf_quiche_ctx_clear(struct cf_quiche_ctx *ctx) +static void h3_stream_hash_free(void *stream); + +static void cf_quiche_ctx_init(struct cf_quiche_ctx *ctx) { - if(ctx) { - if(ctx->h3c) - quiche_h3_conn_free(ctx->h3c); - if(ctx->h3config) - quiche_h3_config_free(ctx->h3config); - if(ctx->qconn) - quiche_conn_free(ctx->qconn); - if(ctx->cfg) - quiche_config_free(ctx->cfg); + DEBUGASSERT(!ctx->initialized); +#ifdef DEBUG_QUICHE + if(!debug_log_init) { + quiche_enable_debug_logging(quiche_debug_log, NULL); + debug_log_init = 1; + } +#endif + Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE, + H3_STREAM_POOL_SPARES); + Curl_hash_offt_init(&ctx->streams, 63, h3_stream_hash_free); + ctx->data_recvd = 0; + ctx->initialized = TRUE; +} + +static void cf_quiche_ctx_free(struct cf_quiche_ctx *ctx) +{ + if(ctx && ctx->initialized) { /* quiche just freed it */ ctx->tls.ossl.ssl = NULL; Curl_vquic_tls_cleanup(&ctx->tls); @@ -132,9 +145,20 @@ static void cf_quiche_ctx_clear(struct cf_quiche_ctx *ctx) Curl_bufcp_free(&ctx->stream_bufcp); Curl_hash_clean(&ctx->streams); Curl_hash_destroy(&ctx->streams); - - memset(ctx, 0, sizeof(*ctx)); } + free(ctx); +} + +static void cf_quiche_ctx_close(struct cf_quiche_ctx *ctx) +{ + if(ctx->h3c) + quiche_h3_conn_free(ctx->h3c); + if(ctx->h3config) + quiche_h3_config_free(ctx->h3config); + if(ctx->qconn) + quiche_conn_free(ctx->qconn); + if(ctx->cfg) + quiche_config_free(ctx->cfg); } static CURLcode cf_flush_egress(struct Curl_cfilter *cf, @@ -1240,8 +1264,8 @@ static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf, return result; } -static CURLcode cf_connect_start(struct Curl_cfilter *cf, - struct Curl_easy *data) +static CURLcode cf_quiche_ctx_open(struct Curl_cfilter *cf, + struct Curl_easy *data) { struct cf_quiche_ctx *ctx = cf->ctx; int rv; @@ -1249,19 +1273,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf, const struct Curl_sockaddr_ex *sockaddr; DEBUGASSERT(ctx->q.sockfd != CURL_SOCKET_BAD); - -#ifdef DEBUG_QUICHE - /* initialize debug log callback only once */ - static int debug_log_init = 0; - if(!debug_log_init) { - quiche_enable_debug_logging(quiche_debug_log, NULL); - debug_log_init = 1; - } -#endif - Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE, - H3_STREAM_POOL_SPARES); - Curl_hash_offt_init(&ctx->streams, 63, h3_stream_hash_free); - ctx->data_recvd = 0; + DEBUGASSERT(ctx->initialized); result = vquic_ctx_init(&ctx->q); if(result) @@ -1403,7 +1415,7 @@ static CURLcode cf_quiche_connect(struct Curl_cfilter *cf, } if(!ctx->qconn) { - result = cf_connect_start(cf, data); + result = cf_quiche_ctx_open(cf, data); if(result) goto out; ctx->started_at = ctx->q.last_op; @@ -1515,23 +1527,20 @@ out: static void cf_quiche_close(struct Curl_cfilter *cf, struct Curl_easy *data) { - struct cf_quiche_ctx *ctx = cf->ctx; - - if(ctx) { + if(cf->ctx) { bool done; (void)cf_quiche_shutdown(cf, data, &done); - cf_quiche_ctx_clear(ctx); + cf_quiche_ctx_close(cf->ctx); } } static void cf_quiche_destroy(struct Curl_cfilter *cf, struct Curl_easy *data) { - struct cf_quiche_ctx *ctx = cf->ctx; - (void)data; - cf_quiche_ctx_clear(ctx); - free(ctx); - cf->ctx = NULL; + if(cf->ctx) { + cf_quiche_ctx_free(cf->ctx); + cf->ctx = NULL; + } } static CURLcode cf_quiche_query(struct Curl_cfilter *cf, @@ -1652,6 +1661,7 @@ CURLcode Curl_cf_quiche_create(struct Curl_cfilter **pcf, result = CURLE_OUT_OF_MEMORY; goto out; } + cf_quiche_ctx_init(ctx); result = Curl_cf_create(&cf, &Curl_cft_http3, ctx); if(result) @@ -1671,7 +1681,7 @@ out: if(udp_cf) Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE); Curl_safefree(cf); - Curl_safefree(ctx); + cf_quiche_ctx_free(ctx); } return result;