QUIC_STREAM_MAP *qsm; /* QUIC Streams Map */
QUIC_TXFC *conn_txfc; /* QUIC Connection-Level TX Flow Controller */
QUIC_RXFC *conn_rxfc; /* QUIC Connection-Level RX Flow Controller */
+ QUIC_RXFC *max_streams_bidi_rxfc; /* QUIC RXFC for MAX_STREAMS generation */
+ QUIC_RXFC *max_streams_uni_rxfc;
const OSSL_CC_METHOD *cc_method; /* QUIC Congestion Controller */
OSSL_CC_DATA *cc_data; /* QUIC Congestion Controller Instance */
OSSL_TIME (*now)(void *arg); /* Callback to get current time. */
#define DEFAULT_INIT_STREAM_RXFC_WND (2 * 1024 * 1024)
#define DEFAULT_STREAM_RXFC_MAX_WND_MUL 5
+#define DEFAULT_INIT_CONN_MAX_STREAMS 100
+
static int ch_init(QUIC_CHANNEL *ch)
{
OSSL_QUIC_TX_PACKETISER_ARGS txp_args = {0};
get_time, ch))
goto err;
+ if (!ossl_quic_rxfc_init_for_stream_count(&ch->max_streams_bidi_rxfc,
+ DEFAULT_INIT_CONN_MAX_STREAMS,
+ get_time, ch))
+ goto err;
+
+ if (!ossl_quic_rxfc_init_for_stream_count(&ch->max_streams_uni_rxfc,
+ DEFAULT_INIT_CONN_MAX_STREAMS,
+ get_time, ch))
+ goto err;
+
if (!ossl_statm_init(&ch->statm))
goto err;
ch->cc_method, ch->cc_data)) == NULL)
goto err;
- if (!ossl_quic_stream_map_init(&ch->qsm, get_stream_limit, ch))
+ if (!ossl_quic_stream_map_init(&ch->qsm, get_stream_limit, ch,
+ &ch->max_streams_bidi_rxfc,
+ &ch->max_streams_uni_rxfc))
goto err;
ch->have_qsm = 1;
/* We use a zero-length SCID. */
- txp_args.cur_dcid = ch->init_dcid;
- txp_args.ack_delay_exponent = 3;
- txp_args.qtx = ch->qtx;
- txp_args.txpim = ch->txpim;
- txp_args.cfq = ch->cfq;
- txp_args.ackm = ch->ackm;
- txp_args.qsm = &ch->qsm;
- txp_args.conn_txfc = &ch->conn_txfc;
- txp_args.conn_rxfc = &ch->conn_rxfc;
- txp_args.cc_method = ch->cc_method;
- txp_args.cc_data = ch->cc_data;
- txp_args.now = get_time;
- txp_args.now_arg = ch;
+ txp_args.cur_dcid = ch->init_dcid;
+ txp_args.ack_delay_exponent = 3;
+ txp_args.qtx = ch->qtx;
+ txp_args.txpim = ch->txpim;
+ txp_args.cfq = ch->cfq;
+ txp_args.ackm = ch->ackm;
+ txp_args.qsm = &ch->qsm;
+ txp_args.conn_txfc = &ch->conn_txfc;
+ txp_args.conn_rxfc = &ch->conn_rxfc;
+ txp_args.max_streams_bidi_rxfc = &ch->max_streams_bidi_rxfc;
+ txp_args.max_streams_uni_rxfc = &ch->max_streams_uni_rxfc;
+ txp_args.cc_method = ch->cc_method;
+ txp_args.cc_data = ch->cc_data;
+ txp_args.now = get_time;
+ txp_args.now_arg = ch;
for (pn_space = QUIC_PN_SPACE_INITIAL; pn_space < QUIC_PN_SPACE_NUM; ++pn_space) {
ch->crypto_send[pn_space] = ossl_quic_sstream_new(INIT_CRYPTO_BUF_LEN);
if (ch->crypto_send[pn_space] == NULL)
ch->tx_init_max_stream_data_uni))
goto err;
- /* TODO(QUIC): MAX_STREAMS modelling */
if (!ossl_quic_wire_encode_transport_param_int(&wpkt, QUIC_TPARAM_INITIAL_MAX_STREAMS_BIDI,
- ch->is_server ? 100 : 100))
+ ossl_quic_rxfc_get_cwm(&ch->max_streams_bidi_rxfc)))
goto err;
if (!ossl_quic_wire_encode_transport_param_int(&wpkt, QUIC_TPARAM_INITIAL_MAX_STREAMS_UNI,
- 100))
+ ossl_quic_rxfc_get_cwm(&ch->max_streams_uni_rxfc)))
goto err;
if (!WPACKET_get_total_written(&wpkt, &buf_len))
OSSL_QUIC_TX_PACKETISER *txp;
QUIC_TXPIM *txpim;
QUIC_CFQ *cfq;
- /* Connection level FC. */
+ /*
+ * Connection level FC. The stream_count RXFCs is used to manage
+ * MAX_STREAMS signalling.
+ */
QUIC_TXFC conn_txfc;
QUIC_RXFC conn_rxfc;
+ QUIC_RXFC max_streams_bidi_rxfc, max_streams_uni_rxfc;
QUIC_STREAM_MAP qsm;
OSSL_STATM statm;
OSSL_CC_DATA *cc_data;
|| args->ackm == NULL
|| args->qsm == NULL
|| args->conn_txfc == NULL
- || args->conn_rxfc == NULL) {
+ || args->conn_rxfc == NULL
+ || args->max_streams_bidi_rxfc == NULL
+ || args->max_streams_uni_rxfc == NULL) {
ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
return 1;
/* Do we want to produce a MAX_STREAMS frame? */
- if (a.allow_conn_fc && (txp->want_max_streams_bidi
- || txp->want_max_streams_uni))
+ if (a.allow_conn_fc
+ && (txp->want_max_streams_bidi
+ || ossl_quic_rxfc_has_cwm_changed(txp->args.max_streams_bidi_rxfc,
+ 0)
+ || txp->want_max_streams_uni
+ || ossl_quic_rxfc_has_cwm_changed(txp->args.max_streams_uni_rxfc,
+ 0)))
return 1;
/* Do we want to produce a HANDSHAKE_DONE frame? */
}
/* MAX_STREAMS_BIDI (Regenerate) */
- /*
- * TODO(STREAMS): Once we support multiple streams, add stream count FC
- * and plug this in.
- */
if (a.allow_conn_fc
- && txp->want_max_streams_bidi
+ && (txp->want_max_streams_bidi
+ || ossl_quic_rxfc_has_cwm_changed(txp->args.max_streams_bidi_rxfc, 0))
&& tx_helper_get_space_left(&h) >= MIN_FRAME_SIZE_MAX_STREAMS_BIDI) {
WPACKET *wpkt = tx_helper_begin(&h);
- uint64_t max_streams = 1; /* TODO */
+ uint64_t max_streams
+ = ossl_quic_rxfc_get_cwm(txp->args.max_streams_bidi_rxfc);
if (wpkt == NULL)
goto fatal_err;
/* MAX_STREAMS_UNI (Regenerate) */
if (a.allow_conn_fc
- && txp->want_max_streams_uni
+ && (txp->want_max_streams_uni
+ || ossl_quic_rxfc_has_cwm_changed(txp->args.max_streams_uni_rxfc, 0))
&& tx_helper_get_space_left(&h) >= MIN_FRAME_SIZE_MAX_STREAMS_UNI) {
WPACKET *wpkt = tx_helper_begin(&h);
- uint64_t max_streams = 0; /* TODO */
+ uint64_t max_streams
+ = ossl_quic_rxfc_get_cwm(txp->args.max_streams_uni_rxfc);
if (wpkt == NULL)
goto fatal_err;
ossl_quic_rxfc_has_cwm_changed(txp->args.conn_rxfc, 1);
}
- if (tpkt->had_max_streams_bidi_frame)
+ if (tpkt->had_max_streams_bidi_frame) {
txp->want_max_streams_bidi = 0;
+ ossl_quic_rxfc_has_cwm_changed(txp->args.max_streams_bidi_rxfc, 1);
+ }
- if (tpkt->had_max_streams_uni_frame)
+ if (tpkt->had_max_streams_uni_frame) {
txp->want_max_streams_uni = 0;
+ ossl_quic_rxfc_has_cwm_changed(txp->args.max_streams_uni_rxfc, 1);
+ }
if (tpkt->had_ack_frame)
txp->want_ack &= ~(1UL << pn_space);
BIO *bio1, *bio2;
QUIC_TXFC conn_txfc;
QUIC_RXFC conn_rxfc, stream_rxfc;
+ QUIC_RXFC max_streams_bidi_rxfc, max_streams_uni_rxfc;
OSSL_STATM statm;
OSSL_CC_DATA *cc_data;
const OSSL_CC_METHOD *cc_method;
NULL)))
goto err;
+ if (!TEST_true(ossl_quic_rxfc_init(&h->max_streams_bidi_rxfc, NULL,
+ 100, 100,
+ fake_now,
+ NULL)))
+ goto err;
+
+ if (!TEST_true(ossl_quic_rxfc_init(&h->max_streams_uni_rxfc, NULL,
+ 100, 100,
+ fake_now,
+ NULL)))
+
if (!TEST_true(ossl_statm_init(&h->statm)))
goto err;
if (!TEST_ptr(h->args.crypto[i] = ossl_quic_sstream_new(4096)))
goto err;
- h->args.cur_scid = scid_1;
- h->args.cur_dcid = dcid_1;
- h->args.qsm = &h->qsm;
- h->args.conn_txfc = &h->conn_txfc;
- h->args.conn_rxfc = &h->conn_rxfc;
- h->args.cc_method = h->cc_method;
- h->args.cc_data = h->cc_data;
- h->args.now = fake_now;
+ h->args.cur_scid = scid_1;
+ h->args.cur_dcid = dcid_1;
+ h->args.qsm = &h->qsm;
+ h->args.conn_txfc = &h->conn_txfc;
+ h->args.conn_rxfc = &h->conn_rxfc;
+ h->args.max_streams_bidi_rxfc = &h->max_streams_bidi_rxfc;
+ h->args.max_streams_uni_rxfc = &h->max_streams_uni_rxfc;
+ h->args.cc_method = h->cc_method;
+ h->args.cc_data = h->cc_data;
+ h->args.now = fake_now;
if (!TEST_ptr(h->txp = ossl_quic_tx_packetiser_new(&h->args)))
goto err;