struct eb_root bufs; /* receive buffers tree ordered by offset */
struct buffer app_buf; /* receive buffer used by stconn layer */
uint64_t msd; /* current max-stream-data limit to enforce */
- uint64_t msd_init; /* initial max-stream-data */
+ uint64_t msd_base; /* max-stream-data previous to latest update */
} rx;
struct {
struct quic_fctl fc; /* stream flow control applied on sending */
else if (quic_stream_is_remote(qcc, id)) {
qcs->rx.msd = qcc->lfctl.msd_uni_r;
}
- qcs->rx.msd_init = qcs->rx.msd;
+ qcs->rx.msd_base = 0;
qcs->wait_event.tasklet = NULL;
qcs->wait_event.events = 0;
struct qcc *qcc = qcs->qcc;
struct quic_frame *frm;
enum ncb_ret ret;
+ uint64_t diff, inc = 0;
TRACE_ENTER(QMUX_EV_QCS_RECV, qcc->conn, qcs);
if (qcs->flags & QC_SF_SIZE_KNOWN)
goto conn_fctl;
- if (qcs->rx.msd - qcs->rx.offset < qcs->rx.msd_init / 2) {
+ /* Check if a MAX_STREAM_DATA frame should be emitted, determined by
+ * the consumed capacity. If no more than 2 Rx buffers can be allocated
+ * per QCS, the limit is set to half the capacity. Else, the limit is
+ * set to match bufsize.
+ */
+ if (qcs->rx.msd - qcs->rx.msd_base < qmux_stream_rx_bufsz() * 2) {
+ if ((qcs->rx.offset - qcs->rx.msd_base) * 2 >= qcs->rx.msd - qcs->rx.msd_base)
+ inc = qcs->rx.offset - qcs->rx.msd_base;
+ }
+ else {
+ diff = qcs->rx.offset - qcs->rx.msd_base;
+ while (diff >= qmux_stream_rx_bufsz()) {
+ inc += qmux_stream_rx_bufsz();
+ diff -= qmux_stream_rx_bufsz();
+ }
+ }
+
+ if (inc) {
TRACE_DATA("increase stream credit via MAX_STREAM_DATA", QMUX_EV_QCS_RECV, qcc->conn, qcs);
frm = qc_frm_alloc(QUIC_FT_MAX_STREAM_DATA);
if (!frm) {
return;
}
- qcs->rx.msd = qcs->rx.offset + qcs->rx.msd_init;
+ qcs->rx.msd += inc;
+ qcs->rx.msd_base += inc;
frm->max_stream_data.id = qcs->id;
frm->max_stream_data.max_stream_data = qcs->rx.msd;