]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
QUIC APL: Add stream creation APIs
authorHugo Landau <hlandau@openssl.org>
Tue, 18 Apr 2023 18:30:54 +0000 (19:30 +0100)
committerHugo Landau <hlandau@openssl.org>
Fri, 12 May 2023 13:47:11 +0000 (14:47 +0100)
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/20765)

include/internal/quic_channel.h
include/internal/quic_stream_map.h
ssl/quic/quic_channel.c
ssl/quic/quic_channel_local.h
ssl/quic/quic_impl.c
ssl/quic/quic_local.h

index d60e4010bdfe2a0bffa45fa6e7f4be64799025fc..7ccf6e0bb250073e350c7d4d3785a4cb5a71fa1c 100644 (file)
@@ -270,6 +270,13 @@ SSL *ossl_quic_channel_get0_ssl(QUIC_CHANNEL *ch);
  */
 CRYPTO_MUTEX *ossl_quic_channel_get_mutex(QUIC_CHANNEL *ch);
 
+/*
+ * Creates a new locally-initiated stream in the stream mapper, choosing an
+ * appropriate stream ID. If is_uni is 1, creates a unidirectional stream, else
+ * creates a bidirectional stream.
+ */
+QUIC_STREAM *ossl_quic_channel_new_stream(QUIC_CHANNEL *ch, int is_uni);
+
 # endif
 
 #endif
index f9a04723c1e2f733568748145965f63007ad20f3..0bdd7e88cfd237b0bdb0e48811ffccd2c35c9d3a 100644 (file)
@@ -101,6 +101,9 @@ struct quic_stream_st {
 
     /* A FIN has been retired from the rstream buffer. */
     unsigned int    recv_fin_retired        : 1;
+
+    /* The stream's XSO has been deleted. Pending GC. */
+    unsigned int    deleted                 : 1;
 };
 
 /*
index 7ef66b234d8113f6f1ff7a8f6d88ab5a7657d368..8e1d41593542128cb9004f28b53afd8cbc855c4f 100644 (file)
@@ -2213,3 +2213,32 @@ SSL *ossl_quic_channel_get0_ssl(QUIC_CHANNEL *ch)
 {
     return ch->tls;
 }
+
+QUIC_STREAM *ossl_quic_channel_new_stream(QUIC_CHANNEL *ch, int is_uni)
+{
+    QUIC_STREAM *qs;
+    int type = 0;
+    uint64_t stream_id, *p_next_ordinal;
+
+    type |= ch->is_server ? QUIC_STREAM_INITIATOR_SERVER
+                          : QUIC_STREAM_INITIATOR_CLIENT;
+
+    if (is_uni) {
+        p_next_ordinal = &ch->next_local_stream_ordinal_uni;
+        type |= QUIC_STREAM_DIR_UNI;
+    } else {
+        p_next_ordinal = &ch->next_local_stream_ordinal_bidi;
+        type |= QUIC_STREAM_DIR_BIDI;
+    }
+
+    if (*p_next_ordinal >= ((uint64_t)1) << 62)
+        return NULL;
+
+    stream_id = ((*p_next_ordinal) << 2) | type;
+
+    if ((qs = ossl_quic_stream_map_alloc(&ch->qsm, stream_id, type)) == NULL)
+        return NULL;
+
+    ++*p_next_ordinal;
+    return qs;
+}
index fbf16a93dbfae75e0a7a7ec2d83e869c4ad4f097..8534ae9835c5b90188fd2fc3313c34503bc7fd33 100644 (file)
@@ -159,6 +159,14 @@ struct quic_channel_st {
     /* Maximum active CID limit, as negotiated by transport parameters. */
     uint64_t                        rx_active_conn_id_limit;
 
+    /*
+     * Used to allocate stream IDs. This is a stream ordinal, i.e., a stream ID
+     * without the low two bits designating type and initiator. Shift and or in
+     * the type bits to convert to a stream ID.
+     */
+    uint64_t                        next_local_stream_ordinal_bidi;
+    uint64_t                        next_local_stream_ordinal_uni;
+
     /* Valid if we are in the TERMINATING or TERMINATED states. */
     QUIC_TERMINATE_CAUSE            terminate_cause;
 
index c02efed5f85d3f4e64811afea33e0b0bff6e8bc4..0dd6576633525e2f762d59f769f40ba68cdea8eb 100644 (file)
@@ -257,10 +257,16 @@ SSL *ossl_quic_new(SSL_CTX *ctx)
     if (!create_channel(qc))
         goto err;
 
+    if ((qc->default_xso = (QUIC_XSO *)ossl_quic_conn_stream_new(&qc->ssl, 0)) == NULL)
+        goto err;
+
     return ssl_base;
 
 err:
-    SSL_free(qc->tls);
+    if (qc != NULL) {
+        ossl_quic_channel_free(qc->ch);
+        SSL_free(qc->tls);
+    }
     OPENSSL_free(qc);
     return NULL;
 }
@@ -275,8 +281,39 @@ void ossl_quic_free(SSL *s)
     if (!expect_quic(s, &ctx))
         return;
 
+    if (ctx.is_stream) {
+        /*
+         * When a QSSO is freed, the XSO is freed immediately, because the XSO
+         * itself only contains API personality layer data. However the
+         * underlying QUIC_STREAM is not freed immediately but is instead marked
+         * as deleted for later collection.
+         */
+
+        quic_lock(ctx.qc);
+
+        assert(ctx.qc->num_xso > 0);
+        --ctx.qc->num_xso;
+
+        ctx.xso->stream->deleted = 1;
+
+        quic_unlock(ctx.qc);
+
+        /* Note: SSL_free calls OPENSSL_free(xso) for us */
+        return;
+    }
+
     quic_lock(ctx.qc);
 
+    /*
+     * Free the default XSO, if any. The QUIC_STREAM is not deleted at this
+     * stage, but is freed during the channel free when the whole QSM is freed.
+     */
+    if (ctx.qc->default_xso != NULL)
+        SSL_free(&ctx.qc->default_xso->ssl);
+
+    /* Ensure we have no remaining XSOs. */
+    assert(ctx.qc->num_xso == 0);
+
     if (ctx.qc->is_thread_assisted && ctx.qc->started) {
         ossl_quic_thread_assist_wait_stopped(&ctx.qc->thread_assist);
         ossl_quic_thread_assist_cleanup(&ctx.qc->thread_assist);
@@ -1047,12 +1084,20 @@ SSL *ossl_quic_conn_stream_new(SSL *s, uint64_t flags)
 {
     QCTX ctx;
     QUIC_XSO *xso = NULL;
+    int is_uni = ((flags & SSL_STREAM_FLAG_UNI) != 0);
 
     if (!expect_quic_conn_only(s, &ctx))
         return NULL;
 
+    quic_lock(ctx.qc);
+
+    if (ossl_quic_channel_is_term_any(ctx.qc->ch)) {
+        QUIC_RAISE_NON_NORMAL_ERROR(ctx.qc, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL);
+        goto err;
+    }
+
     if ((xso = OPENSSL_zalloc(sizeof(*xso))) == NULL)
-        return NULL;
+        goto err;
 
     if (!ossl_ssl_init(&xso->ssl, s->ctx, s->method, SSL_TYPE_QUIC_XSO))
         goto err;
@@ -1061,11 +1106,18 @@ SSL *ossl_quic_conn_stream_new(SSL *s, uint64_t flags)
     xso->blocking   = ctx.qc->default_blocking;
     xso->ssl_mode   = ctx.qc->default_ssl_mode;
 
-    xso->stream     = NULL; /* TODO XXX ossl_quic_channel_new_stream */
+    xso->stream     = ossl_quic_channel_new_stream(ctx.qc->ch, is_uni);
+    if (xso->stream == NULL)
+        goto err;
+
+    ++ctx.qc->num_xso;
+
+    quic_unlock(ctx.qc);
     return &xso->ssl;
 
 err:
     OPENSSL_free(xso);
+    quic_unlock(ctx.qc);
     return NULL;
 }
 
index 3906a20357e8bfe3716f52a3f40bd09dbc3557c5..4b9d715c9bff79f35dbf06b96a0c8490a017b598 100644 (file)
@@ -138,6 +138,9 @@ struct quic_conn_st {
     OSSL_TIME                       (*override_now_cb)(void *arg);
     void                            *override_now_cb_arg;
 
+    /* Number of XSOs allocated. Includes the default XSO, if any. */
+    size_t                          num_xso;
+
     /* Have we started? */
     unsigned int                    started                 : 1;