Fix two of the close-flush data-loss bugs (#116 ported to main) - #139
Merged
Conversation
Issue #125's close-flush data loss is fully diagnosed: the libwebrtc reference peer is blameless. Its immediate close-after-send (spec-legal; libwebrtc flushes before the SCTP reset per RFC 8831 section 6.7) coalesces the tail DATA and the reset RECONFIG into one burst, and three distinct receiver-side bugs mishandled it. This fixes two: 1. rtc-sctp discarded received-but-undelivered messages on an incoming stream reset (reference-x-wasmtime, `answerer: receive: closed`): reset_streams_if_any -> unregister_stream dropped the stream's reassembly queue with reassembled-but-unread messages inside, before the driver polled the pending Readable events. Fixed by lann/rtc#1 (rebased onto upstream master, rev 89f518ea). 2. The reference peer's wait_open rejected an already-closing incoming channel (wasmtime-x-reference, `answerer: channel closed before open`): a remote-announced channel that reads closing/closed was necessarily open first and its messages are already queued — open->send->close can land inside one 25 ms poll interval. Remote channels now count that state as opened; locally created channels still fail. Bug 3 (the webrtc driver delivers a data-channel close ahead of already- received messages) remains open as #117; the jco-node analog is #124. The rtc fix rides new git pins replacing the crates.io 0.20.0 versions: webrtc consumes rtc as an in-repo submodule path dependency, which no version requirement or [patch] can redirect, so both workspace deps resolve from one lann/webrtc branch (rev 15755c6b) whose only delta from upstream webrtc master is that submodule pointed at lann/rtc#1's rev. One source means the direct rtc dependency (wasip3-impl) and the wasmtime host's transitive rtc-sctp are the same package. This moves the stack from released 0.20.0 to master's 0.21.0 (unreleased, the crypto- provider migration); no code changes were needed. Reopens #120 (unwind the pins once releases including the fix ship). Also: recv_sequence (suite body) and the reference peer's close-flush receive loop report `(after N of M messages)` on failure, so partial delivery is distinguishable from a receive path that never yielded. Gates: just check, just test, examples::test-webrtc-composed, and the full conformance run (loopback + interop, 304 results, 0 failing, 1 expected-fail: #123, matrices unchanged) all pass. Flake check: 10 further interop pair-suite iterations each of reference-x-wasmtime and wasmtime-x-reference - 240 case results, 0 failures, channel-close-flush 20/20 (the shapes fixed here reproduced on roughly a third of runs before). Closes #125.
This was referenced Aug 6, 2026
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Port of #116 (opened against the pre-migration tree; superseded by this PR) onto main. #125 is now fully diagnosed: the libwebrtc reference peer is blameless. Its immediate close-after-send (spec-legal; libwebrtc flushes before the SCTP reset per RFC 8831 §6.7) coalesces the tail DATA and the reset RECONFIG into one burst, and three distinct receiver-side bugs mishandled it. This PR fixes two.
Fixed here
rtc-sctpdiscarded received-but-undelivered messages on an incoming stream reset (reference-x-wasmtime,answerer: receive: closed).reset_streams_if_any→unregister_streamdropped the stream's reassembly queue with reassembled-but-unread messages inside, before the driver polled the pendingReadableevents. Fixed by sctp: don't discard received-but-undelivered data on incoming stream reset lann/rtc#1, rebased onto upstream master (rev89f518ea).wait_openrejected an already-closing incoming channel (wasmtime-x-reference,answerer: channel closed before open). A remote-announced channel that readsclosing/closedwas necessarily open first and its messages are already queued; open→send→close can land inside one 25 ms poll interval. Remote channels now count that state as opened; locally created channels still fail.Also:
recv_sequencefailures (suite body + reference peer) now report(after N of M messages), which is what made the diagnosis tractable.Dependency shape (differs from #116)
#116 used
[patch.crates-io]; that is no longer viable and this PR uses pinned git dependencies instead:webrtcmaster consumesrtcas an in-repo submodule path dependency, which no version requirement or[patch]can redirect.So both workspace deps resolve from one
lann/webrtcbranch (rtc-sctp-reset-undelivered-data, rev15755c6b) whose only delta from upstreamwebrtcmaster is thertcsubmodule pointed at lann/rtc#1's rev. One source means the directrtcdependency (wasip3-impl) and the wasmtime host's transitivertc-sctpare the same package — a split-source attempt produced exactly the expected type-identity mismatch inrtc-ct-driver(itsrtc::values feedwebrtcAPIs). This moves the stack from released 0.20.0 to master's 0.21.0 (the crypto-provider migration); no code changes were needed. Reopens #120: unwind the pins once releases including the fix ship.Remaining (not fixed here)
webrtcdriver delivers a data-channel close ahead of already-received messages — webrtc 0.20 driver delivers data-channel close ahead of already-received messages (E18 bug 3) #117 (mechanism verified still present onwebrtcmaster: the driver delta since 0.20.0 is onlynon_exhaustivematch arms). It did not reproduce in 20 verification iterations, plausibly because the reference offerer's 20 ms send pacing (from Migrate the conformance suite onto the polymorph:test harness #135's mitigations) prevents the DATA+RECONFIG coalescing that triggers it.reference-x-jco-nodefailures with the same trigger are node-datachannel drops messages queued behind a remote close #124 (node-datachannel TSFN race).Verification
just check,just test(22/22, incl. the cli-signaling end-to-end),just examples::test-webrtc-composed— all green on the 0.21 stack.just conformance: 148 loopback + 156 interop results, 0 failing (1 expected-fail: rtc emits no SCTP stream reset on data-channel close #123), matrices unchanged.reference-x-wasmtimeandwasmtime-x-reference— 240 case results, 0 failures,channel-close-flush20/20. (The two shapes fixed here previously reproduced on ~1/3 of runs; Fix two of E18's three close-flush data-loss bugs #116's own loops still saw 4/20 bug-3 failures, absent here per the pacing note above.)Closes #125. Supersedes #116.