Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
95cb5d0
chore(quest): claim quest/m1/api-audit/transport-config.md
kixelated Oct 23, 2026
5368ca5
Consolidate native transport configuration
kixelated Oct 23, 2026
daf151b
Merge origin/main into quest/m1/api-audit/transport-config
kixelated Oct 23, 2026
8dfbedd
Split backoff into wait, cap, and healthy knobs
kixelated Oct 23, 2026
c6ca61f
Merge origin/main into quest/m1/api-audit/transport-config
kixelated Oct 23, 2026
db396d5
Format moq-quic test lint attribute
kixelated Oct 23, 2026
c58c5fc
Merge origin/main into quest/m1/api-audit/transport-config
kixelated Oct 24, 2026
d761218
Keep a disabled relay WebSocket SETUP timeout disabled
kixelated Oct 24, 2026
a5b4438
Adapt moq-tokio tests to main's qmux framing API
kixelated Oct 24, 2026
b931aa9
Give the bouncing-fleet reconnect tests their healthy bar
kixelated Oct 24, 2026
ab7065e
Merge origin/main into quest/m1/api-audit/transport-config
kixelated Oct 24, 2026
94ab6f2
Merge origin/main into quest/m1/api-audit/transport-config
kixelated Oct 24, 2026
3384e09
Use moq_net::time::Instant::now in the flap test
kixelated Oct 24, 2026
f268fe7
Merge origin/main into quest/m1/api-audit/transport-config
kixelated Oct 24, 2026
80ed7eb
Merge remote-tracking branch 'origin/main' into HEAD
kixelated Oct 24, 2026
30fef1c
fix(ffi): build the wasm accepted session without a driver handle
kixelated Oct 24, 2026
24b74bf
Merge remote-tracking branch 'origin/main' into HEAD
kixelated Oct 24, 2026
9ecc76e
Merge remote-tracking branch 'origin/main' into HEAD
kixelated Oct 24, 2026
76a846d
Merge remote-tracking branch 'origin/main' into HEAD
kixelated Oct 24, 2026
2a260c5
docs(tokio): keep flag help free of rustdoc links
kixelated Oct 24, 2026
d09917f
Merge remote-tracking branch 'origin/main' into rq-6529
kixelated Oct 24, 2026
f56de21
Merge remote-tracking branch 'origin/main' into HEAD
kixelated Oct 24, 2026
d4a6921
Merge remote-tracking branch 'origin/main' into HEAD
kixelated Oct 24, 2026
b87bb0d
Merge remote-tracking branch 'origin/main' into rq-6529
kixelated Oct 24, 2026
304a278
fix: adapt to main's session close cause and once removal
kixelated Oct 24, 2026
8b52369
Merge remote-tracking branch 'origin/main' into rq-6529
kixelated Oct 24, 2026
c16b55e
test: adapt main's auth tests to the consolidated config and session
kixelated Oct 24, 2026
c5593da
Merge remote-tracking branch 'origin/main' into rq-6529
kixelated Oct 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 0 additions & 21 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions bench/ffi-gen/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,14 @@ impl MoqClient {
/// A client that dials once, with no reconnect.
#[cfg_attr(feature = "uniffi", uniffi::constructor)]
pub fn new() -> Result<Self, MoqError> {
let mut connect = moq_tokio::connect::Config::default();
connect.once = Some(true);
let connect = moq_tokio::connect::Config::default();
let _guard = runtime().enter();
let client = connect
.init(moq_tokio::quic::Config::default())
.map_err(|err| MoqError::Net {
reason: err.to_string(),
})?;
Ok(Self { client })
Ok(Self { client: client.with_reconnect(false) })
}

/// Connect to `url`, publishing and consuming through `origin`. Takes `&self`, which
Expand Down
6 changes: 1 addition & 5 deletions deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,7 @@ allow = [
"Unlicense",
"Zlib",
]
exceptions = [
# AWS-LC's FIPS build still carries OpenSSL-licensed code. Reachable only
# through moq-quic's opt-in `aws-lc-rs-fips` feature, kept from quinn.
{ crate = "aws-lc-fips-sys", allow = ["OpenSSL"] },
]
exceptions = []

[bans]
multiple-versions = "warn"
Expand Down
2 changes: 1 addition & 1 deletion doc/bin/gstreamer.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,6 @@ preferred first; every stable version by default), `tls-disable-verify`,
Debug with `GST_DEBUG=*:4` for GStreamer and `RUST_LOG=debug` for the plugin.
To decrypt a capture, set `quic-keylog=true` on either element along with
`SSLKEYLOGFILE`; the variable alone writes nothing, and the flag without it fails
the start.
the start. Existing Unix log files must be private (mode 0600); files accessible to group or others are refused.

`moqsrc` creates source pads only for enabled renditions. Disabling a rendition stops its media and holds its pad idle without EOS; enabling it again resumes on the same pad.
2 changes: 1 addition & 1 deletion doc/bin/obs.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ supports them), and the WebSocket fallback race. A rejected value stops the
stream with the reason in the log rather than silently using a default.
To decrypt a packet capture, turn on **TLS key log** here or in a MoQ Source's
properties and start OBS with `SSLKEYLOGFILE` naming the file; the variable
alone writes nothing, and the toggle without it fails the connection.
alone writes nothing, and the toggle without it fails the connection. Existing Unix log files must be private (mode 0600); files accessible to group or others are refused.

The plugin is C++ over the [generated C++ bindings](/lib/cpp/) and ships with
every moq-cpp release. Stopping finishes the tracks and drains for up to one
Expand Down
18 changes: 11 additions & 7 deletions doc/bin/relay/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,16 @@ predecessor's QUIC connections, so clients reconnect at once instead of
waiting out the idle timeout. Keep it secret, and give it to one relay
only: any holder resets every other holder's connections, so live relays behind
one address would reset each other's clients unless the load balancer routes by
connection ID (`lb_id`, QUIC-LB). Relays on different addresses gain nothing from sharing
connection ID (`[listen.lb] id`, QUIC-LB). Relays on different addresses gain nothing from sharing
it, since a client accepts a reset only from its relay's address.
Create one with `openssl rand -hex 32 > reset.key`.

A setting no configured listener reads stops startup rather than being ignored.
A stream-only relay refuses `preferred_v4`, `preferred_v6`, `lb_id` (or `load_balancer`), and
A stream-only relay refuses `preferred_v4`, `preferred_v6`, `lb.id`, and
`reset.secret`, which only QUIC reads, and a `[listen.tls]` `cert`, `key`, or `generate` unless
`tcp.tls` serves it.
`lb_nonce` needs `lb_id`. `lb_id` and `lb_nonce` cannot be combined with `load_balancer`.
`[listen.lb] nonce` needs an `id` in the same table; unset nonce uses 8.
The `--listen-quic-lb-id` and `--listen-quic-lb-nonce` flags update that table.
`unix.allow` needs `unix.bind`.

## \[quic]
Expand All @@ -80,21 +81,24 @@ Transport tuning, applied to accepted and dialed connections alike.
congestion_control = "delay" # "delay" (BBR, the default), "loss" (CUBIC), or "none".
max_streams = 10000 # Concurrent streams per connection, bidi and uni; 0 is refused. Default.
idle_timeout = "10s" # Drop a connection after this long with nothing on it. Default.
keep_alive = "3s" # Ping interval; "0s" disables it. iroh still pings at least every 5s. Default.
keep_alive = "3s" # Ping interval; "0s" disables it. iroh refuses zero and keeps a separate 5s path heartbeat. Default.
gso = true # UDP segmentation offload. iroh cannot turn it off.
mtu_discovery = false # Path MTU discovery. Default.
receive_window = 134217728 # Whole-connection window, in bytes. Default (128 MiB).
stream_receive_window = 4194304 # Per-stream window, in bytes. Default (4 MiB).
send_window = 16777216 # Unacknowledged outgoing data, in bytes. Default (16 MiB).
qlog = "/var/log/moq/qlog" # Existing directory. Needs the `qlog` build feature.
keylog = false # Write TLS secrets to the file SSLKEYLOGFILE names. Default.
# keylog = "/private/keys.log" # Explicit secret log path; unset is off.
```

`congestion_control = "none"` runs no congestion control and no pacing. It is
meant for tests and controlled links, where nothing else shares the path.

`SSLKEYLOGFILE` alone writes nothing: set `keylog = true` too, and only while
debugging, since the file decrypts every captured session.
Set `keylog` only while debugging, since the file decrypts every captured session.
Tokio and io\_uring open the configured path at initialization. New Unix files are
mode 0600; an existing file readable by group or others is refused without changing
its permissions. `SSLKEYLOGFILE` does not configure native relay logging.
Iroh currently refuses an explicit keylog path when enabled.

`idle_timeout` is how long a peer that vanished without a close keeps its
sessions, and so its [cluster routes](/bin/relay/cluster#failure-detection).
Expand Down
1 change: 0 additions & 1 deletion quest/m1/api-audit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ Rejected in planning:
- [Media surface trim](/quest/m1/api-audit/media-trim.md) - media crate items with no consumer go private, and Rust/JS media names agree
- [One frame rate name](/quest/m1/api-audit/frame-rate.md) - core `moq_video::Rate` becomes `FrameRate`, as the bindings name it
- [Pinned consumers adopt the CLI flag names](/quest/m1/api-audit/cli-flags-consumers.md) - pinned downstream deployments move past the flag rename and use its spellings
- [Transport config](/quest/m1/api-audit/transport-config.md) - moq-tokio and moq-quic configs have one meaning for unset, enums for modes, no order-dependent setters, and no leftover features
- [Session-only items stay private](/quest/m1/api-audit/model-private.md) - model items only the built-in sessions use are private
- [Only sessions accept a request](/quest/m1/api-audit/claim-request-type.md) - accepting an application claim's request fails to compile, and the peer-route hatches are crate-private
- [A request's source enforces its validity](/quest/m1/api-audit/answer.md) - a stale source refuses new track requests by itself, with no public additions
Expand Down
41 changes: 0 additions & 41 deletions quest/m1/api-audit/transport-config.md

This file was deleted.

8 changes: 2 additions & 6 deletions quest/m1/js-reload-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ and accepts no option it ignores.

## Plan

[Transport config](/quest/m1/api-audit/transport-config.md) splits Rust's
healthy bar out of `backoff.initial` into `backoff.healthy`. `ReloadDelay`
Rust's moq-tokio split its healthy bar out of `backoff.initial` into
`backoff.healthy` ([moq-dev/moq#6529](https://github.com/moq-dev/moq/pull/6529)). `ReloadDelay`
(`js/net/src/connection/reload.ts`) still uses `initial` as the healthy bar.
Add `healthy` with Rust's default and a mocked-time test.

Expand All @@ -20,7 +20,3 @@ the reload loop never passes them to `connect()`. Decided 2026-10-23
unless that quest lands keeping it public, in which case forward it.

Public API: breaking JS option change; the Impact bullet says how to migrate. Wire: none.

## Required

- [Transport config](/quest/m1/api-audit/transport-config.md) - the Rust `backoff.healthy` this mirrors
8 changes: 1 addition & 7 deletions quest/m1/quic-api/trim.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Every public item of moq-quic, `moq_tokio::quic::driver`, and moq-uring's
`quic` module has a consumer in this repository, moq.pro, moq.dev, or an m1
quest, or it is private or deleted. Unordered reads, the duplicate limit
setters, unused features, and quinn-era docs are gone.
setters, and quinn-era docs are gone.

## Plan

Expand Down Expand Up @@ -53,12 +53,6 @@ driver's `read_chunk(max, ordered)` lose the flag, and `Chunk.offset`,
deleted. The driver's `read_to_end` is their only caller and reads ordered.
Two of the upstream fixes ported so far were unordered-mode bugs.

Moved here from [transport config](/quest/m1/api-audit/transport-config.md):
drop moq-quic's unused features (`rustls-ring`, `tracing-log`, `bloom`,
`platform-verifier`, fips, log) and the "backwards compat" `rustls` alias;
gate `pub use rustls` on `any(ring, aws-lc-rs)` so it exists under
`rustls-aws-lc-rs`.

Docs that still describe quinn: the crate docs (`lib.rs`, "the futures-based
quinn API" and C bindings) point at `moq_tokio::quic::driver`; "Quinn" in
`config/mod.rs`, `crypto.rs`, `cid_generator.rs`, `config/transport.rs`, and
Expand Down
2 changes: 1 addition & 1 deletion rs/kio/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ categories = ["asynchronous", "concurrency"]

[features]
# Per-task Ready poll accounting for deterministic simulators, never production.
sim = []
_sim = []

[dependencies]
smallvec = { version = "1.15", features = ["union"] }
Expand Down
4 changes: 2 additions & 2 deletions rs/kio/src/consumer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ impl<T> Consumer<T> {
/// channel is still open, registers the [`Waiter`] for notification.
/// Returns `Err(`[`Ref`]`)` if the channel has been closed while the
/// condition returned by `f` is still pending.
#[cfg_attr(feature = "sim", track_caller)]
#[cfg_attr(feature = "_sim", track_caller)]
pub fn poll<F, R>(&self, waiter: &Waiter, f: F) -> Poll<Result<R, Ref<'_, T>>>
where
F: FnOnce(&Ref<'_, T>) -> Poll<R>,
Expand All @@ -96,7 +96,7 @@ impl<T> Consumer<T> {
}

/// Poll for channel closure, registering the waiter if still open.
#[cfg_attr(feature = "sim", track_caller)]
#[cfg_attr(feature = "_sim", track_caller)]
pub fn poll_closed(&self, waiter: &Waiter) -> Poll<()> {
let mut state = self.state.lock();
if state.closed {
Expand Down
16 changes: 8 additions & 8 deletions rs/kio/src/coop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,40 +9,40 @@ use std::task::Poll;

use crate::Waiter;

#[cfg(feature = "sim")]
#[cfg(feature = "_sim")]
thread_local! {
static READY: std::cell::Cell<Option<usize>> = const { std::cell::Cell::new(None) };
}

/// Restores the enclosing count, even when a spawned task panics and its executor
/// catches the panic.
#[cfg(feature = "sim")]
#[cfg(feature = "_sim")]
struct Reset(Option<usize>);

#[cfg(feature = "sim")]
#[cfg(feature = "_sim")]
impl Drop for Reset {
fn drop(&mut self) {
READY.set(self.0);
}
}

/// Count ready kio polls until the returned guard drops, panicking if the task spins.
#[cfg(feature = "sim")]
#[cfg(feature = "_sim")]
#[must_use = "keep the guard until the task poll returns"]
pub fn scope() -> impl Drop {
Reset(READY.replace(Some(0)))
}

/// Give a [`Tasks`](crate::Tasks) child's poll its own count, but only inside a counting scope.
#[cfg(feature = "sim")]
#[cfg(feature = "_sim")]
pub(crate) fn child() -> impl Drop {
Reset(READY.replace(READY.get().map(|_| 0)))
}

#[inline]
#[cfg_attr(feature = "sim", track_caller)]
#[cfg_attr(feature = "_sim", track_caller)]
pub(crate) fn ready<T>(value: T) -> Poll<T> {
#[cfg(feature = "sim")]
#[cfg(feature = "_sim")]
{
let count = READY.get().map(|count| count + 1);
READY.set(count);
Expand Down Expand Up @@ -75,7 +75,7 @@ impl Budget {
/// The yield refills the budget for the next poll. Call it only where `Pending` goes
/// straight up to the task: a caller that reads `Pending` as "nothing now" would
/// mistake the yield for an answer.
#[cfg_attr(feature = "sim", track_caller)]
#[cfg_attr(feature = "_sim", track_caller)]
pub fn poll_yield(&mut self, waiter: &Waiter) -> Poll<()> {
match self.left.checked_sub(1) {
Some(left) => {
Expand Down
10 changes: 5 additions & 5 deletions rs/kio/src/producer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ impl<T> Producer<T> {
/// while pending.
///
/// Returns `Poll::Ready(Err(`[`Ref`]`))` if the channel is closed.
#[cfg_attr(feature = "sim", track_caller)]
#[cfg_attr(feature = "_sim", track_caller)]
pub fn poll<F>(&self, waiter: &Waiter, f: F) -> Poll<Result<Mut<'_, T>, Ref<'_, T>>>
where
F: FnOnce(&Ref<'_, T>) -> Poll<()>,
Expand All @@ -151,7 +151,7 @@ impl<T> Producer<T> {
/// [`Mut`], so it never flags the state modified and never wakes consumers.
/// Use it to wait on a read condition from the producer side without creating
/// a [`Consumer`].
#[cfg_attr(feature = "sim", track_caller)]
#[cfg_attr(feature = "_sim", track_caller)]
pub fn poll_ref<F, R>(&self, waiter: &Waiter, f: F) -> Poll<Result<R, Ref<'_, T>>>
where
F: FnOnce(&Ref<'_, T>) -> Poll<R>,
Expand Down Expand Up @@ -193,7 +193,7 @@ impl<T> Producer<T> {

/// Poll for channel closure (an explicit [`Mut::close`], e.g. an abort),
/// registering the waiter if still open.
#[cfg_attr(feature = "sim", track_caller)]
#[cfg_attr(feature = "_sim", track_caller)]
pub fn poll_closed(&self, waiter: &Waiter) -> Poll<()> {
let mut state = self.state.lock();
if state.closed {
Expand All @@ -213,7 +213,7 @@ impl<T> Producer<T> {

/// Poll-based variant of [`Self::unused`]: `Ready(Ok(()))` when no consumers
/// remain, [`Closed`] if the channel closed first, else `Pending`.
#[cfg_attr(feature = "sim", track_caller)]
#[cfg_attr(feature = "_sim", track_caller)]
pub fn poll_unused(&self, waiter: &Waiter) -> Poll<Result<(), Closed>> {
let mut state = self.state.lock();
if state.closed {
Expand Down Expand Up @@ -252,7 +252,7 @@ impl<T> Producer<T> {

/// Poll-based variant of [`Self::used`]: `Ready(Ok(()))` once a consumer
/// exists, [`Closed`] if the channel closed first, else `Pending`.
#[cfg_attr(feature = "sim", track_caller)]
#[cfg_attr(feature = "_sim", track_caller)]
pub fn poll_used(&self, waiter: &Waiter) -> Poll<Result<(), Closed>> {
let mut state = self.state.lock();
if state.closed {
Expand Down
4 changes: 2 additions & 2 deletions rs/kio/src/queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ impl<T> Queue<T> {
/// (or anything that does).
///
/// Registers `waiter` while full; a pop or close re-polls it.
#[cfg_attr(feature = "sim", track_caller)]
#[cfg_attr(feature = "_sim", track_caller)]
pub fn poll_push_with<F: FnOnce() -> T>(&self, waiter: &Waiter, make: F) -> Poll<Result<(), Closed>> {
let mut waiters = {
let mut state = self.state.lock();
Expand Down Expand Up @@ -181,7 +181,7 @@ impl<T> Queue<T> {
///
/// Queued items drain before closure is reported, so [`Closed`] means empty
/// *and* closed. Registers `waiter` while empty; a push or close re-polls it.
#[cfg_attr(feature = "sim", track_caller)]
#[cfg_attr(feature = "_sim", track_caller)]
pub fn poll_pop(&self, waiter: &Waiter) -> Poll<Result<T, Closed>> {
let (item, mut waiters) = {
let mut state = self.state.lock();
Expand Down
Loading
Loading