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

RFC 9001 4 / 5 / RFC 9000 17.2: the socket-free core of the server wire loop. More...

#include "app/http3/core/h3/control.h"
#include "app/http3/core/h3/priority.h"
#include "app/http3/core/h3settings/control_settings.h"
#include "app/http3/request/h3reqdrive/request_drive.h"
#include "app/http3/server/h3srv/state.h"
#include "app/http3/server/srvloop/body_window.h"
#include "common/bytes/span/span.h"
#include "tls/ext/stp/server_tp.h"
#include "tls/handshake/roles/server/server.h"
#include "transport/conn/pnspace/pnspaces/recv_spaces.h"
#include "transport/packet/frame/frame/connctl.h"
#include "transport/packet/frame/frame/ncid.h"
#include "transport/recovery/detect/recovery/ackpolicy.h"

Go to the source code of this file.

Data Structures

struct  wired_srvloop_stream_slot
 One request stream's cross-datagram reassembly state — everything the original single-stream wired_srvloop held, now per stream id. More...
struct  wired_srvloop_pending_priority
 One buffered PRIORITY_UPDATE naming a request stream this connection has not opened yet (RFC 9218 10 / 9218-010). More...
struct  wired_srvloop_ctrl_stream
 The peer's control stream, reassembled across datagrams (RFC 9000 2.2) past its leading type varint, so its HTTP/3 frames (SETTINGS, GOAWAY, PRIORITY_UPDATE, ...) can be walked once fully buffered up to parsed. More...
struct  wired_srvloop_wt_window
 One WT bidi/uni slot's receive-window bookkeeping, shared shape for both tables (see wired_srvloop_wt_stream_slot / _uni_stream_slot below). More...
struct  wired_srvloop_wt_stream_slot
 One WebTransport bidi stream's cross-datagram reassembly state (draft- ietf-webtrans-http3-15 4.3). More...
struct  wired_srvloop_wt_uni_stream_slot
 One WebTransport uni stream's cross-datagram reassembly state (draft-ietf- webtrans-http3-15 4.3). More...
struct  wired_srvloop_rx_datagram
 One queued received QUIC DATAGRAM frame's payload (RFC 9221 5). More...
struct  wired_srvloop_closed
 RFC 9000 3.2: closed client stream indexes (id / 4) of one stream type – every index below floor, plus the 1024 just above it in bm (bit k = index floor + k). More...
struct  wired_srvloop_reset
 One peer RESET_STREAM (is_stop 0) or STOP_SENDING (is_stop 1). More...
struct  wired_srvloop
 Per-connection state of the server wire loop, re-armed by wired_srvloop_init and driven by wired_srvloop_step. More...
struct  wired_srvloop_conn
 The loop and its orchestrator, driven together through every wire step (mirrors wired_srvboot_conn, srvboot's cold-start counterpart). More...

Macros

#define WIRED_SRVLOOP_MAX_ACK_DELAY_MS   25
 RFC 9000 18.2's default max_ack_delay when the peer's own transport parameter isn't tracked (this SDK does not parse the client's max_ack_delay yet – YAGNI until a deployment needs a non-default value).
#define WIRED_SRVLOOP_NCID_RX   4
 NEW_CONNECTION_ID frames kept per step (wired_srvloop.ncid_rx); more are dropped – the peer may issue at most active_connection_id_limit.
#define WIRED_SRVLOOP_PATH_RX   2
 PATH_CHALLENGE frames latched until answered (wired_srvloop.path_challenge_rx_data); more are dropped.
#define WIRED_SRVLOOP_MAX_STREAMS   40
 RFC 9000 2.2: how many client bidi (request) streams one connection can reassemble concurrently.
#define WIRED_SRVLOOP_MAX_PENDING_PRIORITY   8
 RFC 9218 7.1 / 10: how many PRIORITY_UPDATE frames naming a not-yet-open request stream one connection buffers (9218-010) until that stream is claimed.
#define WIRED_SRVLOOP_CTRL_BUF_CAP   512
 Byte capacity of the peer control stream's reassembly buffer (RFC 9114 6.2.1, RFC 9218 7.1).
#define WIRED_SRVLOOP_MAX_WT_STREAMS   24
 RFC 9000 2.2: how many concurrent WebTransport bidi streams (draft-ietf- webtrans-http3-15 4.3) one connection can reassemble.
#define WIRED_SRVLOOP_WT_BUF_CAP   49152
 Byte capacity of one WT bidi/uni reassembly slot's receive window (buf below).
#define WIRED_SRVLOOP_WT_MAX_RANGES   8
 How many disjoint received-but-not-yet-contiguous byte ranges one WT slot's window tracks past its frontier (see wired_srvloop_wt_window).
#define WIRED_SRVLOOP_MAX_WT_UNI_STREAMS   9
 draft-ietf-webtrans-http3-15 4.3: how many concurrent WebTransport uni streams (client-initiated, RFC 9000 2.1 low bits 10) one connection can reassemble.
#define WIRED_SRVLOOP_MAX_RX_DATAGRAMS   256
 RFC 9221 5: how many received QUIC DATAGRAM frames one connection queues before a future consumer (a WebTransport session, Phase 7b Slice 2) drains them.
#define WIRED_SRVLOOP_RX_DATAGRAM_CAP   1200
 Byte capacity of one queued received QUIC DATAGRAM's payload (RFC 9221 5/3).
#define WIRED_SRVLOOP_RESET_Q
 RFC 9000 19.4/19.5: peer RESET_STREAM/STOP_SENDING frames one step can queue.

Typedefs

typedef int(* wired_srvloop_handler) (void *ctx, const wired_h3reqdrive_req *req, u64 offset, wired_obuf *body_out, const char **content_type, int *more, u64 *total_size)
 Build (a round of) the response body for a decoded request.
typedef int(* wired_srvloop_on_body) (void *ctx, const wired_h3reqdrive_req *req, u64 stream_id, wired_span chunk, int fin)
 Receive a request body as it streams in (RFC 9114 4.1), instead of having it buffered whole into req's body (limited to one request window, BODYWIN_CAP bytes, larger bodies answered 413).

Functions

static u64 wired_srvloop_stream_limit (u64 configured)
 Advertised initial_max_streams_bidi resolved from configured (0 = the built-in default) and clamped to the reassembly-table capacity above.
static u64 wired_srvloop_uni_stream_limit (void)
 RFC 9000 4.6: the client-initiated UNI stream limit the server initially advertises, sized to what its receive side actually backs – the same lockstep rule wired_srvloop_stream_limit applies to bidi.
void wired_srvloop_closed_mark (wired_srvloop_closed *w, u64 stream_id)
 Record stream_id's id-space index in w (see srvloop.c's closed-set doc: exact ids over a sliding 1024-index window; an id past the window slides it up, counting every index left behind as recorded).
int wired_srvloop_closed_has (const wired_srvloop_closed *w, u64 stream_id)
 1 if stream_id's index is recorded in w (or below its window).
void wired_srvloop_set_handler (wired_srvloop *l, wired_srvloop_handler cb, void *ctx)
 Register the app response-body builder; pass 0 to clear (body-less 200).
int wired_srvloop_init (wired_srvloop *l, const u8 *cli_scid, u8 cli_scid_len)
 Record the client's source connection id (the DCID for server-sent packets) and reset the HTTP/3 state.
int wired_srvloop_slot_for (wired_srvloop *l, u64 stream_id)
 RFC 9000 2.2: the streams[] slot reassembling request stream_id, allocating a free one on first sight – dispatch.c routes each request STREAM frame to its own stream's slot through this (a payload may coalesce frames of several request streams).
void wired_srvloop_priority_apply (wired_srvloop *l, u64 stream_id, const h3_priority *p)
 RFC 9218 7.1 / 10: apply a validated PRIORITY_UPDATE (request variant) to stream_id – directly into its streams[] slot if already open, else buffered in pending_priority[] until wired_srvloop_slot_for later claims that stream id (9218-010).
int wired_srvloop_priority_of (const wired_srvloop *l, u64 stream_id, h3_priority *out)
 RFC 9218 10: read stream_id's current priority (its RFC 9218 4.1 default until any PRIORITY_UPDATE or Priority header field changed it) without allocating a streams[] slot – the counterpart read used by a response scheduler (srvrun.c) ordering its send passes, as opposed to wired_srvloop_slot_for's claim-or-allocate used by the receive path.
void wired_srvloop_slot_release (wired_srvloop *l, u64 stream_id)
 RFC 9000 2.2: free the streams[] slot reassembling stream_id, once its response has been fully sent and acknowledged – called by the response driver (srvrun.c) so a stream id's slot becomes reusable for a later request.
int wired_srvloop_wt_slot_find (const wired_srvloop *l, u64 stream_id)
 draft-ietf-webtrans-http3-15 4.3: find the wt_streams slot already reassembling stream_id, so dispatch.c's gather_wt_stream can route a later (offset>0) frame into the same slot its signal frame claimed.
int wired_srvloop_wt_slot_claim (wired_srvloop *l, u64 stream_id)
 draft-ietf-webtrans-http3-15 4.3: claim and reset a free wt_streams slot for stream_id, called the first time a stream's leading 0x41 signal is recognized.
int wired_srvloop_wt_uni_slot_find (const wired_srvloop *l, u64 stream_id)
 draft-ietf-webtrans-http3-15 4.3: find the wt_uni_streams slot already reassembling stream_id, mirroring wired_srvloop_wt_slot_find for the separate uni table.
int wired_srvloop_wt_uni_slot_claim (wired_srvloop *l, u64 stream_id)
 draft-ietf-webtrans-http3-15 4.3: claim and reset a free wt_uni_streams slot for stream_id, called the first time a uni stream's leading type varint is recognized as 0x54, mirroring wired_srvloop_wt_slot_claim.
int wired_srvloop_wt_slot_claim_local (wired_srvloop *l, u64 stream_id)
 RFC 9000 2.1: pre-claim a wt_streams slot for a stream id THIS endpoint itself opened (a server-initiated bidi stream, id bits 01) – unlike wired_srvloop_wt_slot_claim, called before any frame for stream_id has arrived, with sig_len left 0 (no signal prefix: the peer's reply is raw application data from its own offset 0).
void wired_srvloop_wt_refuse (wired_srvloop *l, u64 stream_id)
 RFC 9114 8.1: queue client WT bidi stream_id for refusal (wt_refused) because no slot was free – unless it is a retransmission of a stream already released or refused.
void wired_srvloop_wt_slot_release (wired_srvloop *l, u64 stream_id)
 draft-ietf-webtrans-http3-15 4.3: free the wt_streams[] slot reassembling stream_id once its FIN has been fully delivered to the app, mirroring wired_srvloop_slot_release for the WT bidi table.
void wired_srvloop_wt_uni_slot_release (wired_srvloop *l, u64 stream_id)
 Same as wired_srvloop_wt_slot_release, for the separate wt_uni_streams table.
void wired_srvloop_wt_window_accept (wired_srvloop_wt_window *win, u64 abs_off, usz n, usz *rel_off, usz *accepted_n)
 draft-ietf-webtrans-http3-15 4.3: clamp [abs_off, abs_off+n) to win's currently open window (drop the stale prefix already delivered/below win.base, and the part beyond win.base + WIRED_SRVLOOP_WT_BUF_CAP the peer has no granted credit for yet) and record the accepted portion into win's range set, recomputing win.frontier.
void wired_srvloop_wt_window_slide (wired_srvloop_wt_window *win, u8 *buf, usz cap, u64 delivered_to)
 draft-ietf-webtrans-http3-15 4.3 / RFC 9000 4.1: once delivered_to (an absolute offset, srvrun.c's own delivered_len) has consumed the whole current frontier, slide the window forward so buf has room for more – shift any bytes still buffered past the frontier (an out-of-order continuation already written ahead of a since-filled gap) down to buf[0], advance win.base by the delivered frontier, and rebase every range in win.ranges by the same amount.
int wired_srvloop_step (const wired_srvloop_conn *conn, wired_mspan dgram, wired_obuf *out)
 Drive one wire iteration: open dgram, dispatch it, and if the step produced a server-direction packet (HANDSHAKE_DONE once confirmed, or a 200 response to a decoded GET) seal it into out, setting out->len.
void wired_srvloop_ecn_note (wired_srvloop *l, u8 ecn)
 RFC 9000 13.4 / RFC 9002 19.3.2: add one received datagram's ECN codepoint (RFC 3168: 0 Not-ECT, 1 ECT(1), 2 ECT(0), 3 CE, matching mmsg_buf.ecn in udp.h) to l's cumulative counts, which app_ack_encode_ranges (respond.c) later reports in the connection's 1-RTT ACK frames.

Detailed Description

RFC 9001 4 / 5 / RFC 9000 17.2: the socket-free core of the server wire loop.

One step opens an inbound datagram with the peer-direction key, dispatches its frames to the handshake or HTTP/3 layer, and seals the resulting outbound packet with the server's own-direction key for the level the conversation has reached. An example program wraps this in a UDP recv/send.

Macro Definition Documentation

◆ WIRED_SRVLOOP_CTRL_BUF_CAP

#define WIRED_SRVLOOP_CTRL_BUF_CAP   512

Byte capacity of the peer control stream's reassembly buffer (RFC 9114 6.2.1, RFC 9218 7.1).

Holds the stream's bytes AFTER the leading 0x00 type varint – SETTINGS plus any number of PRIORITY_UPDATE frames comfortably fit; a real peer's control stream is a handful of small frames, not a bulk transfer, so this need not match a WT stream's throughput-sized window.

◆ WIRED_SRVLOOP_MAX_ACK_DELAY_MS

#define WIRED_SRVLOOP_MAX_ACK_DELAY_MS   25

RFC 9000 18.2's default max_ack_delay when the peer's own transport parameter isn't tracked (this SDK does not parse the client's max_ack_delay yet – YAGNI until a deployment needs a non-default value).

Matches srvrun.c's own SRVRUN_MAX_ACK_DELAY_US (25000us = 25ms); kept as a separate constant here since srvloop must not depend on srvrun.

◆ WIRED_SRVLOOP_MAX_PENDING_PRIORITY

#define WIRED_SRVLOOP_MAX_PENDING_PRIORITY   8

RFC 9218 7.1 / 10: how many PRIORITY_UPDATE frames naming a not-yet-open request stream one connection buffers (9218-010) until that stream is claimed.

Small and fixed: a client reprioritizing a stream ahead of opening it is a corner case, not a bulk pattern, so this need not track WIRED_SRVLOOP_MAX_STREAMS' own sizing.

◆ WIRED_SRVLOOP_MAX_RX_DATAGRAMS

#define WIRED_SRVLOOP_MAX_RX_DATAGRAMS   256

RFC 9221 5: how many received QUIC DATAGRAM frames one connection queues before a future consumer (a WebTransport session, Phase 7b Slice 2) drains them.

Datagrams are unordered/unreliable per RFC 9221, so — unlike the single-slot send side — the receive side uses a small fixed queue rather than one overwritable slot: losing an already-arrived datagram to a same-step overwrite is a worse user-visible bug than the send side's "last write wins" (see rx_datagram_n's overflow policy below). Sized to a full receive batch of coalesced tiny datagrams: 16 packets per step (srvrun's receive batch) x ~16 sub-80-byte frames per 1252-byte packet. A real client (flupke's transfer-datagram-receive) coalesces ~9 "GET <file>" datagrams per packet and fires 200 in one burst; the old depth of 4 dropped 129 of them with zero network loss.

◆ WIRED_SRVLOOP_MAX_STREAMS

#define WIRED_SRVLOOP_MAX_STREAMS   40

RFC 9000 2.2: how many client bidi (request) streams one connection can reassemble concurrently.

40, not a handful: quic-interop-runner's zerortt testcase (TestCaseZeroRTT.NUM_FILES) opens 40 concurrent request streams in a single 0-RTT/1-RTT burst – a client that fires them all up front (quic-go does) never retries a stream this SDK's own slot table dropped, so anything short of 40 silently loses requests past the cap forever. Overridable at build time (-DWIRED_SRVLOOP_MAX_STREAMS=N); 40 is the floor the zerortt testcase demands.

◆ WIRED_SRVLOOP_MAX_WT_STREAMS

#define WIRED_SRVLOOP_MAX_WT_STREAMS   24

RFC 9000 2.2: how many concurrent WebTransport bidi streams (draft-ietf- webtrans-http3-15 4.3) one connection can reassemble.

Separate from WIRED_SRVLOOP_MAX_STREAMS/wired_srvloop_stream_slot: a WT bidi stream's bytes past the leading 0x41 signal are raw application data with no HTTP/3 HEADERS/DATA framing, so they need no req_scratch/req_wrap-shaped fields. 24: a MoQT session (draft-ietf-moq-transport-19) keeps one request stream open per live PUBLISH / SUBSCRIBE / PUBLISH_NAMESPACE / SUBSCRIBE_NAMESPACE – a 4-person moqt_chat room needs ~16 per browser plus the server's control stream. A stream past the table is refused on the wire (wt_refused below), never dropped. Each slot owns one WIRED_SRVLOOP_WT_BUF_CAP window, so this is the main per-connection BSS knob: overridable per build (-DWIRED_SRVLOOP_MAX_WT_STREAMS=N).

◆ WIRED_SRVLOOP_MAX_WT_UNI_STREAMS

#define WIRED_SRVLOOP_MAX_WT_UNI_STREAMS   9

draft-ietf-webtrans-http3-15 4.3: how many concurrent WebTransport uni streams (client-initiated, RFC 9000 2.1 low bits 10) one connection can reassemble.

Separate table from wt_streams[] (bidi): a uni stream's directionality is structurally different (no response half), even though its post-type-byte bytes are raw application data just like a WT bidi stream's post-signal bytes. Sized to the whole advertised uni limit (wired_srvloop_uni_stream_limit, 9): an HTTP/3 client spends 3 of it on its control/QPACK streams and gets 6 WT data streams (5 concurrent runner transfers), but a raw-QUIC client (draft-ietf-moq-transport-19 3.3, one uni stream per MoQT subgroup) has no plumbing and may hold all 9 open as data streams at once – with only 6 slots the last 3 would be ACKed yet land nowhere (RawQuic plan K3). Cost: 3 more WIRED_SRVLOOP_WT_BUF_CAP windows per connection.

◆ WIRED_SRVLOOP_RESET_Q

#define WIRED_SRVLOOP_RESET_Q
Value:
#define WIRED_SRVLOOP_MAX_WT_STREAMS
RFC 9000 2.2: how many concurrent WebTransport bidi streams (draft-ietf- webtrans-http3-15 4....
Definition srvloop.h:237
#define WIRED_SRVLOOP_MAX_WT_UNI_STREAMS
draft-ietf-webtrans-http3-15 4.3: how many concurrent WebTransport uni streams (client-initiated,...
Definition srvloop.h:397
#define WIRED_SRVLOOP_MAX_STREAMS
RFC 9000 2.2: how many client bidi (request) streams one connection can reassemble concurrently.
Definition srvloop.h:117
u64 usz
unsigned size (size_t equivalent)
Definition types.h:20

RFC 9000 19.4/19.5: peer RESET_STREAM/STOP_SENDING frames one step can queue.

Every stream slot this loop tracks (request, WT bidi, WT uni) can draw at most one RESET_STREAM and one STOP_SENDING, so two per slot holds a peer tearing down everything in one packet; more than that is a flood (the caller closes with H3_EXCESSIVE_LOAD on overflow).

◆ WIRED_SRVLOOP_RX_DATAGRAM_CAP

#define WIRED_SRVLOOP_RX_DATAGRAM_CAP   1200

Byte capacity of one queued received QUIC DATAGRAM's payload (RFC 9221 5/3).

1200 comfortably covers a max_datagram_frame_size-bounded HTTP Datagram (RFC 9297 2.1: quarter-stream-id varint, up to 8 bytes, plus up to ~998 bytes of application payload under a typical ~1200-byte max_datagram_frame_size) without truncating it on receive.

◆ WIRED_SRVLOOP_WT_BUF_CAP

#define WIRED_SRVLOOP_WT_BUF_CAP   49152

Byte capacity of one WT bidi/uni reassembly slot's receive window (buf below).

Sized past one full BDP for quic-interop-runner's simulated link (10Mbps/30ms RTT is ~37KB) so a single WT stream's throughput is not window-capped – with 5 streams sharing one connection's fair share of that link, a smaller window left several of quic-interop-runner's WebTransport send-mode transfer tests short of finishing inside its fixed per-test timeout (verified against a real webtransport-go run). Used to be kept at 4KB because wired_srvloop is embedded in srvrun_conn (6 bidi + 6 uni slots), and srvrun_test.c's test helpers used to stack-allocate a whole WIRED_CONNTABLE_CAP-sized connection table each – that allocation has since moved to static storage (matching production's own g_srvrun_env singleton, which was never on the stack to begin with), so this can now size for throughput instead of a stack budget it no longer shares. Overridable per build (-D flag) – but the advertised per-stream windows (STP_DEFAULT_STREAM_DATA_LOCAL, server_tp.h) are a promise backed by exactly this capacity, so any override must change both together (server_tp_test.c pins them equal).

◆ WIRED_SRVLOOP_WT_MAX_RANGES

#define WIRED_SRVLOOP_WT_MAX_RANGES   8

How many disjoint received-but-not-yet-contiguous byte ranges one WT slot's window tracks past its frontier (see wired_srvloop_wt_window).

RFC 9000 2.2 reassembly is offset-indexed and reordering-tolerant by design, so a lost-then-retransmitted frame routinely lands after a gap; a small fixed set (rather than one high-water mark) is what lets the frontier — and therefore delivery — advance correctly once the gap fills, instead of silently skipping the buffered-but-undelivered bytes past it.

Typedef Documentation

◆ wired_srvloop_handler

typedef int(* wired_srvloop_handler) (void *ctx, const wired_h3reqdrive_req *req, u64 offset, wired_obuf *body_out, const char **content_type, int *more, u64 *total_size)

Build (a round of) the response body for a decoded request.

Copy from req (its body is a view into per-step scratch, not valid past the call) into body_out, setting body_out->len. May set *content_type to a static NUL-terminated string to add a content-type field line; left unchanged (0) omits it.

offset is the count of response body bytes already delivered by prior rounds (0 on the first call for a request). A handler whose whole body fits in one round ignores offset and never touches *more or *total_size (both default to "done"/"unknown"): this is the common case and every existing handler's behavior is unchanged. A handler with more body than fits body_out's capacity writes as much as fits starting at offset, sets *more = 1, and (on the first round only, offset == 0) sets *total_size to the full body length if known – callers that frame the body with an upfront length field (e.g. HTTP/3's DATA frame) need this to write that length before any bytes are available. The caller then invokes this handler again with offset advanced by the bytes it just produced, repeating until *more is left 0.

Parameters
ctxthe opaque context registered with wired_srvloop_set_handler
reqthe decoded request; its views are not valid past the call
offsetresponse body bytes already delivered by prior rounds
body_outreceives this round's response body bytes
content_typereceives the content-type string, or left at its caller-supplied value (0) to omit the field line (only consulted on the first round, offset == 0)
morecaller-zeroed before the call; set to 1 to request another round starting at offset + body_out->len
total_sizecaller-zeroed before the call; on the first round (offset == 0) only, set to the full body length if known up front
Returns
1 to send the body, 0 for a body-less 200.

◆ wired_srvloop_on_body

typedef int(* wired_srvloop_on_body) (void *ctx, const wired_h3reqdrive_req *req, u64 stream_id, wired_span chunk, int fin)

Receive a request body as it streams in (RFC 9114 4.1), instead of having it buffered whole into req's body (limited to one request window, BODYWIN_CAP bytes, larger bodies answered 413).

Sequencing, per request stream (CONNECT excepted, its stream carries capsules): once the HEADERS frame is whole, req is decoded (method, path, headers; req->body stays empty) and every DATA payload byte is passed here in order, in chunks that never cross a frame. The call that ends the body has fin=1 – an empty chunk when the body is empty or ends in a non-DATA frame. Only after fin=1 does the response handler run, with the same request. Returning 0 stops the body: no further call for the stream (no fin), the client is asked to stop sending, and the response is 413 (the handler is not called). A stream that ends inside a frame closes the connection with H3_FRAME_ERROR (RFC 9114 7.1); fin=1 never arrives.

Parameters
ctxthe context registered with wired_srvloop_set_handler
reqthe decoded request; valid until its response is reaped
stream_idthe request stream
chunkbody bytes, valid only during the call
fin1 on the last call for the stream
Returns
1 to keep receiving, 0 to stop and answer 413

Function Documentation

◆ wired_srvloop_ecn_note()

void wired_srvloop_ecn_note ( wired_srvloop * l,
u8 ecn )

RFC 9000 13.4 / RFC 9002 19.3.2: add one received datagram's ECN codepoint (RFC 3168: 0 Not-ECT, 1 ECT(1), 2 ECT(0), 3 CE, matching mmsg_buf.ecn in udp.h) to l's cumulative counts, which app_ack_encode_ranges (respond.c) later reports in the connection's 1-RTT ACK frames.

The caller driving the UDP receive loop (e.g. srvrun.c) calls this once per received datagram, ahead of or alongside wired_srvloop_step – the two are independent calls since wired_srvloop_step's dgram argument carries no ECN information itself. A Not-ECT (0) codepoint is a no-op: it advances none of the three counters.

Parameters
lthe loop whose cumulative counts to advance
ecnthe received datagram's ECN codepoint (0..3)

◆ wired_srvloop_init()

int wired_srvloop_init ( wired_srvloop * l,
const u8 * cli_scid,
u8 cli_scid_len )

Record the client's source connection id (the DCID for server-sent packets) and reset the HTTP/3 state.

Parameters
lthe loop to initialize
cli_scidthe client's source connection id
cli_scid_lencli_scid length in octets
Returns
1, or 0 if cli_scid_len exceeds 20.

◆ wired_srvloop_priority_apply()

void wired_srvloop_priority_apply ( wired_srvloop * l,
u64 stream_id,
const h3_priority * p )

RFC 9218 7.1 / 10: apply a validated PRIORITY_UPDATE (request variant) to stream_id – directly into its streams[] slot if already open, else buffered in pending_priority[] until wired_srvloop_slot_for later claims that stream id (9218-010).

A stream id that is neither open nor buffered anywhere is simply added to (or overwrites its own entry in) pending_priority[]; a full pending table drops the update, same truncate-on-overflow policy family as this file's other fixed tables.

Parameters
lthe loop to apply into
stream_idthe client bidi request stream id the update names
pthe priority to apply (already decoded/validated by the caller)

◆ wired_srvloop_priority_of()

int wired_srvloop_priority_of ( const wired_srvloop * l,
u64 stream_id,
h3_priority * out )

RFC 9218 10: read stream_id's current priority (its RFC 9218 4.1 default until any PRIORITY_UPDATE or Priority header field changed it) without allocating a streams[] slot – the counterpart read used by a response scheduler (srvrun.c) ordering its send passes, as opposed to wired_srvloop_slot_for's claim-or-allocate used by the receive path.

Parameters
lthe loop whose streams[] table to search
stream_idthe client bidi request stream id
outreceives the priority, valid only when 1 is returned
Returns
1 if stream_id has an open streams[] slot, 0 otherwise.

◆ wired_srvloop_set_handler()

void wired_srvloop_set_handler ( wired_srvloop * l,
wired_srvloop_handler cb,
void * ctx )

Register the app response-body builder; pass 0 to clear (body-less 200).

Parameters
lthe loop to register on
cbthe response-body builder, 0 to clear
ctxopaque context handed back to cb

◆ wired_srvloop_slot_for()

int wired_srvloop_slot_for ( wired_srvloop * l,
u64 stream_id )

RFC 9000 2.2: the streams[] slot reassembling request stream_id, allocating a free one on first sight – dispatch.c routes each request STREAM frame to its own stream's slot through this (a payload may coalesce frames of several request streams).

Parameters
lthe loop whose streams[] table to search/claim
stream_idthe client bidi request stream id
Returns
the slot index; -2 when the stream was already answered and released (RFC 9000 3.2: a late duplicate, its frames are discarded without claiming anything); or -1 when the table is full (the stream's frames are dropped, same as the old fixed capacity of one).

◆ wired_srvloop_slot_release()

void wired_srvloop_slot_release ( wired_srvloop * l,
u64 stream_id )

RFC 9000 2.2: free the streams[] slot reassembling stream_id, once its response has been fully sent and acknowledged – called by the response driver (srvrun.c) so a stream id's slot becomes reusable for a later request.

HTTP/3 never reuses a stream id, so without this the table's WIRED_SRVLOOP_MAX_STREAMS slots exhaust permanently after that many sequential requests on distinct streams.

Parameters
lthe loop whose streams[] table to release from
stream_idthe client bidi request stream id; a no-op if it has no slot.

◆ wired_srvloop_step()

int wired_srvloop_step ( const wired_srvloop_conn * conn,
wired_mspan dgram,
wired_obuf * out )

Drive one wire iteration: open dgram, dispatch it, and if the step produced a server-direction packet (HANDSHAKE_DONE once confirmed, or a 200 response to a decoded GET) seal it into out, setting out->len.

Parameters
connthe loop/orchestrator pair to drive
dgramthe inbound datagram to open and dispatch
outreceives the sealed outbound packet, when one is produced
Returns
1 if an outbound packet was written, 0 if the step produced none (or the input was dropped).

◆ wired_srvloop_stream_limit()

u64 wired_srvloop_stream_limit ( u64 configured)
inlinestatic

Advertised initial_max_streams_bidi resolved from configured (0 = the built-in default) and clamped to the reassembly-table capacity above.

Advertising more streams than the table can hold opens a silent-loss window: when loss delays the ACKs that release slots, a legitimately opened stream finds the table full, its frames land nowhere, and the carrying packet is still ACKed – so the peer never retransmits and the request is gone for good. The limit and the table must stay in lockstep.

◆ wired_srvloop_uni_stream_limit()

u64 wired_srvloop_uni_stream_limit ( void )
inlinestatic

RFC 9000 4.6: the client-initiated UNI stream limit the server initially advertises, sized to what its receive side actually backs – the same lockstep rule wired_srvloop_stream_limit applies to bidi.

An HTTP/3 client's fixed plumbing (control + QPACK encoder + decoder) holds three of these uni streams for the connection's whole life, a raw-QUIC client none; every other uni stream is application data reassembled in the wt_uni_streams[] slot table, which therefore backs the whole limit. Advertising more than the slots invites the documented full-table failure (see WIRED_SRVLOOP_MAX_STREAMS's doc): a loss-delayed burst of legitimate streams lands frames in no slot while their packets still ACK, so the peer never retransmits and the messages are gone for good. The limit grows by one per released slot (srvrun.c's uni re-grant), exactly like bidi.

◆ wired_srvloop_wt_refuse()

void wired_srvloop_wt_refuse ( wired_srvloop * l,
u64 stream_id )

RFC 9114 8.1: queue client WT bidi stream_id for refusal (wt_refused) because no slot was free – unless it is a retransmission of a stream already released or refused.

Marks it closed so its later frames are not read as an HTTP/3 request.

◆ wired_srvloop_wt_slot_claim()

int wired_srvloop_wt_slot_claim ( wired_srvloop * l,
u64 stream_id )

draft-ietf-webtrans-http3-15 4.3: claim and reset a free wt_streams slot for stream_id, called the first time a stream's leading 0x41 signal is recognized.

Parameters
lthe loop to claim a slot on
stream_idthe WT bidi stream id
Returns
the slot index, or -1 if the table is full.

◆ wired_srvloop_wt_slot_claim_local()

int wired_srvloop_wt_slot_claim_local ( wired_srvloop * l,
u64 stream_id )

RFC 9000 2.1: pre-claim a wt_streams slot for a stream id THIS endpoint itself opened (a server-initiated bidi stream, id bits 01) – unlike wired_srvloop_wt_slot_claim, called before any frame for stream_id has arrived, with sig_len left 0 (no signal prefix: the peer's reply is raw application data from its own offset 0).

Idempotent: a stream_id already claimed is returned unchanged rather than re-reset, so calling this once per wired_server_wt_open_bidi is safe even if a frame beat it to the slot in a pathological reordering.

Parameters
lthe loop to claim a slot on
stream_idthe server-initiated bidi stream id
Returns
the slot index, or -1 if the table is full.

◆ wired_srvloop_wt_slot_find()

int wired_srvloop_wt_slot_find ( const wired_srvloop * l,
u64 stream_id )

draft-ietf-webtrans-http3-15 4.3: find the wt_streams slot already reassembling stream_id, so dispatch.c's gather_wt_stream can route a later (offset>0) frame into the same slot its signal frame claimed.

Parameters
lthe loop to search
stream_idthe WT bidi stream id
Returns
the slot index, or -1 if this stream has no slot yet.

◆ wired_srvloop_wt_slot_release()

void wired_srvloop_wt_slot_release ( wired_srvloop * l,
u64 stream_id )

draft-ietf-webtrans-http3-15 4.3: free the wt_streams[] slot reassembling stream_id once its FIN has been fully delivered to the app, mirroring wired_srvloop_slot_release for the WT bidi table.

Also raises the table's released-id watermark (see wired_srvloop_wt_slot_claim's doc) so a late duplicate/reordered frame for this now-freed id is never mistaken for a fresh stream.

Parameters
lthe loop whose wt_streams[] table to release from
stream_idthe WT bidi stream id; a no-op if it has no slot.

◆ wired_srvloop_wt_uni_slot_claim()

int wired_srvloop_wt_uni_slot_claim ( wired_srvloop * l,
u64 stream_id )

draft-ietf-webtrans-http3-15 4.3: claim and reset a free wt_uni_streams slot for stream_id, called the first time a uni stream's leading type varint is recognized as 0x54, mirroring wired_srvloop_wt_slot_claim.

Parameters
lthe loop to claim a slot on
stream_idthe WT uni stream id
Returns
the slot index, or -1 if the table is full.

◆ wired_srvloop_wt_uni_slot_find()

int wired_srvloop_wt_uni_slot_find ( const wired_srvloop * l,
u64 stream_id )

draft-ietf-webtrans-http3-15 4.3: find the wt_uni_streams slot already reassembling stream_id, mirroring wired_srvloop_wt_slot_find for the separate uni table.

Parameters
lthe loop to search
stream_idthe WT uni stream id
Returns
the slot index, or -1 if this stream has no slot yet.

◆ wired_srvloop_wt_window_accept()

void wired_srvloop_wt_window_accept ( wired_srvloop_wt_window * win,
u64 abs_off,
usz n,
usz * rel_off,
usz * accepted_n )

draft-ietf-webtrans-http3-15 4.3: clamp [abs_off, abs_off+n) to win's currently open window (drop the stale prefix already delivered/below win.base, and the part beyond win.base + WIRED_SRVLOOP_WT_BUF_CAP the peer has no granted credit for yet) and record the accepted portion into win's range set, recomputing win.frontier.

The caller (dispatch.c) still owns the actual buf write, at *rel_off for *accepted_n bytes – this only answers "where, and how much".

Parameters
winthe slot's window to accept into
abs_offthe frame's absolute (post-signal) stream offset
nthe frame's byte count
rel_offset to the offset into buf to write the accepted bytes at
accepted_nset to how many trailing bytes of [abs_off, abs_off+n) fall inside the open window (0 if none do – entirely stale or entirely beyond the window)

◆ wired_srvloop_wt_window_slide()

void wired_srvloop_wt_window_slide ( wired_srvloop_wt_window * win,
u8 * buf,
usz cap,
u64 delivered_to )

draft-ietf-webtrans-http3-15 4.3 / RFC 9000 4.1: once delivered_to (an absolute offset, srvrun.c's own delivered_len) has consumed the whole current frontier, slide the window forward so buf has room for more – shift any bytes still buffered past the frontier (an out-of-order continuation already written ahead of a since-filled gap) down to buf[0], advance win.base by the delivered frontier, and rebase every range in win.ranges by the same amount.

A no-op if delivered_to has not yet reached win.base + win.frontier (nothing contiguous left to reclaim room for).

Parameters
winthe slot's window to slide
bufthe slot's own backing buffer (same one window offsets index)
capbuf's capacity (WIRED_SRVLOOP_WT_BUF_CAP)
delivered_tothe absolute offset delivered up to so far