Files
amethyst/quic
Claude b25644bf8b fix(quic): stabilization pass — concurrency, RFC compliance, DoS hardening
Verified and applied 12 focused fixes from a four-agent review of the
quic module. Each fix verified against the actual code; agent
findings that traced to false positives (pendingPing clear-without-emit,
sentPackets on encrypt failure) are documented in the review thread
but not changed.

Concurrency / flakiness:
- PTO consecutive count: double-increment removed; now incremented
  exactly once per PTO event in handlePtoFired before requeue, so the
  threshold check inside requeueInflightForProbe sees the post-
  increment value AND the between-probe re-requeue doesn't bump again.
- Wallclock → monotonic: QuicConnection.nowMillis defaults to
  TimeSource.Monotonic anchored at construction, so NTP step /
  suspend-resume can't poison RTT samples. Driver uses
  connection.nowMillis instead of carrying its own clock.
- Close-state race: atomic CAS via closeStateMonitor in close() and
  markClosedExternally so concurrent teardown paths can't both fire
  qlog "connection closed" and stomp on closeReason.
- streamsList CME: converted to @Volatile var List<QuicStream> with
  immutable-snapshot publishing under streamsLock. closeAllSignals'
  iteration is now CME-free without holding the (suspending) lock.
- JcaAesGcmAead: synchronized seal/open; multi-entry recent-nonce
  history (was single most-recent — could mask a duplicate against
  the second-most-recent under intermediate seals); on seal failure
  evict the cached nonce so a retry with the same nonce takes the
  safe fresh-Cipher path.

Wire correctness / spec:
- Connection-level send credit no longer debited on retransmits
  (added Chunk.isRetransmit; writer skips sendConnectionFlowConsumed
  += data.size when set). Pre-fix a few PTO rounds on a long stream
  exhausted credit and stalled the connection.
- ACK-delay shl overflow: clamp ackDelayExponent to 0..20 and
  clamp the peer's varint to (Long.MAX_VALUE >>> exponent) before
  shift; clamp negative now-vs-recv-time before shift on outbound
  AckTracker.
- Key-update commit only when new-phase packet PN exceeds
  largestReceived (RFC 9001 §6.1).
- RESET_STREAM final-size validation: enforce equality with prior
  FIN size and ≥ highestObservedOffset; close FINAL_SIZE_ERROR
  otherwise.
- STOP_SENDING handling: respond with RESET_STREAM on the local
  send side (was silently dropped, peer's flow-credit wasted).
- ReceiveBuffer.insert: typed InsertResult; second FIN with
  conflicting size and offset-past-FIN data both surface
  FINAL_SIZE_ERROR via the parser instead of being silently dropped.
- Retry SCID==DCID self-loop: reject Retry where the peer's SCID
  equals our original DCID (RFC 9000 §17.2.5.2).

DoS hardening:
- ACK PN walk: drainAckedSentPackets rewritten to scan in-flight
  keys against parsed ranges instead of walking every PN. A peer
  with firstAckRange = 2^62-1 used to pin a core forever; now
  bounded by the sent-packets map size.
- UDP socket: channel.connect(remote) after bind so the kernel
  filters off-path datagrams. Stops trivial source spoofing from
  burning AEAD attempts.

https://claude.ai/code/session_01AhGvbMV8uPRse3TmAGaddM
2026-05-08 22:56:05 +00:00
..