]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
QUIC Stream Mapper: CSM-related changes, stream limits handling
authorHugo Landau <hlandau@openssl.org>
Thu, 17 Nov 2022 15:29:44 +0000 (15:29 +0000)
committerHugo Landau <hlandau@openssl.org>
Fri, 13 Jan 2023 13:20:15 +0000 (13:20 +0000)
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/19703)

include/internal/quic_stream_map.h
ssl/quic/quic_stream_map.c
test/quic_txp_test.c

index 5f0e0347e4f70733def8bcde97e13aa9be97c432..b4e0993eb584805175dfca9942e6349b40ebe7a8 100644 (file)
 # define OSSL_INTERNAL_QUIC_STREAM_MAP_H
 # pragma once
 
-#include "internal/e_os.h"
-#include "internal/time.h"
-#include "internal/quic_types.h"
-#include "internal/quic_stream.h"
-#include "internal/quic_fc.h"
-#include <openssl/lhash.h>
+# include "internal/e_os.h"
+# include "internal/time.h"
+# include "internal/quic_types.h"
+# include "internal/quic_stream.h"
+# include "internal/quic_fc.h"
+# include <openssl/lhash.h>
+
+# ifndef OPENSSL_NO_QUIC
 
 /*
  * QUIC Stream
@@ -68,18 +70,23 @@ struct quic_stream_st {
     unsigned int    active : 1;
 
     /*
-     * Has STOP_SENDING been requested? Note that this is not the same as
-     * want_stop_sending below, as a STOP_SENDING frame may already have been
+     * Has STOP_SENDING been requested (by us)? Note that this is not the same
+     * as want_stop_sending below, as a STOP_SENDING frame may already have been
      * sent and fully acknowledged.
      */
     unsigned int    stop_sending            : 1;
 
     /*
-     * Has RESET_STREAM been requested? Works identically to STOP_SENDING for
-     * transmission purposes.
+     * Has RESET_STREAM been requested (by us)? Works identically to
+     * STOP_SENDING for transmission purposes.
      */
     unsigned int    reset_stream            : 1;
 
+    /* Has our peer sent a STOP_SENDING frame? */
+    unsigned int    peer_stop_sending       : 1;
+    /* Has our peer sent a RESET_STREAM frame? */
+    unsigned int    peer_reset_stream       : 1;
+
     /* Temporary flags used by TXP. */
     unsigned int    txp_sent_fc             : 1;
     unsigned int    txp_sent_stop_sending   : 1;
@@ -91,6 +98,9 @@ struct quic_stream_st {
     unsigned int    want_max_stream_data    : 1; /* used for regen only */
     unsigned int    want_stop_sending       : 1; /* used for gen or regen */
     unsigned int    want_reset_stream       : 1; /* used for gen or regen */
+
+    /* A FIN has been retired from the rstream buffer. */
+    unsigned int    recv_fin_retired        : 1;
 };
 
 /*
@@ -121,9 +131,26 @@ typedef struct quic_stream_map_st {
     QUIC_STREAM_LIST_NODE   active_list;
     size_t                  rr_stepping, rr_counter;
     QUIC_STREAM             *rr_cur;
+    uint64_t                (*get_stream_limit_cb)(int uni, void *arg);
+    void                    *get_stream_limit_cb_arg;
 } QUIC_STREAM_MAP;
 
-int ossl_quic_stream_map_init(QUIC_STREAM_MAP *qsm);
+/*
+ * get_stream_limit is a callback which is called to retrieve the current stream
+ * limit for streams created by us. This mechanism is not used for
+ * peer-initiated streams. If a stream's stream ID is x, a stream is allowed if
+ * (x >> 2) < returned limit value; i.e., the returned value is exclusive.
+ *
+ * If uni is 1, get the limit for locally-initiated unidirectional streams, else
+ * get the limit for locally-initiated bidirectional streams.
+ *
+ * If the callback is NULL, stream limiting is not applied.
+ * Stream limiting is used to determine if frames can currently be produced for
+ * a stream.
+ */
+int ossl_quic_stream_map_init(QUIC_STREAM_MAP *qsm,
+                              uint64_t (*get_stream_limit_cb)(int uni, void *arg),
+                              void *get_stream_limit_cb_arg);
 
 /*
  * Any streams still in the map will be released as though
@@ -229,4 +256,6 @@ void ossl_quic_stream_iter_init(QUIC_STREAM_ITER *it, QUIC_STREAM_MAP *qsm,
  */
 void ossl_quic_stream_iter_next(QUIC_STREAM_ITER *it);
 
+# endif
+
 #endif
index d080bac2339477fa3812746f3b221a3c17a24625..52e8e14bf8f547e159db331e3272510dcc534a11 100644 (file)
@@ -91,13 +91,18 @@ static int cmp_stream(const QUIC_STREAM *a, const QUIC_STREAM *b)
     return 0;
 }
 
-int ossl_quic_stream_map_init(QUIC_STREAM_MAP *qsm)
+int ossl_quic_stream_map_init(QUIC_STREAM_MAP *qsm,
+                              uint64_t (*get_stream_limit_cb)(int uni, void *arg),
+                              void *get_stream_limit_cb_arg)
 {
     qsm->map = lh_QUIC_STREAM_new(hash_stream, cmp_stream);
     qsm->active_list.prev = qsm->active_list.next = &qsm->active_list;
     qsm->rr_stepping = 1;
     qsm->rr_counter  = 0;
     qsm->rr_cur      = NULL;
+
+    qsm->get_stream_limit_cb        = get_stream_limit_cb;
+    qsm->get_stream_limit_cb_arg    = get_stream_limit_cb_arg;
     return 1;
 }
 
@@ -236,13 +241,29 @@ static int stream_has_data_to_send(QUIC_STREAM *s)
 
 void ossl_quic_stream_map_update_state(QUIC_STREAM_MAP *qsm, QUIC_STREAM *s)
 {
-    int should_be_active
-        = (s->rstream != NULL
-           && (s->want_max_stream_data
-               || ossl_quic_rxfc_has_cwm_changed(&s->rxfc, 0)))
-        || s->want_stop_sending
-        || s->want_reset_stream
-        || stream_has_data_to_send(s);
+    int should_be_active, allowed_by_stream_limit = 1;
+
+    if (qsm->get_stream_limit_cb != NULL
+        && (s->type & QUIC_STREAM_INITIATOR_CLIENT) != 0) {
+        int uni = ((s->type & QUIC_STREAM_DIR_UNI) != 0);
+        uint64_t stream_limit, stream_ordinal = s->id >> 2;
+
+        stream_limit
+            = qsm->get_stream_limit_cb(uni, qsm->get_stream_limit_cb_arg);
+
+        allowed_by_stream_limit = (stream_ordinal < stream_limit);
+    }
+
+    should_be_active
+        = allowed_by_stream_limit
+        && !s->peer_stop_sending
+        && !s->peer_reset_stream
+        && ((s->rstream != NULL
+            && (s->want_max_stream_data
+                || ossl_quic_rxfc_has_cwm_changed(&s->rxfc, 0)))
+            || s->want_stop_sending
+            || s->want_reset_stream
+            || stream_has_data_to_send(s));
 
     if (should_be_active)
         stream_map_mark_active(qsm, s);
index ab9b943c7ef25d9a585c2953b767297df981fe09..8d2361af18b7a9b82cc509b8b85be77f570827ab 100644 (file)
@@ -162,7 +162,7 @@ static int helper_init(struct helper *h)
                                                h->cc_data)))
         goto err;
 
-    if (!TEST_true(ossl_quic_stream_map_init(&h->qsm)))
+    if (!TEST_true(ossl_quic_stream_map_init(&h->qsm, NULL, NULL)))
         goto err;
 
     h->have_qsm = 1;