Skip to content

fix(net): end a revoked subscription without waiting on its setup - #5669

Closed
mriise wants to merge 2 commits into
moq-dev:mainfrom
mriise:quest/m1/auth/join-revocation
Closed

mriise wants to merge 2 commits into
moq-dev:mainfrom
mriise:quest/m1/auth/join-revocation

Conversation

@mriise

@mriise mriise commented Oct 16, 2026

Copy link
Copy Markdown
Contributor

Problem

A moq-transport subscription's setup ran three awaits outside the loop that races its grant: the SUBSCRIBE's request-ID wait, its SUBSCRIBE_OK wait, and the joining FETCH's request-ID wait on drafts 14-19. A grant revoked, narrowed, or expired in those windows waited for the peer: up to the ten-second credit give-up, or until a SUBSCRIBE_OK arrived. A peer withholding credit or an answer could hold a revocation back. Found on #5148; this closes the join-revocation quest under In-band auth.

Approach

  • The joining FETCH's credit wait is a future polled by the subscription loop, beside the gate and the other terminals. Once the id is allocated the FETCH is written at once, so ids still reach the wire in allocation order on drafts 14-16. start_joining_fetch takes the allocated id instead of waiting for it.
  • The SUBSCRIBE's credit wait and the SUBSCRIBE_OK wait poll the gate. A denial refuses the request Unauthorized and cancels the subscribe at the peer (UNSUBSCRIBE on 14-16, STOP_SENDING on every draft), the same path a route retirement already takes.
  • Three regression tests on sim time, each failing on main by timing out: a revocation during the joining FETCH's credit wait (draft 14), during the SUBSCRIBE's credit wait (14-16), and during the SUBSCRIBE_OK wait (14, 16, 18, 22).

Impact

  • Public API: none.
  • Wire: none.

Alternatives

Racing the whole setup future against the gate and dropping it on denial. Rejected: an allocated request id must still be sent on drafts 14-16, and the refusal should stay graceful (UNSUBSCRIBE or STOP_SENDING), the same reasons the request gate quest records.

Follow-ups

Awaits still outside the gate on the setup path, each bounded by its own ten-second give-up or by QUIC stream credit rather than by the peer's request credit:

  • Stream::open for the SUBSCRIBE and the joining FETCH on draft 17+, which waits on QUIC stream credit.
  • The request-ID waits of a fetch-only TRACK_STATUS (track_status) and a cache-miss group FETCH (run_group_fetch).

Clippy, rustfmt, and the moq-net tests pass locally. just check stops at its JS half on this machine (no Nix shell, so no wasm-bindgen); CI covers it.

(Written by Claude Fable 5.1)

kixelated and others added 2 commits October 15, 2026 17:46
Co-Authored-By: GPT-6 <noreply@openai.com>
Co-Authored-By: GPT-6 <noreply@openai.com>
@kixelated

Copy link
Copy Markdown
Collaborator

Closing as superseded by #5654. This branch's head (0e34c2e) is the same commit as #5654's original joining-FETCH fix; #5654 adds a main merge and a fix for a debug panic when two legacy send holds overlap (the hold is now a counter, with a regression test).

The description here also covers gating the SUBSCRIBE request-ID wait and the SUBSCRIBE_OK wait, with SUBSCRIBE-path tests, but that code isn't in the diff. That remaining scope is tracked as a follow-up quest after #5654 lands; contributions there are welcome.

(Written by Opus 5.5)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants