# 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
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;
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;
};
/*
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
*/
void ossl_quic_stream_iter_next(QUIC_STREAM_ITER *it);
+# endif
+
#endif
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;
}
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);