The previous logic assumed that a datagram must be available if the
future was notified, but this might not be the case if e.g. two
futures are concurrently waiting for datagrams, but only one datagram
has been received, since we use notify_waiters to wake all waiting
futures to be robust in the face of cancellation.
After a spurious wakeup, `Connection::open_uni` and `open_bi` would
switch to waiting for notifications about incoming streams, rather
than the intended notification about new stream ID flow control
budget. This was probably a copy-paste error from `poll_accept`.
When the application observes a stream finish or reset, we dispose of
its state via `StreamsState::stream_freed`, and queue a transmit of
stream flow control credit directly on the
`Connection`. `stream_freed` however also sets
`StreamsState::max_streams_dirty`, which is polled each time we
receive a packet to see whether a stream has become fully closed due
to an incoming frame. Together, these led to a MAX_STREAMS frame being
transmit both immediately, and following the next packet receipt. We
prevent that by unsetting the appropriate `max_streams_dirty` flags
when sending `MAX_STREAMS`.
Similar to existing logic handling finishing of a stopped stream in
StreamsState::received. The missing credit would be issued if a stream
is later closed through a different code path, but there is no
guarantee that would happen.
Reduces indirection and allows us to avoid cloning an `Arc` each time
one of the relevant events is waited on, and opens the door to
handwritten futures built on them.
Application datagrams may be too large to fit into a packet with ACKs
present. Therefore, if we have unsent ACKs, doing so may push a queued
application datagram into the next packet. If no other data is queued,
the first packet will then be ACK-only. Sending an ACK-only packet
without having received an ACK-eliciting packet following our last
ACK-only packet is illegal, and will trigger a debug assert.
By being slightly less enthusiastic about sending ACKs, we ensure that
any inadvertently generated ACK-only packet is legal and simplify our
logic slightly. This approach also seems to be popular with other
implementations, as indicated by ad-hoc feedback on the slack.
This has come up several times, most recently in
https://github.com/quinn-rs/quinn/issues/1395. While equivalent
behavior is already possible by waiting for e.g. `IncomingUniStreams`
to yield `Err` or `None`, this is substantially more discoverable.