stream_send and dgram_send tx_cap accounting behavior for the congestion window and flow window, leading to two related problems:
- Stream-send call order determines who gets capacity (starvation)
stream_send decrements tx_cap immediately when data is buffered (tx_cap = min(cwnd_available, max_tx_data - tx_data)). This means the order in which the application calls stream_send across streams determines which one gets the connection's send budget — not respecting the streams' declared priority. Calling stream_send on a low-priority stream first can exhaust tx_cap entirely, causing a subsequent stream_send on a high-priority stream to return Error::Done. Stream priority only controls wire scheduling of already-buffered data, not buffering admission.
Example: birneee@da27e93
dgram_send does not decrement tx_cap
dgram_send pushes datagrams to a queue without touching tx_cap. As a result, the same congestion window that blocks a second stream_send places no equivalent restriction on dgram_send. It is possible to simultaneously buffer more data than the congestion window allows:
The tx_cap used by stream_send does not reflect already-queued datagrams. The restriction only catches up on the next recv() cycle after send() puts the datagrams on the wire.
Proposal
At minimum, the following functions should document their behavior in the function docs:
stream_send
stream_send_zc
dgram_send
dgram_send_buf
Applications relying on stream priority, operating near the congestion window limit, or assuming that all buffered data can be sent within one round-trip need to understand this behavior to avoid starving high-priority streams or buffering more data than the congestion window allows.
stream_sendanddgram_sendtx_capaccounting behavior for the congestion window and flow window, leading to two related problems:stream_send decrements
tx_capimmediately when data is buffered (tx_cap = min(cwnd_available, max_tx_data - tx_data)). This means the order in which the application calls stream_send across streams determines which one gets the connection's send budget — not respecting the streams' declared priority. Calling stream_send on a low-priority stream first can exhausttx_capentirely, causing a subsequentstream_sendon a high-priority stream to returnError::Done. Stream priority only controls wire scheduling of already-buffered data, not buffering admission.Example: birneee@da27e93
dgram_senddoes not decrementtx_capdgram_sendpushes datagrams to a queue without touchingtx_cap. As a result, the same congestion window that blocks a secondstream_sendplaces no equivalent restriction ondgram_send. It is possible to simultaneously buffer more data than the congestion window allows:The
tx_capused bystream_senddoes not reflect already-queued datagrams. The restriction only catches up on the nextrecv()cycle aftersend()puts the datagrams on the wire.Proposal
At minimum, the following functions should document their behavior in the function docs:
stream_sendstream_send_zcdgram_senddgram_send_bufApplications relying on stream priority, operating near the congestion window limit, or assuming that all buffered data can be sent within one round-trip need to understand this behavior to avoid starving high-priority streams or buffering more data than the congestion window allows.