wired
libc-free QUIC/HTTP3 SDK in C for x86_64-linux
Loading...
Searching...
No Matches
moqtrel.h File Reference

Reliable-relay byte ring for the MOQT hub: one publisher's relayed track bytes buffered once, with an independent read cursor per subscriber, so a slow subscriber's refused sends are retried instead of dropped. More...

Go to the source code of this file.

Data Structures

struct  moqtrel_sub
 One subscriber's read cursor into a ring. More...
struct  moqtrel_buf
 One reliable-relay ring: the publisher's relayed bytes plus every subscriber's cursor and the publisher-side backpressure state. More...

Macros

#define WIRED_MOQTREL_POOL   4
 Fixed capacity: reliable-relay rings the hub owns (one per concurrently relayed reliable track; further tracks fall back to the lossy path).
#define WIRED_MOQTREL_CAP   ((u64)3 * WIRED_SRVLOOP_WT_BUF_CAP)
 Ring capacity in bytes.
#define WIRED_MOQTREL_ROUND_MAX   16384
 Longest contiguous slice handed to one stream_send round.
#define WIRED_MOQTREL_STALL_MS   10000
 A subscriber whose sends have been refused for this long while bytes are pending is shed (reset) so it cannot pin the ring forever.
#define WIRED_MOQTREL_HEADROOM   (WIRED_MOQTRUN_RELAY_FRAG_MAX + WIRED_SRVLOOP_WT_BUF_CAP + 16)
 Session send credit (WT_MAX_DATA remaining) a reliable-relay round must leave unspent, so one lossy screen-share round on the SAME session still fits: a held fragment plus one receive window of delivered bytes plus 16 for the adapter's signal prefix, which the hub never sees.
#define WIRED_MOQTREL_MAX_SUBS   31
 Fixed capacity: subscriber cursors per ring.
#define WIRED_MOQTREL_MARKS   8
 Arrival marks a ring keeps (moqtrel_mark).

Functions

void moqtrel_reset (moqtrel_buf *b)
 Empty b: offsets zero, no publisher, every cursor inactive.
int moqtrel_append (moqtrel_buf *b, wired_span src)
 Append src's bytes at tail (wrapping physically at CAP).
wired_span moqtrel_next_round (const moqtrel_buf *b, u32 sub)
 The next contiguous slice to send to subscriber sub: starts at its sent cursor, length capped by pending bytes (tail - sent), by WIRED_MOQTREL_ROUND_MAX, and by the physical ring end.
void moqtrel_note_sent (moqtrel_buf *b, u32 sub, usz n, u64 now_ms)
 Record an accepted send: sub's cursor advances by n and its stall clock restarts at now_ms.
void moqtrel_mark (moqtrel_buf *b, u64 now_ms)
 Record that every byte up to tail has arrived by now_ms; call after each moqtrel_append.
u64 moqtrel_age_ms (const moqtrel_buf *b, u32 sub, u64 now_ms)
 How long ago subscriber sub's next unsent byte arrived (draft-ietf- moq-transport-19 8, the age OBJECT_DELIVERY_TIMEOUT is checked against).
void moqtrel_reclaim (moqtrel_buf *b)
 Advance head to the slowest pinning cursor: min(sent) over cursors that are active and not shed, or tail when no such cursor exists.
int moqtrel_should_hold (const moqtrel_buf *b)
 Decide publisher backpressure: 1 when free space fell below two receive windows (2 * WIRED_SRVLOOP_WT_BUF_CAP) and the hold is not yet applied.
int moqtrel_should_release (const moqtrel_buf *b)
 Decide backpressure release: 1 when a hold is applied and used bytes drained to at most half a receive window.
int moqtrel_stalled (const moqtrel_buf *b, u32 sub, u64 now_ms)
 Stall check for subscriber sub: 1 when it is active, not shed, has pending bytes, and its last accepted send is more than WIRED_MOQTREL_STALL_MS before now_ms.
int moqtrel_awaits_sub (const moqtrel_buf *b, u64 now_ms)
 Late-subscriber wait: 1 while no cursor ever attached (head is still 0, so the ring holds the stream from its first byte), the publisher's FIN has not arrived, and the ring was bound at most WIRED_MOQTREL_STALL_MS before now_ms – keep the ring bound so a subscriber activated mid-stream can still read it all.
int moqtrel_all_done (const moqtrel_buf *b)
 Completion check: 1 when every active cursor is shed or fin_done (so the ring can go back to the pool).

Detailed Description

Reliable-relay byte ring for the MOQT hub: one publisher's relayed track bytes buffered once, with an independent read cursor per subscriber, so a slow subscriber's refused sends are retried instead of dropped.

This module only keeps state and makes decisions (what span to send next, when to hold/release the publisher's receive credit, which subscriber has stalled); it performs no io. The hub calls the decision functions and acts on them through its wired_moqt_io table.

head and tail are absolute, monotonically increasing byte offsets; the physical ring index is offset % WIRED_MOQTREL_CAP. used = tail - head, free = CAP - used.

Macro Definition Documentation

◆ WIRED_MOQTREL_CAP

#define WIRED_MOQTREL_CAP   ((u64)3 * WIRED_SRVLOOP_WT_BUF_CAP)

Ring capacity in bytes.

Three publisher receive windows: one the publisher may already have in flight when the hold lands, one advertised on top of it, one of slack so held data never overflows the ring.

◆ WIRED_MOQTREL_HEADROOM

#define WIRED_MOQTREL_HEADROOM   (WIRED_MOQTRUN_RELAY_FRAG_MAX + WIRED_SRVLOOP_WT_BUF_CAP + 16)

Session send credit (WT_MAX_DATA remaining) a reliable-relay round must leave unspent, so one lossy screen-share round on the SAME session still fits: a held fragment plus one receive window of delivered bytes plus 16 for the adapter's signal prefix, which the hub never sees.

WIRED_MOQTRUN_RELAY_FRAG_MAX comes from this header's includer (moqtrun.h), so this macro expands only past that point (moqtrun.c and its tests) – the same include-order note as WIRED_MOQTREL_MAX_SUBS. This is the same WIRED_MOQTRUN_RELAY_FRAG_MAX + WIRED_SRVLOOP_WT_BUF_CAP quantity srvrun.c's SRVRUN_WTSEND_BUF sizing comment computes independently (srvrun.c never includes moqtrun.h, so the two cannot share one macro); keep both comments in sync if either term changes.

◆ WIRED_MOQTREL_MAX_SUBS

#define WIRED_MOQTREL_MAX_SUBS   31

Fixed capacity: subscriber cursors per ring.

Mirrors WIRED_MOQTRUN_MAX_SUBS (moqtrun.h includes this header, so the value is repeated here instead of the macro; moqtrun.h asserts the two stay equal once both are in scope).

Function Documentation

◆ moqtrel_age_ms()

u64 moqtrel_age_ms ( const moqtrel_buf * b,
u32 sub,
u64 now_ms )

How long ago subscriber sub's next unsent byte arrived (draft-ietf- moq-transport-19 8, the age OBJECT_DELIVERY_TIMEOUT is checked against).

Parameters
bthe ring
subsubscriber index
now_mscurrent time in ms
Returns
age in ms, 0 when the subscriber is caught up.

◆ moqtrel_all_done()

int moqtrel_all_done ( const moqtrel_buf * b)

Completion check: 1 when every active cursor is shed or fin_done (so the ring can go back to the pool).

Parameters
bthe ring
Returns
1 done, 0 otherwise.

◆ moqtrel_append()

int moqtrel_append ( moqtrel_buf * b,
wired_span src )

Append src's bytes at tail (wrapping physically at CAP).

Parameters
bthe ring
srcbytes to copy in
Returns
1 appended, 0 if src would exceed free space (nothing written; the caller counts the overflow – by design this never happens while the hold watermark is respected).

◆ moqtrel_awaits_sub()

int moqtrel_awaits_sub ( const moqtrel_buf * b,
u64 now_ms )

Late-subscriber wait: 1 while no cursor ever attached (head is still 0, so the ring holds the stream from its first byte), the publisher's FIN has not arrived, and the ring was bound at most WIRED_MOQTREL_STALL_MS before now_ms – keep the ring bound so a subscriber activated mid-stream can still read it all.

Parameters
bthe ring
now_mscurrent time in ms
Returns
1 keep waiting, 0 otherwise.

◆ moqtrel_mark()

void moqtrel_mark ( moqtrel_buf * b,
u64 now_ms )

Record that every byte up to tail has arrived by now_ms; call after each moqtrel_append.

Same-ms appends share a mark. ponytail: with every mark taken, the newest mark absorbs the append and keeps its own time, so the absorbed bytes read older than they are – a timeout can fire early, by at most the time since that mark; raise WIRED_MOQTREL_MARKS if a lagging cursor's timeouts must be exact over more appends.

Parameters
bthe ring
now_mscurrent time in ms

◆ moqtrel_next_round()

wired_span moqtrel_next_round ( const moqtrel_buf * b,
u32 sub )

The next contiguous slice to send to subscriber sub: starts at its sent cursor, length capped by pending bytes (tail - sent), by WIRED_MOQTREL_ROUND_MAX, and by the physical ring end.

Parameters
bthe ring
subsubscriber index
Returns
a view into the ring; .n == 0 when the subscriber is caught up.

◆ moqtrel_note_sent()

void moqtrel_note_sent ( moqtrel_buf * b,
u32 sub,
usz n,
u64 now_ms )

Record an accepted send: sub's cursor advances by n and its stall clock restarts at now_ms.

Parameters
bthe ring
subsubscriber index
nbytes the accepted round carried
now_mscurrent time in ms

◆ moqtrel_reclaim()

void moqtrel_reclaim ( moqtrel_buf * b)

Advance head to the slowest pinning cursor: min(sent) over cursors that are active and not shed, or tail when no such cursor exists.

Parameters
bthe ring

◆ moqtrel_reset()

void moqtrel_reset ( moqtrel_buf * b)

Empty b: offsets zero, no publisher, every cursor inactive.

Parameters
bthe ring to reset

◆ moqtrel_should_hold()

int moqtrel_should_hold ( const moqtrel_buf * b)

Decide publisher backpressure: 1 when free space fell below two receive windows (2 * WIRED_SRVLOOP_WT_BUF_CAP) and the hold is not yet applied.

Parameters
bthe ring
Returns
1 to hold now, 0 otherwise.

◆ moqtrel_should_release()

int moqtrel_should_release ( const moqtrel_buf * b)

Decide backpressure release: 1 when a hold is applied and used bytes drained to at most half a receive window.

Parameters
bthe ring
Returns
1 to release now, 0 otherwise.

◆ moqtrel_stalled()

int moqtrel_stalled ( const moqtrel_buf * b,
u32 sub,
u64 now_ms )

Stall check for subscriber sub: 1 when it is active, not shed, has pending bytes, and its last accepted send is more than WIRED_MOQTREL_STALL_MS before now_ms.

Parameters
bthe ring
subsubscriber index
now_mscurrent time in ms
Returns
1 stalled (shed it), 0 otherwise.