From 8a2e9abac8dbdab154461484a19261daf05926f7 Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Tue, 18 Jul 2023 16:15:49 +0100 Subject: [PATCH] QUIC APL: Shutdown Stream Flush Functionality Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/21484) --- ssl/quic/quic_impl.c | 55 +++++++++++++++++++++++++++++++++++++++++-- ssl/quic/quic_local.h | 7 ++++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/ssl/quic/quic_impl.c b/ssl/quic/quic_impl.c index a725bd73108..4479e98f4f2 100644 --- a/ssl/quic/quic_impl.c +++ b/ssl/quic/quic_impl.c @@ -1097,6 +1097,30 @@ int ossl_quic_get_net_write_desired(SSL *s) * */ +QUIC_NEEDS_LOCK +static void qc_shutdown_flush_init(QUIC_CONNECTION *qc) +{ + QUIC_STREAM_MAP *qsm; + + if (qc->shutting_down) + return; + + qsm = ossl_quic_channel_get_qsm(qc->ch); + + ossl_quic_stream_map_begin_shutdown_flush(qsm); + qc->shutting_down = 1; +} + +/* Returns 1 if all shutdown-flush streams have been done with. */ +QUIC_NEEDS_LOCK +static int qc_shutdown_flush_finished(QUIC_CONNECTION *qc) +{ + QUIC_STREAM_MAP *qsm = ossl_quic_channel_get_qsm(qc->ch); + + return qc->shutting_down + && ossl_quic_stream_map_is_shutdown_flush_finished(qsm); +} + /* SSL_shutdown */ static int quic_shutdown_wait(void *arg) { @@ -1105,6 +1129,15 @@ static int quic_shutdown_wait(void *arg) return ossl_quic_channel_is_terminated(qc->ch); } +/* Returns 1 if shutdown flush process has finished or is inapplicable. */ +static int quic_shutdown_flush_wait(void *arg) +{ + QUIC_CONNECTION *qc = arg; + + return ossl_quic_channel_is_term_any(qc->ch) + || qc_shutdown_flush_finished(qc); +} + QUIC_TAKES_LOCK int ossl_quic_conn_shutdown(SSL *s, uint64_t flags, const SSL_SHUTDOWN_EX_ARGS *args, @@ -1112,6 +1145,7 @@ int ossl_quic_conn_shutdown(SSL *s, uint64_t flags, { int ret; QCTX ctx; + int stream_flush = ((flags & SSL_SHUTDOWN_FLAG_NO_STREAM_FLUSH) == 0); if (!expect_quic(s, &ctx)) return 0; @@ -1122,16 +1156,33 @@ int ossl_quic_conn_shutdown(SSL *s, uint64_t flags, quic_lock(ctx.qc); + /* Phase 1: Stream Flushing */ + if (stream_flush) { + qc_shutdown_flush_init(ctx.qc); + + if (!qc_shutdown_flush_finished(ctx.qc)) { + if (qc_blocking_mode(ctx.qc)) + block_until_pred(ctx.qc, quic_shutdown_flush_wait, ctx.qc, 0); + else + ossl_quic_reactor_tick(ossl_quic_channel_get_reactor(ctx.qc->ch), 0); + } + + if (!qc_shutdown_flush_finished(ctx.qc)) { + quic_unlock(ctx.qc); + return 0; /* ongoing */ + } + } + + /* Phase 2: Connection Closure */ ossl_quic_channel_local_close(ctx.qc->ch, args != NULL ? args->quic_error_code : 0); - /* TODO(QUIC): !SSL_SHUTDOWN_FLAG_NO_STREAM_FLUSH */ - if (ossl_quic_channel_is_terminated(ctx.qc->ch)) { quic_unlock(ctx.qc); return 1; } + /* Phase 3: Terminating Wait Time */ if (qc_blocking_mode(ctx.qc) && (flags & SSL_SHUTDOWN_FLAG_RAPID) == 0) block_until_pred(ctx.qc, quic_shutdown_wait, ctx.qc, 0); else diff --git a/ssl/quic/quic_local.h b/ssl/quic/quic_local.h index 7e257825c86..eb6d3e4e6f6 100644 --- a/ssl/quic/quic_local.h +++ b/ssl/quic/quic_local.h @@ -182,6 +182,13 @@ struct quic_conn_st { /* Have we created a default XSO yet? */ unsigned int default_xso_created : 1; + /* + * Pre-TERMINATING shutdown phase in which we are flushing streams. + * Monotonically transitions to 1. + * New streams cannot be created in this state. + */ + unsigned int shutting_down : 1; + /* Default stream type. Defaults to SSL_DEFAULT_STREAM_MODE_AUTO_BIDI. */ uint32_t default_stream_mode; -- 2.47.2