QUIC APL: Shutdown Stream Flush Functionality
authorHugo Landau <hlandau@openssl.org>
Tue, 18 Jul 2023 15:15:49 +0000 (16:15 +0100)
committerMatt Caswell <matt@openssl.org>
Mon, 31 Jul 2023 13:03:25 +0000 (14:03 +0100)
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/21484)

ssl/quic/quic_impl.c
ssl/quic/quic_local.h

index a725bd731082c1b12cb3f3ecf268de1558e41cdb..4479e98f4f248f2b3a3d6425f3e32b78e0673261 100644 (file)
@@ -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
index 7e257825c86c563ccedca386c315c79aaf733bd7..eb6d3e4e6f6d3eef96f7060e77845bc1980eee76 100644 (file)
@@ -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;