summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHugo Landau <hlandau@openssl.org>2022-11-17 15:29:44 +0000
committerHugo Landau <hlandau@openssl.org>2023-01-13 13:20:15 +0000
commitcbe7f586ad42b7cf6d16b11a6d614798df0a5d29 (patch)
tree85619475d9e2368a3275aff470e54f08c8a2abb4
parent3a37c9235de465fe8d557b32f0178bfad0c09908 (diff)
QUIC Stream Mapper: CSM-related changes, stream limits handling
Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/19703)
-rw-r--r--include/internal/quic_stream_map.h51
-rw-r--r--ssl/quic/quic_stream_map.c37
-rw-r--r--test/quic_txp_test.c2
3 files changed, 70 insertions, 20 deletions
diff --git a/include/internal/quic_stream_map.h b/include/internal/quic_stream_map.h
index 5f0e0347e4..b4e0993eb5 100644
--- a/include/internal/quic_stream_map.h
+++ b/include/internal/quic_stream_map.h
@@ -11,12 +11,14 @@
# 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
diff --git a/ssl/quic/quic_stream_map.c b/ssl/quic/quic_stream_map.c
index d080bac233..52e8e14bf8 100644
--- a/ssl/quic/quic_stream_map.c
+++ b/ssl/quic/quic_stream_map.c
@@ -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);
diff --git a/test/quic_txp_test.c b/test/quic_txp_test.c
index ab9b943c7e..8d2361af18 100644
--- a/test/quic_txp_test.c
+++ b/test/quic_txp_test.c
@@ -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;