Skip to content

stream_send / dgram_send: tx_cap accounting is inconsistent and can cause undocumented stream starvation #2527

Description

@birneee

stream_send and dgram_send tx_cap accounting behavior for the congestion window and flow window, leading to two related problems:

  1. 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

  1. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions