Repository navigation
feat(net): MoQ Active Count for IETF namespace subscriptions #4268
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
e7b3443
quest: claim ietf-announce-count
kixelated 13e1550
feat(net): count an IETF namespace subscription's initial set
kixelated 5f951f0
refactor(net): rename the extension to MoQ Active Count
kixelated a76b4b7
Merge remote-tracking branch 'origin/dev' into quest/m1/ietf-announce…
kixelated a1f6623
Merge remote-tracking branch 'origin/dev' into quest/m1/ietf-announce…
kixelated 1f3222b
fix(net): frame Active Count on NAMESPACE messages and refuse it else…
kixelated 96c0602
fix(net): define Active Count's caught up from the subscriber's side
kixelated 67f111e
Merge remote-tracking branch 'origin/dev' into pr-4268
kixelated 6b08c19
fix(net): close the session on a misplaced ACTIVE_COUNT
kixelated File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| --- | ||
| title: "MoQ Active Count Extension" | ||
| abbrev: "moq-active-count" | ||
| category: info | ||
|
|
||
| docname: draft-lcurley-moq-active-count-latest | ||
| submissiontype: IETF # also: "independent", "editorial", "IAB", or "IRTF" | ||
| number: | ||
| date: | ||
| v: 3 | ||
| area: wit | ||
| workgroup: moq | ||
|
|
||
| author: | ||
| - | ||
| fullname: Luke Curley | ||
| email: kixelated@gmail.com | ||
|
|
||
| normative: | ||
| moqt: I-D.ietf-moq-transport | ||
|
|
||
| informative: | ||
|
|
||
| --- abstract | ||
|
|
||
| This document defines an extension for MoQ Transport {{moqt}} that tells a subscriber how many NAMESPACE messages answering its SUBSCRIBE_NAMESPACE come before the first change. | ||
| The subscriber then knows when it has caught up, instead of guessing from a quiet stream. | ||
|
|
||
| --- note_Note_to_Readers | ||
|
|
||
| This document was generated by an AI model from the implementation at [github.com/moq-dev/moq](https://github.com/moq-dev/moq) and is maintained alongside it. | ||
| Submit an [issue](https://github.com/moq-dev/moq/issues) or [PR](https://github.com/moq-dev/moq/pulls) if this spec sucks and you want to fix anything. | ||
|
|
||
| --- middle | ||
|
|
||
| # Conventions and Definitions | ||
| {::boilerplate bcp14-tagged} | ||
|
|
||
| A suffix is **active** on a SUBSCRIBE_NAMESPACE stream from a NAMESPACE message carrying it until a NAMESPACE_DONE message carrying it. | ||
| A subscriber is **caught up** on a SUBSCRIBE_NAMESPACE once it has read Count ({{count}}) NAMESPACE messages after REQUEST_OK, immediately on a Count of 0. | ||
|
|
||
|
|
||
| # Introduction | ||
| A publisher answers SUBSCRIBE_NAMESPACE with a NAMESPACE message for each suffix it already advertises under the subscription's prefix, then keeps the stream open to report changes. | ||
| Nothing on the wire separates the two, so a subscriber cannot tell "there are no broadcasts" from "they have not arrived yet". | ||
| The best it can do is wait for the stream to go quiet, which is slow when there is nothing to send and wrong when the network stalls partway. | ||
|
|
||
| This extension has the publisher put on its REQUEST_OK how many NAMESPACE messages come before the first change. | ||
|
|
||
|
|
||
| # Setup Negotiation | ||
|
|
||
| An endpoint declares this extension with the following Setup Option ({{moqt}} Section 10.3): | ||
|
|
||
| ~~~ | ||
| ACTIVE_COUNT Setup Option { | ||
| Option Key (vi64) = 0x40B64 | ||
| Option Value (vi64) = 1 | ||
| } | ||
| ~~~ | ||
|
|
||
| A receiver MUST ignore the value. | ||
| The extension is negotiated when both endpoints declare the option, and applies to every SUBSCRIBE_NAMESPACE on the session in both directions. | ||
| An endpoint MUST NOT declare the option on a version of {{moqt}} without the NAMESPACE message. | ||
|
|
||
|
|
||
| # Counting {#count} | ||
|
|
||
| When the extension is negotiated, a publisher MUST include the following parameter in the REQUEST_OK answering a SUBSCRIBE_NAMESPACE: | ||
|
|
||
| ~~~ | ||
| ACTIVE_COUNT Parameter { | ||
| Type (vi64) = 0x40B66 | ||
| Value (vi64) = Count | ||
| } | ||
| ~~~ | ||
|
|
||
| The publisher MUST send exactly Count NAMESPACE messages immediately after REQUEST_OK, before any other message on the stream, making active each suffix it advertises to the subscriber when it answers, one message per suffix; later changes follow as usual. | ||
| A suffix the publisher does not advertise to this subscriber, such as one whose path loops back through it, is neither sent nor counted. | ||
|
|
||
| A subscriber counts every NAMESPACE message toward Count, including any it discards on receipt. | ||
|
|
||
| A subscriber MUST close the session with a PROTOCOL_VIOLATION if the REQUEST_OK answering a SUBSCRIBE_NAMESPACE omits the parameter when the extension is negotiated, or carries it when it is not. | ||
| An endpoint MUST close the session with a PROTOCOL_VIOLATION if a REQUEST_OK answering any other request carries the parameter. | ||
|
|
||
|
|
||
| # Security Considerations | ||
|
|
||
| The count reveals no more than the NAMESPACE messages that follow it. | ||
| A publisher that promises more than it sends can only delay the subscriber's notion of having caught up, which it could equally do by withholding NAMESPACE messages. | ||
|
|
||
|
|
||
| # IANA Considerations | ||
|
|
||
| This document requests the following registrations. | ||
| High, distinctive values are requested to avoid the low ranges reserved by {{moqt}} and to minimize collisions with provisional registrations by other extensions. | ||
|
|
||
| ## MOQT Setup Options | ||
|
|
||
| This document requests one registration in the "MOQT Setup Options" registry ({{moqt}} Section 15.4), whose policy is Specification Required. | ||
|
|
||
| | Value | Name | Reference | | ||
| |:--------|:----------------|:--------------| | ||
| | 0x40B64 | ACTIVE_COUNT | This Document | | ||
|
|
||
| ## MOQT Message Parameters | ||
|
|
||
| This document requests one registration in the "MOQT Message Parameters" registry ({{moqt}} Section 15.7). | ||
|
|
||
| | Value | Name | Carried In | Reference | | ||
| |:--------|:----------------|:-----------|:--------------| | ||
| | 0x40B66 | ACTIVE_COUNT | REQUEST_OK | This Document | | ||
|
|
||
| Both values are even, so each is a bare varint. | ||
|
|
||
|
|
||
| --- back | ||
|
|
||
| # Acknowledgments | ||
| {:numbered="false"} | ||
|
|
||
| This document was drafted with the assistance of Claude, an AI assistant by Anthropic. |
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
This file was deleted.
Oops, something went wrong.
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| # [S] @moq/net counts an IETF namespace subscription until it is caught up | ||
|
|
||
| ## Goal | ||
|
|
||
| `@moq/net` speaks the MoQ Active Count extension | ||
| (`drafts/draft-lcurley-moq-active-count.md`) on draft-16+, as `rs/moq-net` | ||
| does: it declares the ACTIVE_COUNT option, its publisher puts on the REQUEST_OK | ||
| answering SUBSCRIBE_NAMESPACE how many NAMESPACE messages come before the | ||
| subscription is caught up, and its subscriber lands that stream's source on | ||
| the count instead of the quiet timer. | ||
|
|
||
| ## Plan | ||
|
|
||
| - Mirror `rs/moq-net/src/ietf/active_count.rs` in `js/net/src/ietf/`, like | ||
| `hidden.ts`: declare on draft-16+ only, and read the peer's declaration. | ||
| - Publisher: count what it advertises before writing REQUEST_OK, then send | ||
| exactly those NAMESPACE messages first. | ||
| - Subscriber: a missing count when negotiated, one when not, or one on any | ||
| other REQUEST_OK is a protocol violation, as in Rust. | ||
| - Extend the IETF cases of the JS caught-up tests to show the counted versions | ||
| land without waiting out the quiet gap. | ||
|
|
||
| Public API: none. Wire: the extension, already specified. | ||
|
|
||
| ## Required | ||
|
|
||
| - [JS caught up](/quest/m1/js-announce-caught-up.md) - the per-source guard the count lands |
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| //! The MoQ Active Count extension (draft-lcurley-moq-active-count-00). | ||
| //! | ||
| //! A publisher answers SUBSCRIBE_NAMESPACE with a NAMESPACE for every suffix it already | ||
| //! advertises, then reports changes on the same stream. Nothing in moq-transport says | ||
| //! where the first part ends, so a subscriber can only guess from the stream going | ||
| //! quiet. When both endpoints declare the ACTIVE_COUNT option, the publisher puts on its | ||
| //! REQUEST_OK how many NAMESPACE messages come before the subscription is caught up. | ||
|
|
||
| use super::Version; | ||
|
|
||
| /// ACTIVE_COUNT Setup Option: the sender counts the NAMESPACE messages before a | ||
| /// subscription is caught up, and reads the peer's count. Even, so the value is a bare varint. | ||
| pub const ACTIVE_COUNT: u64 = 0x40B64; | ||
|
|
||
| /// ACTIVE_COUNT REQUEST_OK parameter: how many NAMESPACE messages immediately follow | ||
| /// before the subscription is caught up. Only answers SUBSCRIBE_NAMESPACE. | ||
| /// Even, so the value is a bare varint. | ||
| pub const ACTIVE_COUNT_PARAM: u64 = 0x40B66; | ||
|
|
||
| /// Whether this version answers SUBSCRIBE_NAMESPACE with NAMESPACE messages. Draft-14/15 | ||
| /// answer with PUBLISH_NAMESPACE requests instead, which the stream cannot count. | ||
| fn supported(version: Version) -> bool { | ||
| !matches!(version, Version::Draft14 | Version::Draft15) | ||
| } | ||
|
|
||
| /// Whether the peer declared the option. We always declare it, so this alone decides | ||
| /// whether the extension is negotiated. | ||
| pub fn from_setup(params: &super::Parameters, version: Version) -> bool { | ||
| supported(version) && params.get_varint(super::ParameterVarInt::ActiveCount).is_some() | ||
| } | ||
|
|
||
| /// Declare that we count and read the peer's count. | ||
| pub fn into_setup(params: &mut super::Parameters, version: Version) { | ||
| if supported(version) { | ||
| params.set_varint(super::ParameterVarInt::ActiveCount, 1); | ||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
|
|
||
| #[test] | ||
| fn only_versions_with_namespace_negotiate() { | ||
| for version in [Version::Draft14, Version::Draft15, Version::Draft16, Version::Draft22] { | ||
| let mut params = super::super::Parameters::default(); | ||
| assert!(!from_setup(¶ms, version)); | ||
| into_setup(&mut params, version); | ||
| assert_eq!(from_setup(¶ms, version), supported(version), "{version:?}"); | ||
| } | ||
| } | ||
| } |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,7 @@ | |
|
|
||
| #[macro_use] | ||
| mod parameters; | ||
| pub mod active_count; | ||
| mod adapter; | ||
| pub mod cluster; | ||
| mod control; | ||
|
|
||
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
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
Oops, something went wrong.
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When a Rust endpoint connects to
@moq/net, this declaration cannot become bilateral because the TypeScript setup andREQUEST_OKhandling remain unchanged, so Rust-JS sessions still use the quiet-timer path instead of Active Count. The newly addedquest/m1/js-active-count.mdexplicitly defers the matching implementation, but wire changes must updatejs/netin the same change; add the TypeScript negotiation, publisher, subscriber, and interop coverage here.AGENTS.md reference: rs/moq-net/AGENTS.md:L5-L5
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deferring on purpose. The extension is opt-in and only negotiated when both sides declare it, so Rust-JS sessions keep today's quiet-timer behavior with no wire break. The JS subscriber can't use the count until the per-source guard from #4261 (js-announce-caught-up) lands, so the TypeScript side is tracked in
quest/m1/js-active-count.mdrather than half-implemented here.(Written by Claude Opus 5.5)