*
* If called on a stream-level TXFC, ossl_quic_txfc_get_credit is called on
* the connection-level TXFC as well, and the lesser of the two values is
- * returned.
+ * returned. The consumed value is the amount already consumed on the connection
+ * level TXFC.
*/
-uint64_t ossl_quic_txfc_get_credit(QUIC_TXFC *txfc);
+uint64_t ossl_quic_txfc_get_credit(QUIC_TXFC *txfc, uint64_t consumed);
/*
* Like ossl_quic_txfc_get_credit(), but when called on a stream-level TXFC,
* retrieves only the stream-level credit value and does not clamp it based on
- * connection-level flow control.
+ * connection-level flow control. Any credit value is reduced by the consumed
+ * amount.
*/
-uint64_t ossl_quic_txfc_get_credit_local(QUIC_TXFC *txfc);
+uint64_t ossl_quic_txfc_get_credit_local(QUIC_TXFC *txfc, uint64_t consumed);
/*
* Consume num_bytes of credit. This is the 'On TX' operation. This should be
return 1;
}
-uint64_t ossl_quic_txfc_get_credit_local(QUIC_TXFC *txfc)
+uint64_t ossl_quic_txfc_get_credit_local(QUIC_TXFC *txfc, uint64_t consumed)
{
- assert(txfc->swm <= txfc->cwm);
- return txfc->cwm - txfc->swm;
+ assert((txfc->swm + consumed) <= txfc->cwm);
+ return txfc->cwm - (consumed + txfc->swm);
}
-uint64_t ossl_quic_txfc_get_credit(QUIC_TXFC *txfc)
+uint64_t ossl_quic_txfc_get_credit(QUIC_TXFC *txfc, uint64_t consumed)
{
uint64_t r, conn_r;
- r = ossl_quic_txfc_get_credit_local(txfc);
+ r = ossl_quic_txfc_get_credit_local(txfc, 0);
if (txfc->parent != NULL) {
assert(txfc->parent->parent == NULL);
- conn_r = ossl_quic_txfc_get_credit_local(txfc->parent);
+ conn_r = ossl_quic_txfc_get_credit_local(txfc->parent, consumed);
if (conn_r < r)
r = conn_r;
}
int ossl_quic_txfc_consume_credit_local(QUIC_TXFC *txfc, uint64_t num_bytes)
{
int ok = 1;
- uint64_t credit = ossl_quic_txfc_get_credit_local(txfc);
+ uint64_t credit = ossl_quic_txfc_get_credit_local(txfc, 0);
if (num_bytes > credit) {
ok = 0;
&num_iov))
return 0;
- fc_credit = ossl_quic_txfc_get_credit(&s->txfc);
+ fc_credit = ossl_quic_txfc_get_credit(&s->txfc, 0);
fc_swm = ossl_quic_txfc_get_swm(&s->txfc);
fc_limit = fc_swm + fc_credit;
QUIC_SSTREAM *sstream,
QUIC_TXFC *stream_txfc,
size_t skip,
- struct chunk_info *chunk)
+ struct chunk_info *chunk,
+ uint64_t consumed)
{
uint64_t fc_credit, fc_swm, fc_limit;
chunk->orig_len = chunk->shdr.len;
/* Clamp according to connection and stream-level TXFC. */
- fc_credit = ossl_quic_txfc_get_credit(stream_txfc);
+ fc_credit = ossl_quic_txfc_get_credit(stream_txfc, consumed);
fc_swm = ossl_quic_txfc_get_swm(stream_txfc);
fc_limit = fc_swm + fc_credit;
QUIC_STREAM *next_stream,
int *have_ack_eliciting,
int *packet_full,
- uint64_t *new_credit_consumed)
+ uint64_t *new_credit_consumed,
+ uint64_t conn_consumed)
{
int rc = 0;
struct chunk_info chunks[2] = {0};
* determining when we can use an implicit length in a STREAM frame.
*/
for (i = 0; i < 2; ++i) {
- if (!txp_plan_stream_chunk(txp, h, sstream, stream_txfc, i, &chunks[i]))
+ if (!txp_plan_stream_chunk(txp, h, sstream, stream_txfc, i, &chunks[i],
+ conn_consumed))
goto err;
if (i == 0 && !chunks[i].valid) {
if (i > 0)
/* Load next chunk for lookahead. */
if (!txp_plan_stream_chunk(txp, h, sstream, stream_txfc, i + 1,
- &chunks[(i + 1) % 2]))
+ &chunks[(i + 1) % 2], conn_consumed))
goto err;
/*
uint64_t cwm;
QUIC_STREAM *stream, *snext;
struct tx_helper *h = &pkt->h;
+ uint64_t conn_consumed = 0;
for (ossl_quic_stream_iter_init(&it, txp->args.qsm, 1);
it.stream != NULL;) {
snext,
have_ack_eliciting,
&packet_full,
- &stream->txp_txfc_new_credit_consumed)) {
+ &stream->txp_txfc_new_credit_consumed,
+ conn_consumed)) {
/* Fatal error (allocation, etc.) */
txp_enlink_tmp(tmp_head, stream);
return 0;
}
+ conn_consumed += stream->txp_txfc_new_credit_consumed;
if (packet_full) {
txp_enlink_tmp(tmp_head, stream);
if (!TEST_uint64_t_eq(ossl_quic_txfc_get_cwm(txfc), 2000))
goto err;
- if (!TEST_uint64_t_eq(ossl_quic_txfc_get_credit_local(txfc), 2000))
+ if (!TEST_uint64_t_eq(ossl_quic_txfc_get_credit_local(txfc, 0), 2000))
goto err;
- if (is_stream && !TEST_uint64_t_eq(ossl_quic_txfc_get_credit(txfc),
+ if (is_stream && !TEST_uint64_t_eq(ossl_quic_txfc_get_credit(txfc, 0),
2000))
goto err;
if (!TEST_true(ossl_quic_txfc_consume_credit(txfc, 500)))
goto err;
- if (!TEST_uint64_t_eq(ossl_quic_txfc_get_credit_local(txfc), 1500))
+ if (!TEST_uint64_t_eq(ossl_quic_txfc_get_credit_local(txfc, 0), 1500))
goto err;
- if (is_stream && !TEST_uint64_t_eq(ossl_quic_txfc_get_credit(txfc),
+ if (is_stream && !TEST_uint64_t_eq(ossl_quic_txfc_get_credit(txfc, 0),
1500))
goto err;
if (!TEST_uint64_t_eq(ossl_quic_txfc_get_swm(txfc), 600))
goto err;
- if (!TEST_uint64_t_eq(ossl_quic_txfc_get_credit_local(txfc), 1400))
+ if (!TEST_uint64_t_eq(ossl_quic_txfc_get_credit_local(txfc, 0), 1400))
goto err;
- if (is_stream && !TEST_uint64_t_eq(ossl_quic_txfc_get_credit(txfc),
+ if (is_stream && !TEST_uint64_t_eq(ossl_quic_txfc_get_credit(txfc, 0),
1400))
goto err;
if (!TEST_true(ossl_quic_txfc_consume_credit(txfc, 1400)))
goto err;
- if (!TEST_uint64_t_eq(ossl_quic_txfc_get_credit_local(txfc), 0))
+ if (!TEST_uint64_t_eq(ossl_quic_txfc_get_credit_local(txfc, 0), 0))
goto err;
- if (is_stream && !TEST_uint64_t_eq(ossl_quic_txfc_get_credit(txfc),
+ if (is_stream && !TEST_uint64_t_eq(ossl_quic_txfc_get_credit(txfc, 0),
0))
goto err;
if (!TEST_uint64_t_eq(ossl_quic_txfc_get_swm(txfc), 2000))
goto err;
- if (!TEST_uint64_t_eq(ossl_quic_txfc_get_credit_local(txfc), 500))
+ if (!TEST_uint64_t_eq(ossl_quic_txfc_get_credit_local(txfc, 0), 500))
goto err;
if (is_stream)
if (!TEST_false(ossl_quic_txfc_has_become_blocked(txfc, 0)))
goto err;
- if (!TEST_uint64_t_eq(ossl_quic_txfc_get_credit(txfc), 1))
+ if (!TEST_uint64_t_eq(ossl_quic_txfc_get_credit(txfc, 0), 1))
goto err;
if (!TEST_true(ossl_quic_txfc_consume_credit(txfc, 1)))