Repository navigation
WebRTC: a native build gives up a browser's lost SCTP chunks itself - #351
Closed
FractumSeraph wants to merge 1 commit into
Closed
FractumSeraph wants to merge 1 commit into
FractumSeraph wants to merge 1 commit into
Conversation
The lossy run of webrtc_native.mjs failed about one time in ten (the channel open, the echoes stopped). Tracing the native end's SCTP showed two causes, both in how the browsers' SCTP (dcsctp, Chromium's and Firefox 146's) gives up lost chunks with FORWARD-TSN: - The native end's SACK reported only 16 gaps. Chunks received past the 16th were never acknowledged, so the browser counted nothing newly acknowledged, never counted the lost chunks missing and never gave them up. A SACK now reports as many gaps as a packet carries. - In 30 runs of each browser, every run that lost the association's first DATA chunk failed, and no other did. dcsctp sends a FORWARD-TSN at most once per smoothed round trip (200 ms when that is longer), each passing only the first gap, and measures the round trip only from SACKs without gaps; with the first chunk lost it keeps its first guess (500 ms), so it gives up a gap every 200 ms, fewer than 10% loss opens, and Chromium falls behind until the native end's TSN window is full. Firefox's dcsctp before 158 has no clock (DataChannelDcSctp leaves TimeMillis returning 0, Mozilla's bug 2077997), so the 200 ms after its first FORWARD-TSN never pass: it sends no other for the rest of the connection. So the native end no longer waits on the browser: a gap a later chunk came past 200 ms ago (RFC 3758's limit on delaying a FORWARD-TSN, under dcsctp's 400 ms minimum retransmission timeout) is given up as if a FORWARD-TSN had come. The channel's messages are never retransmitted, so such a chunk is lost either way; the SACKs stay valid for any SCTP (only TSNs below one received are acknowledged). The log says once per connection, with the SCTP state, when a gap is given up here or the browser acknowledges nothing. Nothing the machines send each other changes: no network version. Checked in Docker (node:24-bookworm, Playwright 1.58: Chromium and Firefox 146.0.1) with webrtc_native.mjs's lossy run looped: before, 4 of 32, 3 of 25 and 3 of 30 Firefox runs and 2 of 12 Chromium runs failed (2 of 30 with the SACK fix alone); after, none of 250 (100 and 25 each browser, 15 more Firefox), at least 677 of 960 messages back; the full test passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 5ace29a)
Collaborator
|
A commit already in testing (1b61b52) fixed the same problem, and the PR conflicts with it. |
FractumSeraph
pushed a commit
to FractumSeraph/OpenCE
that referenced
this pull request
Oct 20, 2026
…rm-keys-psp-vita-uwp Delta platforms: PSP, Vita and the Xbox One/Series in developer mode
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.
The problem
The CI step "Test in Chromium and Firefox" (
node port/web/tests/webrtc_native.mjs chromium firefox, web job) fails now and then in its lossy run, the one with a tenth of the datagrams lost each way. The lossless runs always pass. In a failing run the data channel stays open, but the echoes stop early, for example:It isn't only a test problem: the native end of a real browser connection (
port/linux/src/p2p_webrtc.c) stops in the same way on a path that loses packets, and the player's connection then times out.On OpenCE main (b1ef7f7), in Docker (node:24-bookworm, Playwright 1.58: Chromium and Firefox 146.0.1), looping the lossy run 30 times per browser, 8 of the 60 runs failed (4 Chromium, 4 Firefox), with 49 to 241 of 960 messages back.
Why
I traced the native end's SCTP and the datagrams the test drops. Both browsers use dcsctp, WebRTC's SCTP (Firefox 146 does too), and both stop giving up their lost chunks (FORWARD-TSN, RFC 3758), so the native end's cumulative TSN stops at the first lost chunk. Two causes:
MAXIMUM_GAP_BLOCKS). Chunks received past the 16th gap were never acknowledged. dcsctp counts a chunk missing only when a SACK newly acknowledges something after it, so it stopped counting the lost chunks missing, never gave them up, and fell back to its retransmission timer. A SACK now reports as many gaps as a packet carries.DcSctpSocketCallbacks::TimeMillis()keeps its default, which returns 0. dcsctp's time therefore never moves, and the 200 ms it waits after its first FORWARD-TSN never pass, so it sends no other for the rest of the connection. Mozilla fixed that on 2026-10-06 (bug 2077997, "Give dcsctp a real clock"), in Firefox 158; the current release, 157, still has it.The fix
The native end no longer depends on the browser's FORWARD-TSN. If a gap in what the browser sent is still open 200 ms after a later chunk arrived, the native end gives it up itself, exactly as if a FORWARD-TSN had come (
sctp_skip, sharinggive_up_towith the FORWARD-TSN handler).The log says once per connection, with the SCTP state, when the native end gives up a gap for the browser or when the browser acknowledges nothing. That should make the next such problem quicker to find.
Nothing the machines send each other changes, so there is no network version change. The README ("Browsers"), NETCODE.md (Transport) and the test's comment describe it.
Checked
Same Docker setup:
webrtc_native.mjs chromium firefoxpasses.not open: ICE connected, connectedmostly, a few ICE failures).p2p_webrtc.ccompiles as C89 (gnu89,-Wall -Wextra -Wdeclaration-after-statement) without new warnings.The commit is cherry-picked from FractumSeraph/OpenCE (5ace29a), with one sentence of its message corrected.
🤖 Generated with Claude Code