Discard client Initial keys when Handshake write keys are installed#6047
Discard client Initial keys when Handshake write keys are installed#6047guhetier wants to merge 2 commits into
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #6047 +/- ##
==========================================
- Coverage 85.96% 85.71% -0.25%
==========================================
Files 60 60
Lines 18847 18850 +3
==========================================
- Hits 16202 16158 -44
- Misses 2645 2692 +47 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
This PR updates MsQuic’s client key lifecycle handling to align with RFC 9001 §4.9.1 by deferring the discard of Initial keys until after a Handshake packet has been sent, aiming to avoid mutating congestion-control state while QuicSendFlush’s packet builder is mid-loop.
Changes:
- Adds a
HandshakePacketSentbit toQUIC_PACKET_BUILDERto record that a Handshake-level packet was finalized/committed for sending. - Sets
HandshakePacketSentduringQuicPacketBuilderFinalizewhen finalizing a Handshake-level packet. - Moves the client Initial-key discard from
QuicPacketBuilderPrepareto the end ofQuicSendFlush(afterQuicPacketBuilderCleanup).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/core/send.c | Defers client Initial key discard to the end of QuicSendFlush based on a builder “Handshake packet happened” bit. |
| src/core/packet_builder.h | Adds HandshakePacketSent to QUIC_PACKET_BUILDER. |
| src/core/packet_builder.c | Removes inline Initial-key discard from Prepare; sets HandshakePacketSent from Finalize. |
|
This looked familiar - it seems to be churning code very similar to #5994. I admit I haven't looked through the logic particularly closely yet, but what can we do to make sure the test gap is reliably closed? |
It is, the first case addressed one corner case but left a second corner. Actually, sending this back to draft, I realized I am not addressing one path correctly yet. |
227061d to
a8aad04
Compare
When a client discards Initial keys mid-flush (per RFC 9001 s4.9.1), the implicit ACK of Initial bytes frees congestion control capacity. However, Builder.SendAllowance was snapshot'd at the start of the flush and is now stale. Without re-flushing, Handshake CRYPTO frames may not be sent because the loop thinks it is CC-blocked. Add an InitialKeysDiscarded flag to the packet builder, set only when QuicCryptoDiscardKeys actually discards (returns TRUE). When set, treat the flush result as QUIC_SEND_INCOMPLETE so the operation is re-queued and the next flush recomputes SendAllowance with the freed capacity. Fixes #5998. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
a8aad04 to
c14a600
Compare
Description
Fixes #5998.
After a previous fix moving the initial key discard to the packet builder (instead of discarding them only when sending a crypto frame), it was still possible for handshake packets to be blocked by CC because:
This is fixed by scheduling a new send flush if there still are things to send after discarding the keys.
Testing
Covered by
Handshake/WithHandshakeArgs4.RandomLoss*. Locally validated:Handshake/WithHandshakeArgs4.RandomLoss/*variants pass over 100 iterations on a local devicespinquic both -timeout:20000 -repeat_count:1exits cleanly.Documentation
No documentation impact.