|
wired
libc-free QUIC/HTTP3 SDK in C for x86_64-linux
|
draft-ietf-moq-transport-18/19/22 hub relay (section numbers are draft-19's unless a draft is named; each peer's negotiated draft, its moqver.h capability bits, picks the per-draft behavior): the app-facing layer wiring the other MOQT domains (vi/kvp/ctl/data/dgram/sess/fetch/ns/tstat/cache) onto the WT application API (app/http3/server/srvrun). More...
#include "app/http3/server/srvrun/srvrun.h"#include "app/moqt/cache/moqcache.h"#include "app/moqt/ctl/moqctl.h"#include "app/moqt/data/moqdata.h"#include "app/moqt/fetch/moqfetch.h"#include "app/moqt/qraw/moqraw.h"#include "app/moqt/run/moqtrel.h"#include "app/moqt/run/moqtss.h"#include "app/moqt/sess/moqsess.h"#include "common/bytes/span/span.h"#include "common/platform/sys/syscall.h"Go to the source code of this file.
Data Structures | |
| struct | wired_moqt_io |
| The send/reset operations this layer needs, as a function-pointer table so it never links wired_server_wt_* directly (kept testable without the QUIC/TLS stack). More... | |
| struct | wired_moqtrun_rngrow |
| One flattened Range Filter Range (draft-19 10.2.10-10.2.14): the (ptype, set_id[, prop_type]) triple names the parameter it came from; a parameter with k Ranges takes k rows. More... | |
| struct | wired_moqtrun_sub |
| One subscriber recorded against the hub's track: which session, and the Track Alias its SUBSCRIBE_OK named – the alias every SUBGROUP_HEADER and OBJECT_DATAGRAM relayed to that session carries (draft-22 3.1.3: unique per Track within the session; moqtrun_session_alias). More... | |
| struct | wired_moqtrun_relay |
| One in-flight relayed publisher stream: which publisher-side stream (pub_stream_id) this relay follows, and – per subscriber slot index in the owning track's subs[] – the subscriber-side uni stream its bytes are forwarded on. More... | |
| struct | wired_moqtrun_ctl_asm |
| Reassembly of control messages split across stream deliveries: holds the not-yet-complete tail of one stream. More... | |
| struct | wired_moqtrun_req |
| One peer-opened request stream (draft-ietf-moq-transport-19 3.3): its own reassembly and reply queue (the same ARMED/PENDING pair as wired_moqtrun_peer.send_bufs, at request-stream size). More... | |
| struct | wired_moqtrun_rdv |
| One SUBSCRIBE held for a publisher. More... | |
| struct | wired_moqtrun_up |
| One SUBSCRIBE the hub sent upstream on its own request stream. More... | |
| struct | wired_moqtrun_fetch |
| One FETCH response being served from the hub cache: Objects of the track incarnation cache_tag in [cursor, end) go out on one uni stream (FETCH_HEADER, then fetch Objects, 11.4.4), one item per stream round as the transport accepts them. More... | |
| struct | wired_moqtrun_upf_leg |
| The bulky part of a fetches[] slot's upstream FETCH, kept beside the slot (wired_moqt_hub.upf_legs, same index) so fetch_waits[] entries, which never run one, do not carry it. More... | |
| struct | wired_moqtrun_track |
| One track a peer PUBLISHes (chat or audio), and the subscribers recorded against it. More... | |
| struct | wired_moqtrun_peer |
| One connected participant's hub-side state: its WT session, its own control-stream MOQT session machine, and the tracks (chat/audio) it has PUBLISHed. More... | |
| struct | wired_moqtrun_live |
| The hub's own clock-paced live track (wired_moqt_publish_live): Group g carries fragment g mod n_frags as its only Object, Groups advancing every group_ms from t0_ms. More... | |
| struct | wired_moqt_hub |
| The hub's whole state: fixed peer table plus the io table it sends through. More... | |
Macros | |
| #define | WIRED_MOQTRUN_MAX_SESSIONS 32 |
| Fixed capacity: concurrent sessions the hub tracks at once. | |
| #define | WIRED_MOQTRUN_MAX_SUBS (WIRED_MOQTRUN_MAX_SESSIONS - 1) |
| Fixed capacity: subscribers recorded against the hub's single published track per session slot (every other connected session, at most). | |
| #define | WIRED_MOQTRUN_URGENCY(sub_prio, pub_prio) |
| RFC 9218 urgency of a subscriber stream from its subscription's Subscriber Priority and the stream's Publisher Priority (both 0..255, lower first, 128 when absent – draft-ietf-moq-transport-19 7.1, 10.2.7). | |
| #define | WIRED_MOQTRUN_CLOSE_PROTOCOL_VIOLATION 0x3 |
| draft-ietf-moq-transport-19 SS3.5 PROTOCOL_VIOLATION session code. | |
| #define | WIRED_MOQTRUN_CLOSE_INTERNAL_ERROR 0x1 |
| draft-ietf-moq-transport-19 SS3.5 INTERNAL_ERROR session code. | |
| #define | WIRED_MOQTRUN_CLOSE_NO_ERROR 0x0 |
| draft-ietf-moq-transport-19 3.5 NO_ERROR session code. | |
| #define | WIRED_MOQTRUN_CLOSE_INVALID_REQUEST_ID 0x4 |
| draft-ietf-moq-transport-18/19 3.5 INVALID_REQUEST_ID session code. | |
| #define | WIRED_MOQTRUN_CLOSE_GOAWAY_TIMEOUT 0x10 |
| draft-ietf-moq-transport-19 3.5 GOAWAY_TIMEOUT session code. | |
| #define | WIRED_MOQTRUN_CLOSE_INVALID_PATH 0x8 |
| draft-ietf-moq-transport-19 3.5 INVALID_PATH session code (a SETUP carried PATH over WebTransport, 10.4). | |
| #define | WIRED_MOQTRUN_CLOSE_INVALID_AUTHORITY 0x19 |
| draft-ietf-moq-transport-19 3.5 INVALID_AUTHORITY session code (a SETUP carried AUTHORITY over WebTransport, 10.4). | |
| #define | WIRED_MOQTRUN_CLOSE_MALFORMED_PATH 0x9 |
| draft-ietf-moq-transport-19 3.5 / -22 12.2 MALFORMED_PATH session code (a raw-QUIC SETUP's PATH is not path-abempty [?query], 10.3.1.2). | |
| #define | WIRED_MOQTRUN_CLOSE_MALFORMED_AUTHORITY 0x1A |
| draft-ietf-moq-transport-19 3.5 / -22 12.2 MALFORMED_AUTHORITY session code (a raw-QUIC SETUP's AUTHORITY is no RFC 3986 authority, 10.3.1.1). | |
| #define | WIRED_MOQTRUN_CLOSE_TOO_MANY_REQUEST_UPDATES 0x1B |
| draft-ietf-moq-transport-19 3.5/10.9 TOO_MANY_REQUEST_UPDATES session code: a request stream already holding MAX_REQUEST_UPDATES outstanding REQUEST_UPDATEs received one more. | |
| #define | WIRED_MOQTRUN_CLOSE_AUTH_TOKEN_CACHE_OVERFLOW 0x13 |
| draft-ietf-moq-transport-22 8.9 / 12.2 AUTH_TOKEN_CACHE_OVERFLOW session code: a REGISTER Token exceeded the hub's 0-byte token cache. | |
| #define | WIRED_MOQTRUN_CLOSE_UNKNOWN_AUTH_TOKEN_ALIAS 0x17 |
| draft-ietf-moq-transport-22 8.9 / 12.2 UNKNOWN_AUTH_TOKEN_ALIAS session code: a Token referenced an Alias the hub never registered. | |
| #define | WIRED_MOQTRUN_MAX_FILTER_RANGES 4 |
| MAX_FILTER_RANGES the hub advertises in its SETUP (draft-19 10.4): Ranges accepted concurrently across one subscription's or fetch's Range filter parameters (10.2.10-10.2.14); a request past it is answered REQUEST_ERROR INVALID_FILTER. | |
| #define | WIRED_MOQTRUN_MAX_REQ_UPDATES 4 |
| MAX_REQUEST_UPDATES the hub advertises in its SETUP (draft-19 10.4): outstanding REQUEST_UPDATEs it accepts per request stream before closing with TOO_MANY_REQUEST_UPDATES. | |
| #define | WIRED_MOQTRUN_IMPL_MAX 64 |
| Longest MOQT_IMPLEMENTATION value (10.4) copied from the client's SETUP; longer values are kept truncated. | |
| #define | WIRED_MOQTRUN_HOLD_BUF 2048 |
| Per-peer buffer for request/Object stream deliveries arriving before SETUP completes both directions (draft-19 3.3): a byte log of (stream id, length, fin, bytes) records replayed in arrival order once the session establishes. | |
| #define | WIRED_MOQTRUN_EARLY_BUF 2048 |
| Per-peer buffer for one SUBGROUP stream that reaches the hub before the publisher's SUBSCRIBE_OK to the hub's upstream SUBSCRIBE (draft-22 3.1.3.1 MAY: its Track Alias is not known yet), relayed once the OK claims the track. | |
| #define | WIRED_MOQTRUN_GOAWAY_URI_MAX 8192 |
| Longest New Session URI wired_moqt_goaway sends: the spec maximum (draft-22 9.2, draft-18/19 10.4). | |
| #define | WIRED_MOQTRUN_GOAWAY_MSG_MAX ((usz)WIRED_MOQTRUN_GOAWAY_URI_MAX + 32) |
| Largest GOAWAY envelope: the URI plus Type, Length, Request ID and URI Length varints. | |
| #define | WIRED_MOQTRUN_DRAIN_TIMEOUT_MS 5000 |
| GOAWAY Timeout the hub gives a session whose peer sent WT_DRAIN_SESSION (wired_moqt_on_session_draining): the peer asked to go, so a short grace for its subscriptions to wind down. | |
| #define | WIRED_MOQTRUN_TRACK_PROPS_MAX 32 |
| Largest Track Properties block a track keeps to forward in SUBSCRIBE_OK: what still fits a WIRED_MOQTRUN_CTL_REPLY_MAX (64) envelope beside the Type/Length (3), the Track Alias (8) and a LARGEST_OBJECT parameter (19). | |
| #define | WIRED_MOQTRUN_RELAY_HDR_MAX 40 |
| Fixed capacity for a saved SUBGROUP_HEADER (draft SS11.4.2: Type + Track Alias + Group ID + optional Subgroup ID varints + optional 1-byte Publisher Priority = at most 4*9+1 = 37 bytes). | |
| #define | WIRED_MOQTRUN_RELAY_FRAG_MAX 16384 |
| Cap on a held tail: the bytes of an Object split across deliveries (past the last complete Object boundary, kept until the next delivery completes them – wired_moqtrun_relay's frag doc), and the size of one WIRED_MOQTRUN_FRAG_POOL buffer. | |
| #define | WIRED_MOQTRUN_FRAG_POOL 8 |
| Hub-wide buffers for held-back Object fragments, shared by every relay (a relay holds one only while an Object is torn across deliveries). | |
| #define | WIRED_MOQTRUN_RESET_AFTER_BUSY 8 |
| Consecutive refused relay rounds (io.stream_send returning busy) after which a subscriber's relay stream is abandoned via io.stream_reset and re-opened fresh (with the saved SUBGROUP_HEADER) on a later round: live audio wants the newest frame delivered, not a faithful replay of a stale backlog. | |
| #define | WIRED_MOQTRUN_MAX_RELAYS 4 |
| Fixed capacity: publisher streams relayed concurrently per track. | |
| #define | WIRED_MOQTRUN_MAX_NAME 64 |
| Fixed capacity for the copied participant id (Track Name) recorded on PUBLISH, used with the namespace (WIRED_MOQTRUN_MAX_NS) to match a later SUBSCRIBE to the right peer. | |
| #define | WIRED_MOQTRUN_MAX_NS 128 |
| Fixed capacity for a track's encoded Track Namespace (count + each field's length + bytes, draft 1.5): MOQCTL_MAX_NS_FIELDS one-byte fields take 65. | |
| #define | WIRED_MOQTRUN_MAX_TRACKS_PER_PEER 4 |
| Fixed capacity: tracks one peer can PUBLISH at once (chat + audio + screen + the screen's low-rate SSTS variant, screen-lo). | |
| #define | WIRED_MOQTRUN_SUB_NAMES ((usz)WIRED_MOQTRUN_MAX_TRACKS_PER_PEER * 4) |
| Fixed capacity: Track Names one peer remembers having SUBSCRIBEd to (wired_moqtrun_peer.sub_names). | |
| #define | WIRED_MOQTRUN_CTL_REPLY_MAX 64 |
| Largest control-message envelope this hub ever sends (SS10 Type+Length+Body), except GOAWAY, whose New Session URI may take up to WIRED_MOQTRUN_GOAWAY_URI_MAX bytes (wired_moqt_goaway sizes its own buffer). | |
| #define | WIRED_MOQTRUN_CTL_MSG_MAX 1024 |
| Largest received control-message Length (body bytes) this hub handles. | |
| #define | WIRED_MOQTRUN_CTL_HDR_MAX 11 |
| Type (vi64, up to 9 bytes) + 16-bit Length. | |
| #define | WIRED_MOQTRUN_MAX_REQS 96 |
| Fixed capacity: peer-opened request streams (draft-ietf-moq-transport-19 3.3) tracked at once, hub-wide. | |
| #define | WIRED_MOQTRUN_MAX_REQS_PER_SESSION (WIRED_MOQTRUN_MAX_REQS / 4) |
| Request streams one session may hold at once, so one session cannot take the whole pool: a fair quarter of it. | |
| #define | WIRED_MOQTRUN_CTL_REPLIES_MAX |
| Replies one control-stream dispatch can queue: the shared control stream can carry several requests per call (moqtrun_dispatch_ctl_stream's own doc), and each can produce one reply – worst case here is one SUBSCRIBE reply per other connected peer's track, WIRED_MOQTRUN_MAX_SUBS * WIRED_MOQTRUN_MAX_TRACKS_PER_PEER of them. | |
| #define | WIRED_MOQTRUN_CTL_SEND_BUF |
| Largest total this hub ever needs to buffer for one peer within one wired_moqt_on_stream_data dispatch: WIRED_MOQTRUN_CTL_REPLIES_MAX, or one longest GOAWAY (WIRED_MOQTRUN_GOAWAY_MSG_MAX), whichever is larger. | |
| #define | WIRED_MOQTRUN_REQ_SEND_BUF ((usz)WIRED_MOQTRUN_CTL_REPLY_MAX * 4) |
| Replies one request-stream delivery can queue: the request's own answer plus a few REQUEST_UPDATE answers arriving with it. | |
| #define | WIRED_MOQTRUN_MAX_RDV 16 |
| Fixed capacity: SUBSCRIBEs held for a publisher (RENDEZVOUS_TIMEOUT, draft-18/19 10.2.6, draft-22 9.20.6), hub-wide. | |
| #define | WIRED_MOQTRUN_RDV_PER_SESSION (WIRED_MOQTRUN_MAX_RDV / 4) |
| Holds one session may own, so one session cannot take the whole table (the WIRED_MOQTRUN_MAX_REQS_PER_SESSION pattern). | |
| #define | WIRED_MOQTRUN_RDV_MAX_MS 1500 |
| Longest hold, ms: the relay MAY use a shorter timeout (10.2.6). | |
| #define | WIRED_MOQTRUN_RDV_RETRY 1001 |
| Retry Interval (ms + 1, draft-18 10.6: 1 = immediately) sent with the EXCESSIVE_LOAD refusal of a hold that did not fit. | |
| #define | WIRED_MOQTRUN_MAX_UP WIRED_MOQTRUN_MAX_RDV |
| Fixed capacity: upstream SUBSCRIBEs the hub holds toward namespace publishers (draft-18/19 9.5, draft-22 7.6), hub-wide, one per Full Track Name (aggregation, 9.4). | |
| #define | WIRED_MOQTRUN_MAX_FETCHES 8 |
| Fixed capacity: FETCH responses (draft-ietf-moq-transport-19 10.12.3) being served at once, hub-wide. | |
| #define | WIRED_MOQTRUN_UPFETCH_BUDGET_MS 2000 |
| Longest an upstream FETCH may run (draft-ietf-moq-transport-22 3.2.3: a relay fetches what it lacks from upstream; 9.20.5: FILL_TIMEOUT is the total budget, this the implementation default when it is absent, and FILL_TIMEOUT shortens it). | |
| #define | WIRED_MOQTRUN_UPF_NONE 0 |
| wired_moqtrun_fetch.up_state: no upstream FETCH in flight. | |
| #define | WIRED_MOQTRUN_UPF_SENT 1 |
| wired_moqtrun_fetch.up_state: upstream FETCH sent, not yet answered. | |
| #define | WIRED_MOQTRUN_UPF_OK 2 |
| wired_moqtrun_fetch.up_state: upstream FETCH_OK received. | |
| #define | WIRED_MOQTRUN_GOAWAY_GRACE_MS 1000 |
| Minimum wall-clock milliseconds (wired_moqt_tick's own clock) between a drained session's PUBLISH_DONE flush and its GOAWAY_TIMEOUT close (3.6/10.11): long enough for a peer under load to read the flushed PUBLISH_DONE and its relay streams' resets before the session itself is gone, so it never races GOAWAY_TIMEOUT against those deliveries. | |
| #define | WIRED_MOQTRUN_PUBDONE_WAIT_MS 2000 |
| How long a publisher's PUBLISH_DONE may wait for the streams its Stream Count names but the hub has not seen relayed to their end (draft-ietf-moq-transport-19 10.11: PUBLISH_DONE may precede late-opening streams). | |
Typedefs | |
| typedef int(* | wired_moqt_authorize_fn) (void *ctx, const moqctl_ftn *name, const moqctl_token *token) |
| draft-ietf-moq-transport-19 SS13.3 authorization hook: as authorize_subscribe the hub calls it once per SUBSCRIBE and per TRACK_STATUS naming a known track, as authorize_publish once per PUBLISH, each with the Full Track Name and the presented AUTHORIZATION TOKEN (Alias Type USE_VALUE; 0 when the message carried none). | |
| typedef int(* | wired_moqt_authorize_ns_fn) (void *ctx, u64 msg_type, const moqctl_ns *ns, const moqctl_token *token) |
| draft-ietf-moq-transport-19 10.15 / 10.18 namespace authorization hook: the hub calls it once per PUBLISH_NAMESPACE or SUBSCRIBE_NAMESPACE (msg_type MOQNS_T_PUBLISH_NAMESPACE / MOQNS_T_SUBSCRIBE_NAMESPACE) with the Track Namespace or Prefix and the presented AUTHORIZATION TOKEN (Alias Type USE_VALUE; 0 when the message carried none). | |
Functions | |
| void | wired_moqt_init (wired_moqt_hub *hub, wired_moqt_io io) |
| Zero-initialize hub and record the io table it will send through. | |
| int | wired_moqt_cache_attach (wired_moqt_hub *hub, u8 *arena, usz size) |
| Gives the hub an Object cache for FETCH (draft-ietf-moq-transport-19 10.12.3): every whole Object a publisher sends is kept in arena, the oldest whole groups evicted first (app/moqt/cache/moqcache.h). | |
| void | wired_moqt_on_session (void *app_ctx, wired_wt_session *s, wired_span path, wired_span protocol) |
| wired_wt_on_session-shaped: registers a new peer slot for s and opens its control stream carrying SETUP (draft 3.3). | |
| void | wired_moqt_on_session_raw (void *app_ctx, wired_wt_session *s, wired_span alpn) |
| wired_rawq_on_session-shaped (srvrun's opt.raw_on_session): registers a raw-QUIC connection's implicit session s. | |
| void | wired_moqt_on_stream_data (void *app_ctx, wired_wt_session *s, u64 stream_id, wired_span data, int fin) |
| wired_wt_on_stream_data-shaped: dispatches one chunk of a control, request or data stream to the hub's session/subscribe state machines and the relay logic. | |
| void | wired_moqt_on_datagram (void *app_ctx, wired_wt_session *s, wired_span data) |
| wired_wt_on_datagram-shaped: relays one received OBJECT_DATAGRAM (draft-ietf-moq-transport-19 11.3.1) verbatim to every active subscriber whose Location Filter takes it, on the track its Track Alias names on the sending peer – the datagram twin of the SUBGROUP stream relay, but stateless: no relay entry, no held fragment, and no delivery to late subscribers (a datagram missed is gone; live audio wants the next frame, not a replay). | |
| void | wired_moqt_on_session_close (void *app_ctx, wired_wt_session *s) |
| wired_wt_on_session_close-shaped: frees the peer slot registered for s and deactivates every subscription other peers' tracks held for it (their relays stop targeting its streams). | |
| void | wired_moqt_on_stream_reset (void *app_ctx, wired_wt_session *s, u64 stream_id, int mapped, u32 app_error_code) |
| wired_wt_on_stream_reset-shaped: a RESET_STREAM / STOP_SENDING on one of s's request streams cancels that request (draft-ietf-moq-transport-19 3.3.3) – a SUBSCRIBE's subscription is released, a PUBLISH's track withdrawn, a PUBLISH_NAMESPACE withdrawn (NAMESPACE_DONE to its subscribers), a SUBSCRIBE_NAMESPACE's pushes stopped – and frees the stream's slot. | |
| int | wired_moqt_goaway (wired_moqt_hub *hub, wired_span new_uri, u64 timeout_ms) |
| draft-ietf-moq-transport-19 3.6 / 10.4 graceful drain: sends GOAWAY (new_uri, timeout_ms) once on the control stream of every open session that has not had one. | |
| void | wired_moqt_on_session_draining (void *app_ctx, wired_wt_session *s) |
| wired_wt_on_session_draining-shaped: the peer of s sent WT_DRAIN_SESSION, so s alone is drained as by wired_moqt_goaway (empty URI, WIRED_MOQTRUN_DRAIN_TIMEOUT_MS). | |
| usz | wired_moqt_publish_blob (wired_moqt_hub *hub, wired_span name, u64 track_alias, wired_span blob, wired_mspan wire) |
| Publish a hub-owned static track: frames blob into wire (moqdata_blob_build: one SUBGROUP_HEADER carrying track_alias, then 16 KiB Objects) and records name. | |
| int | wired_moqt_publish_live (wired_moqt_hub *hub, wired_span name, u64 track_alias, const wired_span *frags, usz n_frags, u64 group_ms, u64 now_ms) |
| Publish the hub's own clock-paced live track: Group g carries fragment g mod n_frags as its only Object (framed byte-identically to moqdata_msg_build: one Type-0x70 SUBGROUP_HEADER + one Object), Groups advancing every group_ms from now_ms. | |
| void | wired_moqt_tick (wired_moqt_hub *hub, u64 now_ms) |
| Clock tick (wire to wired_srvrun_opt.on_step): the current Group is (now_ms - t0_ms) / group_ms; every live subscriber whose last accepted Group is older is sent it via io.send_uni2. | |
draft-ietf-moq-transport-18/19/22 hub relay (section numbers are draft-19's unless a draft is named; each peer's negotiated draft, its moqver.h capability bits, picks the per-draft behavior): the app-facing layer wiring the other MOQT domains (vi/kvp/ctl/data/dgram/sess/fetch/ns/tstat/cache) onto the WT application API (app/http3/server/srvrun).
One hub is a central server: clients PUBLISH tracks under namespaces of their choosing, SUBSCRIBE / FETCH / TRACK_STATUS by full track name, and discover each other through PUBLISH_NAMESPACE / SUBSCRIBE_NAMESPACE. All state lives in this one struct, so a hub serves a single process.
The actual WT sends (open/append/reset) are routed through a caller- supplied wired_moqt_io table rather than calling wired_server_wt_* here directly, so this file has no link-time dependency on the QUIC/TLS stack and can be driven by a test harness with stub functions.
| #define WIRED_MOQTRUN_CTL_MSG_MAX 1024 |
Largest received control-message Length (body bytes) this hub handles.
draft-ietf-moq-transport-19 SS10 allows up to 65535; a longer message closes the session like an unknown Type (moqtrun_asm_pop).
| #define WIRED_MOQTRUN_CTL_REPLIES_MAX |
Replies one control-stream dispatch can queue: the shared control stream can carry several requests per call (moqtrun_dispatch_ctl_stream's own doc), and each can produce one reply – worst case here is one SUBSCRIBE reply per other connected peer's track, WIRED_MOQTRUN_MAX_SUBS * WIRED_MOQTRUN_MAX_TRACKS_PER_PEER of them.
| #define WIRED_MOQTRUN_CTL_SEND_BUF |
Largest total this hub ever needs to buffer for one peer within one wired_moqt_on_stream_data dispatch: WIRED_MOQTRUN_CTL_REPLIES_MAX, or one longest GOAWAY (WIRED_MOQTRUN_GOAWAY_MSG_MAX), whichever is larger.
| #define WIRED_MOQTRUN_EARLY_BUF 2048 |
Per-peer buffer for one SUBGROUP stream that reaches the hub before the publisher's SUBSCRIBE_OK to the hub's upstream SUBSCRIBE (draft-22 3.1.3.1 MAY: its Track Alias is not known yet), relayed once the OK claims the track.
The race window is ~1 RTT, the same as WIRED_MOQTRUN_HOLD_BUF's; a stream that outgrows it is dropped as before. ponytail: one stream per peer; raise if publishers open several.
| #define WIRED_MOQTRUN_FRAG_POOL 8 |
Hub-wide buffers for held-back Object fragments, shared by every relay (a relay holds one only while an Object is torn across deliveries).
A torn Object finding none free is dropped like an oversized one (moqtrun_relay_save_frag). 8 covers every concurrently torn stream the chat room produces (a few screen/audio/chat streams in flight at once); past that only the excess stream is dropped (ended at its last whole Object), never another stream's bytes.
| #define WIRED_MOQTRUN_GOAWAY_GRACE_MS 1000 |
Minimum wall-clock milliseconds (wired_moqt_tick's own clock) between a drained session's PUBLISH_DONE flush and its GOAWAY_TIMEOUT close (3.6/10.11): long enough for a peer under load to read the flushed PUBLISH_DONE and its relay streams' resets before the session itself is gone, so it never races GOAWAY_TIMEOUT against those deliveries.
ponytail: fixed grace, not an ack wait; raise if a slow peer is still seen losing the race.
| #define WIRED_MOQTRUN_HOLD_BUF 2048 |
Per-peer buffer for request/Object stream deliveries arriving before SETUP completes both directions (draft-19 3.3): a byte log of (stream id, length, fin, bytes) records replayed in arrival order once the session establishes.
The pre-SETUP window is ~1 RTT, so bursts are tiny; a request delivery that does not fit is reset EXCESSIVE_LOAD at arrival, an Object delivery is dropped. ponytail: flat per-peer log; raise if real clients race SETUP with more data.
| #define WIRED_MOQTRUN_IMPL_MAX 64 |
Longest MOQT_IMPLEMENTATION value (10.4) copied from the client's SETUP; longer values are kept truncated.
ponytail: informational only; widen if an operator needs more.
| #define WIRED_MOQTRUN_MAX_FETCHES 8 |
Fixed capacity: FETCH responses (draft-ietf-moq-transport-19 10.12.3) being served at once, hub-wide.
A FETCH past it is answered REQUEST_ERROR INTERNAL_ERROR. ponytail: room-sized; raise when clients fetch in parallel.
| #define WIRED_MOQTRUN_MAX_FILTER_RANGES 4 |
MAX_FILTER_RANGES the hub advertises in its SETUP (draft-19 10.4): Ranges accepted concurrently across one subscription's or fetch's Range filter parameters (10.2.10-10.2.14); a request past it is answered REQUEST_ERROR INVALID_FILTER.
Matches the per-subscription range storage (wired_moqtrun_sub). ponytail: room-sized; raise with the storage if clients filter finer.
| #define WIRED_MOQTRUN_MAX_NS 128 |
Fixed capacity for a track's encoded Track Namespace (count + each field's length + bytes, draft 1.5): MOQCTL_MAX_NS_FIELDS one-byte fields take 65.
A longer namespace is refused on PUBLISH, never truncated (truncation would make distinct tracks match).
| #define WIRED_MOQTRUN_MAX_RDV 16 |
Fixed capacity: SUBSCRIBEs held for a publisher (RENDEZVOUS_TIMEOUT, draft-18/19 10.2.6, draft-22 9.20.6), hub-wide.
Each hold already pins one request-stream slot (WIRED_MOQTRUN_MAX_REQS = 96), so 16 lets a sixth of the pool wait at once – interop clients hold one (moq-test-*, rendezvous-timeout) or two (two subscribers of one track). Past it, or past WIRED_MOQTRUN_RDV_PER_SESSION, the SUBSCRIBE is refused EXCESSIVE_LOAD at once, never dropped. Each slot ~1.3 KB of BSS. ponytail: room-sized; raise with WIRED_MOQTRUN_MAX_REQS.
| #define WIRED_MOQTRUN_MAX_RELAYS 4 |
Fixed capacity: publisher streams relayed concurrently per track.
The audio track holds ONE for its whole call; chat holds one per in-flight message (open -> data rounds -> FIN, ~2 RTT) – 4 covers a burst without meaningfully growing the peer table. A stream arriving with every slot busy is not relayed (its subscribers miss that one message).
| #define WIRED_MOQTRUN_MAX_REQ_UPDATES 4 |
MAX_REQUEST_UPDATES the hub advertises in its SETUP (draft-19 10.4): outstanding REQUEST_UPDATEs it accepts per request stream before closing with TOO_MANY_REQUEST_UPDATES.
One more than fits a reply buffer's coalesced answers (WIRED_MOQTRUN_REQ_SEND_BUF's sizing).
| #define WIRED_MOQTRUN_MAX_REQS 96 |
Fixed capacity: peer-opened request streams (draft-ietf-moq-transport-19 3.3) tracked at once, hub-wide.
A request stream past it is reset with EXCESSIVE_LOAD; a completed request frees its slot once both sides have ended. Each slot is ~1.9 KB of BSS. Sized for a full moqt_chat room with track switching on (draft-22, one request per stream): each of 4 peers holds 4 PUBLISH + 3 namespace requests + 3x4 SUBSCRIBEs = 19 streams (76 hub-wide), so 96 keeps the per-session quarter (24) above 19 with headroom for a fill or FETCH. ponytail: room-sized; raise when rooms grow.
| #define WIRED_MOQTRUN_MAX_REQS_PER_SESSION (WIRED_MOQTRUN_MAX_REQS / 4) |
Request streams one session may hold at once, so one session cannot take the whole pool: a fair quarter of it.
Past it a new request stream is reset with EXCESSIVE_LOAD (draft-ietf-moq-transport-19 3.3.4).
| #define WIRED_MOQTRUN_MAX_SESSIONS 32 |
Fixed capacity: concurrent sessions the hub tracks at once.
Small on purpose – a room-sized deployment, not a general server. ponytail: raise if a real deployment needs more concurrent participants.
| #define WIRED_MOQTRUN_MAX_TRACKS_PER_PEER 4 |
Fixed capacity: tracks one peer can PUBLISH at once (chat + audio + screen + the screen's low-rate SSTS variant, screen-lo).
Each track slot is ~13 KB (31 subs + 4 relays), so 3 -> 4 grows the peer table by ~32 slots of that; SUB_NAMES and CTL_SEND_BUF scale with it below.
| #define WIRED_MOQTRUN_MAX_UP WIRED_MOQTRUN_MAX_RDV |
Fixed capacity: upstream SUBSCRIBEs the hub holds toward namespace publishers (draft-18/19 9.5, draft-22 7.6), hub-wide, one per Full Track Name (aggregation, 9.4).
Every pending one has a waiter in hub->rdv, so WIRED_MOQTRUN_MAX_RDV of them covers every hold going upstream at once; an Established one lives as long as its track, at most one of each publisher's WIRED_MOQTRUN_MAX_TRACKS_PER_PEER slots. Past it a waiter with no deadline is refused EXCESSIVE_LOAD. ~1.3 KB of BSS each. ponytail: room-sized; raise with WIRED_MOQTRUN_MAX_RDV.
| #define WIRED_MOQTRUN_PUBDONE_WAIT_MS 2000 |
How long a publisher's PUBLISH_DONE may wait for the streams its Stream Count names but the hub has not seen relayed to their end (draft-ietf-moq-transport-19 10.11: PUBLISH_DONE may precede late-opening streams).
Bounds a count the hub never reaches, e.g. 2^62-1 ("unknown"); past it the subscribers' PUBLISH_DONE goes out with the streams still open reset.
| #define WIRED_MOQTRUN_RDV_MAX_MS 1500 |
Longest hold, ms: the relay MAY use a shorter timeout (10.2.6).
Below the 2 s a runner client allots to rendezvous-timeout: imquic asks 500000 for its 500 ms window (microseconds read as ms), so any larger cap misses the REQUEST_ERROR TIMEOUT it waits for. Still above the publisher lag of the moq-rs moq-test scenarios (they ask 5000 ms).
| #define WIRED_MOQTRUN_RELAY_FRAG_MAX 16384 |
Cap on a held tail: the bytes of an Object split across deliveries (past the last complete Object boundary, kept until the next delivery completes them – wired_moqtrun_relay's frag doc), and the size of one WIRED_MOQTRUN_FRAG_POOL buffer.
A held tail is always shorter than its framed Object (Object ID Delta, Properties, Payload Length, payload), so a tail reaching this size belongs to a larger Object: it is dropped and its stream stops relaying (moqtrun_relay_save_frag). An Object that arrives whole in one delivery is never held. 16384 fits a chat attachment chunk or a small media frame. Datagram Objects are bounded by the QUIC datagram size instead.
| #define WIRED_MOQTRUN_RESET_AFTER_BUSY 8 |
Consecutive refused relay rounds (io.stream_send returning busy) after which a subscriber's relay stream is abandoned via io.stream_reset and re-opened fresh (with the saved SUBGROUP_HEADER) on a later round: live audio wants the newest frame delivered, not a faithful replay of a stale backlog.
8 rounds of 20ms voice ~= 160ms of sustained send-slot fullness – the transient one-round busy bursts a healthy call shows (a handful scattered per 10s, measured) never trip it, while true send starvation (server CPU-capped) converts to a fresh stream well under a second, discarding the ~0.5s of backlog the send slot's staging can hold.
| #define WIRED_MOQTRUN_SUB_NAMES ((usz)WIRED_MOQTRUN_MAX_TRACKS_PER_PEER * 4) |
Fixed capacity: Track Names one peer remembers having SUBSCRIBEd to (wired_moqtrun_peer.sub_names).
The chat app subscribes to every track of every other candidate participant, and the sample room has four candidate ids, so a peer can hold 3 others * 4 tracks = 12 names; 16 leaves room without a rejoined publisher's oldest name being evicted.
| #define WIRED_MOQTRUN_TRACK_PROPS_MAX 32 |
Largest Track Properties block a track keeps to forward in SUBSCRIBE_OK: what still fits a WIRED_MOQTRUN_CTL_REPLY_MAX (64) envelope beside the Type/Length (3), the Track Alias (8) and a LARGEST_OBJECT parameter (19).
ponytail: a larger block is forwarded empty; widen together with WIRED_MOQTRUN_CTL_REPLY_MAX if publishers send long properties.
| #define WIRED_MOQTRUN_UPFETCH_BUDGET_MS 2000 |
Longest an upstream FETCH may run (draft-ietf-moq-transport-22 3.2.3: a relay fetches what it lacks from upstream; 9.20.5: FILL_TIMEOUT is the total budget, this the implementation default when it is absent, and FILL_TIMEOUT shortens it).
Past it the request is cancelled and the rest served from the cache, so no fetch slot waits on a silent peer. ponytail: fixed; make it a hub setting if rooms need another bound.
| #define WIRED_MOQTRUN_URGENCY | ( | sub_prio, | |
| pub_prio ) |
RFC 9218 urgency of a subscriber stream from its subscription's Subscriber Priority and the stream's Publisher Priority (both 0..255, lower first, 128 when absent – draft-ietf-moq-transport-19 7.1, 10.2.7).
7.2 orders by subscriber priority, then publisher priority, so the subscriber's half picks the pair and the publisher's half the one within it: 4..7. Control and request streams keep the transport default 3 and so go first (7.2: they SHOULD be prioritized highest). The fallback when wired_moqt_io.stream_sched is 0: Group Order and the full 8-bit priorities need that hook's class; equal urgencies share the send pass in turn.
| typedef int(* wired_moqt_authorize_fn) (void *ctx, const moqctl_ftn *name, const moqctl_token *token) |
draft-ietf-moq-transport-19 SS13.3 authorization hook: as authorize_subscribe the hub calls it once per SUBSCRIBE and per TRACK_STATUS naming a known track, as authorize_publish once per PUBLISH, each with the Full Track Name and the presented AUTHORIZATION TOKEN (Alias Type USE_VALUE; 0 when the message carried none).
Return non-zero to grant, 0 to answer REQUEST_ERROR UNAUTHORIZED. The token scheme (CAT / Privacy Pass) is the deployment's to verify – this SDK carries the bytes, not the policy.
| typedef int(* wired_moqt_authorize_ns_fn) (void *ctx, u64 msg_type, const moqctl_ns *ns, const moqctl_token *token) |
draft-ietf-moq-transport-19 10.15 / 10.18 namespace authorization hook: the hub calls it once per PUBLISH_NAMESPACE or SUBSCRIBE_NAMESPACE (msg_type MOQNS_T_PUBLISH_NAMESPACE / MOQNS_T_SUBSCRIBE_NAMESPACE) with the Track Namespace or Prefix and the presented AUTHORIZATION TOKEN (Alias Type USE_VALUE; 0 when the message carried none).
Return non-zero to grant, 0 to answer REQUEST_ERROR UNAUTHORIZED.
| int wired_moqt_cache_attach | ( | wired_moqt_hub * | hub, |
| u8 * | arena, | ||
| usz | size ) |
Gives the hub an Object cache for FETCH (draft-ietf-moq-transport-19 10.12.3): every whole Object a publisher sends is kept in arena, the oldest whole groups evicted first (app/moqt/cache/moqcache.h).
Without one the hub caches nothing and a FETCH is answered with its range as unknown. Call once after wired_moqt_init, before any session; arena must outlive the hub.
| hub | the hub |
| arena | cache storage, owned by the app |
| size | arena bytes (each Object costs MOQCACHE_HDR on top) |
| int wired_moqt_goaway | ( | wired_moqt_hub * | hub, |
| wired_span | new_uri, | ||
| u64 | timeout_ms ) |
draft-ietf-moq-transport-19 3.6 / 10.4 graceful drain: sends GOAWAY (new_uri, timeout_ms) once on the control stream of every open session that has not had one.
A session that got GOAWAY answers every later new request REQUEST_ERROR GOING_AWAY (requests already answered stay, and their REQUEST_UPDATEs are served). A session still open timeout_ms after this call is sent PUBLISH_DONE GOING_AWAY for every subscription it holds on a request stream (its relay streams reset GOING_AWAY first) by the next tick, and closed on the tick after: GOAWAY_TIMEOUT while it still has a request stream, a published track or a subscription open, NO_ERROR when nothing is left. The deadline counts from the last wired_moqt_tick's now_ms, so call this once the tick runs (a call before the first tick counts from 0). timeout_ms 0 sets no deadline (10.4: no specific timeout). A publisher's session ending, for any reason, sends its subscribers on other sessions PUBLISH_DONE TRACK_ENDED. Subscriptions made on the control stream get no PUBLISH_DONE (it has no Request ID to name them by).
| hub | the hub |
| new_uri | where clients reconnect, empty to reuse the current URI (copied into the message) |
| timeout_ms | grace before GOAWAY_TIMEOUT, 0 for none |
| void wired_moqt_on_datagram | ( | void * | app_ctx, |
| wired_wt_session * | s, | ||
| wired_span | data ) |
wired_wt_on_datagram-shaped: relays one received OBJECT_DATAGRAM (draft-ietf-moq-transport-19 11.3.1) verbatim to every active subscriber whose Location Filter takes it, on the track its Track Alias names on the sending peer – the datagram twin of the SUBGROUP stream relay, but stateless: no relay entry, no held fragment, and no delivery to late subscribers (a datagram missed is gone; live audio wants the next frame, not a replay).
app_ctx must be the wired_moqt_hub*. Each subscriber copy goes through io.send_datagram (accepted -> stat_dg_sent, refused -> stat_dg_drop); a datagram moqdg_take refuses or whose alias matches no track is dropped whole on stat_dg_bad – draft 11.3.1 says an invalid Type MUST close the session with PROTOCOL_VIOLATION, but this hub's io table has no close operation, so counting-and-dropping is the closest it can do. A session never registered, or an io table whose send_datagram is 0, is a no-op.
| void wired_moqt_on_session | ( | void * | app_ctx, |
| wired_wt_session * | s, | ||
| wired_span | path, | ||
| wired_span | protocol ) |
wired_wt_on_session-shaped: registers a new peer slot for s and opens its control stream carrying SETUP (draft 3.3).
app_ctx must be the wired_moqt_hub*. path/protocol are unused (room membership is hub-side fixed, not negotiated).
| void wired_moqt_on_session_close | ( | void * | app_ctx, |
| wired_wt_session * | s ) |
wired_wt_on_session_close-shaped: frees the peer slot registered for s and deactivates every subscription other peers' tracks held for it (their relays stop targeting its streams).
app_ctx must be the wired_moqt_hub*. Without this, a dead session's peer slot leaks forever and a reconnecting client whose new session reuses the same slot memory is mistaken for the dead peer – it never receives SETUP and stays mute until the process restarts. A session the hub never registered is a no-op.
| void wired_moqt_on_session_draining | ( | void * | app_ctx, |
| wired_wt_session * | s ) |
wired_wt_on_session_draining-shaped: the peer of s sent WT_DRAIN_SESSION, so s alone is drained as by wired_moqt_goaway (empty URI, WIRED_MOQTRUN_DRAIN_TIMEOUT_MS).
app_ctx must be the wired_moqt_hub*.
| void wired_moqt_on_session_raw | ( | void * | app_ctx, |
| wired_wt_session * | s, | ||
| wired_span | alpn ) |
wired_rawq_on_session-shaped (srvrun's opt.raw_on_session): registers a raw-QUIC connection's implicit session s.
The MOQT draft comes from the ALPN token (moqt-NN, the same moqver table as the WT subprotocol; an unlisted one falls back to draft-19), and the control streams are the uni pair, as on a WT session with a negotiated token (-22 6.3/6.4). The client's PATH/AUTHORITY Setup Options are then judged by hub->raw_policy (moqraw_setup_verdict), and a GOAWAY to s carries an empty New Session URI (reuse the current one, -22 9.2). With no free peer slot s is closed INTERNAL_ERROR through io.close_session. app_ctx must be the wired_moqt_hub*.
| app_ctx | the wired_moqt_hub* |
| s | the connection's implicit session |
| alpn | the negotiated ALPN protocol id, e.g. "moqt-22" |
| void wired_moqt_on_stream_data | ( | void * | app_ctx, |
| wired_wt_session * | s, | ||
| u64 | stream_id, | ||
| wired_span | data, | ||
| int | fin ) |
wired_wt_on_stream_data-shaped: dispatches one chunk of a control, request or data stream to the hub's session/subscribe state machines and the relay logic.
app_ctx must be the wired_moqt_hub*.
A peer-opened bidi stream is a request stream (draft-ietf-moq-transport-19 3.3): its messages go through the same handlers as the control stream's, and their replies go back on it. Its first message must be a request type and every later one must belong to that request, else the session closes with PROTOCOL_VIOLATION. Control and request messages are reassembled across calls; a FIN does not cancel a request (3.3.2). A request answered without establishing a subscription or track is complete: the hub FINs its side after the answer and frees the slot once the peer's side has ended too. With request streams on, a peer-opened bidi stream is never read as Object data.
Namespace discovery (6.1-6.2): a PUBLISH_NAMESPACE held open on its request stream is announced to every SUBSCRIBE_NAMESPACE whose prefix matches – NAMESPACE on the subscriber's stream, NAMESPACE_DONE once it is withdrawn by the last session publishing it (several may; each namespace is announced once). A session republishing its own namespace is refused UNINTERESTED; a session's prefixes overlapping (either empty, or the same first field) are refused PREFIX_OVERLAP. Both requests pass authorize_namespace first. Hub-owned tracks (publish_blob / publish_live) have no namespace and are not announced.
TRACK_STATUS (10.14) is answered like a SUBSCRIBE that creates nothing: REQUEST_OK with the Largest Location, or REQUEST_ERROR. REQUEST_UPDATE (10.9) on a SUBSCRIBE's stream replaces the parameters it carries (FORWARD, SUBSCRIBER_PRIORITY, OBJECT_DELIVERY_TIMEOUT, LOCATION_FILTER) and is answered REQUEST_OK; elsewhere it gets NOT_SUPPORTED. Objects reach a subscription only inside its Location Filter (Group-granular on streams), and one whose first byte arrived longer ago than its OBJECT_DELIVERY_TIMEOUT resets its stream with DELIVERY_TIMEOUT (draft 8).
| void wired_moqt_on_stream_reset | ( | void * | app_ctx, |
| wired_wt_session * | s, | ||
| u64 | stream_id, | ||
| int | mapped, | ||
| u32 | app_error_code ) |
wired_wt_on_stream_reset-shaped: a RESET_STREAM / STOP_SENDING on one of s's request streams cancels that request (draft-ietf-moq-transport-19 3.3.3) – a SUBSCRIBE's subscription is released, a PUBLISH's track withdrawn, a PUBLISH_NAMESPACE withdrawn (NAMESPACE_DONE to its subscribers), a SUBSCRIBE_NAMESPACE's pushes stopped – and frees the stream's slot.
On a relayed publisher stream it returns the relay's held fragment buffer to the hub's pool; any other stream is a no-op. mapped/app_error_code are unused.
| usz wired_moqt_publish_blob | ( | wired_moqt_hub * | hub, |
| wired_span | name, | ||
| u64 | track_alias, | ||
| wired_span | blob, | ||
| wired_mspan | wire ) |
Publish a hub-owned static track: frames blob into wire (moqdata_blob_build: one SUBGROUP_HEADER carrying track_alias, then 16 KiB Objects) and records name.
A later SUBSCRIBE naming name from any peer is answered SUBSCRIBE_OK – carrying track_alias, the alias the framed header itself has, so the subscriber can bind the stream to its subscription – and the framed bytes go to that peer once, on one uni stream (a single io.send_uni call: the SDK paces an oversized payload itself, holding it as a view). A repeat SUBSCRIBE from the same peer gets SUBSCRIBE_OK again but no second copy; a session close forgets the peer, so a reconnect receives it afresh. A refused send_uni answers REQUEST_ERROR (counted on stat_open_drop) and records nothing, so the peer's next SUBSCRIBE tries again. The hub-owned name wins over a peer track of the same name. Call once at boot, before any session; wire must outlive the hub (the framed bytes are held as a view).
| hub | the hub |
| name | Track Name subscribers ask for (copied; at most WIRED_MOQTRUN_MAX_NAME bytes) |
| track_alias | Track Alias carried by the framed header and by every SUBSCRIBE_OK for this track |
| blob | the bytes to publish (copied into wire's framing) |
| wire | destination for the framed bytes; size it with MOQDATA_BLOB_WIRE_CAP(blob.n) |
| int wired_moqt_publish_live | ( | wired_moqt_hub * | hub, |
| wired_span | name, | ||
| u64 | track_alias, | ||
| const wired_span * | frags, | ||
| usz | n_frags, | ||
| u64 | group_ms, | ||
| u64 | now_ms ) |
Publish the hub's own clock-paced live track: Group g carries fragment g mod n_frags as its only Object (framed byte-identically to moqdata_msg_build: one Type-0x70 SUBGROUP_HEADER + one Object), Groups advancing every group_ms from now_ms.
A later SUBSCRIBE naming name is answered SUBSCRIBE_OK carrying track_alias and immediately sent the Group current at the most recent wired_moqt_tick; each Group boundary a later tick crosses sends every subscriber the new Group's fragment on its own uni stream via io.send_uni2 (head = framing, body = the fragment, held as a view – frags and their bytes must outlive the hub). A refused send is retried while the clock is still in that Group and abandoned once it passes (counted on stat_live_drop) – a subscriber is never sent a stale Group. Call once at boot; a re-publish resets the track and forgets its subscribers.
| hub | the hub |
| name | Track Name subscribers ask for (copied; at most WIRED_MOQTRUN_MAX_NAME bytes) |
| track_alias | Track Alias carried by every framed header and every SUBSCRIBE_OK for this track |
| frags | per-Group fragment views (caller-owned, must outlive hub; every fragment must be non-empty – an empty Object payload would need the explicit Status varint this framing never carries) |
| n_frags | entries at frags |
| group_ms | Group duration in milliseconds |
| now_ms | current clock: Group 0 starts here |
| void wired_moqt_tick | ( | wired_moqt_hub * | hub, |
| u64 | now_ms ) |
Clock tick (wire to wired_srvrun_opt.on_step): the current Group is (now_ms - t0_ms) / group_ms; every live subscriber whose last accepted Group is older is sent it via io.send_uni2.
No live track: no-op.