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

The complete server event loop: the sanctioned socket-owning layer over the socket-free srvboot/srvloop core. More...

Go to the source code of this file.

Data Structures

struct  wired_wt_resource_decision
 draft-ietf-webtrans-http3-16 SS3.2 (WTH3-016/WTH3-018): the app's verdict for one Extended CONNECT's :authority/:path, filled in by a registered wired_wt_resource_check before the session is established. More...
struct  wired_http_exchange
 One request/response exchange handed to a wired_http_handler. More...
struct  wired_srvrun_handler
 The application's request responder: the callback and its opaque context, registered on the loop as a pair (wired_srvloop_set_handler takes the same pair). More...
struct  wired_srvrun_obs
 Optional debug-log file paths, each 0 to disable (the default): a qlog (RFC 9002-shaped packet_sent/packet_received events, JSON-SEQ framed) and an NSS key log (SSLKEYLOGFILE format) for decrypting a capture in Wireshark. More...
struct  wired_srvrun_opt
 Opt-in polling-driver knobs, both off (0) by default so wired_server_run's behavior is unchanged. More...
struct  wired_srvrun_wt_usage
 draft-ietf-webtrans-http3-15 SS8: WebTransport feature-usage totals for one env, monotonic since wired_srvrun_env_init – the operational visibility the draft asks servers to keep for anomaly detection. More...
struct  wired_wt_sched
 A server-sent stream's send class and its place inside a flow, set by wired_server_wt_stream_schedule (the MoQT hub's draft-ietf-moq-transport -22 7.2 order on top of the RFC 9218 urgency). More...
struct  wired_wt_occupancy
 Current WebTransport occupancy of the server loop the caller runs in, against the compile-time capacities – for an app exposing stats. More...

Macros

#define WIRED_HTTP_MAX_FIELDS   8
 Most response header fields one wired_http_handler round may set.
#define WIRED_HTTP_FIELD_BYTES_MAX   384
 Upper bound on the summed name, value and content_type bytes of one response's header fields, so the framed HEADERS always fits the response row's header room.

Typedefs

typedef struct wired_srvrun_env wired_srvrun_env
 Opaque: one server loop instance's mutable state (connection table, response/rx storage, pacing scratch).
typedef void(* wired_wt_on_datagram) (void *app_ctx, wired_wt_session *s, wired_span data)
 draft-ietf-webtrans-http3-15 SS4: app-facing delivery of one received QUIC DATAGRAM (RFC 9221 5) associated with a WebTransport session, drained from wired_srvloop's rx_datagrams queue once per connection step.
typedef void(* wired_wt_on_stream_data) (void *app_ctx, wired_wt_session *s, u64 stream_id, wired_span data, int fin)
 draft-ietf-webtrans-http3-15 4.3: app-facing delivery of one reassembled chunk of a WebTransport bidi/uni stream's bytes, drained from wired_srvloop's wt_streams/wt_uni_streams once per connection step.
typedef void(* wired_wt_on_stream_reset) (void *app_ctx, wired_wt_session *s, u64 stream_id, int mapped, u32 app_error_code)
 draft-ietf-webtrans-http3-15 4.4 (WTH3-040): app-facing delivery of a RESET_STREAM/STOP_SENDING received on one of session s's own WT bidi/uni streams.
typedef void(* wired_wt_on_session) (void *app_ctx, wired_wt_session *s, wired_span path, wired_span protocol)
 WebTransport subprotocol negotiation (draft-ietf-webtrans-http3-15 SS3.4): app-facing notification that a WebTransport session was established (its 2xx accept response has been built).
typedef void(* wired_wt_on_session_close) (void *app_ctx, wired_wt_session *s)
 App-facing notification that a WebTransport session ended server-side: its own CONNECT stream closed, it violated a WT flow-control limit, the server sent WT_CLOSE_SESSION, or its whole connection tore down (peer CONNECTION_CLOSE, boot failure, or the idle-timeout sweep).
typedef void(* wired_wt_on_session_draining) (void *app_ctx, wired_wt_session *s)
 draft-ietf-webtrans-http3-15 4.7: the peer sent WT_DRAIN_SESSION on s's CONNECT stream – an advisory request to wind the session down soon.
typedef void(* wired_rawq_on_session) (void *app_ctx, wired_wt_session *s, wired_span alpn)
 draft-ietf-moq-transport-19 3.1.5 / -22 6.2.2 (native QUIC): app-facing notification that a raw-QUIC application connection (its ALPN one of wired_srvboot_id.raw_alpns) got its implicit session.
typedef void(* wired_wt_resource_check) (void *app_ctx, wired_span authority, wired_span path, wired_wt_resource_decision *out)
 draft-ietf-webtrans-http3-15 SS3.2: app-facing resource lookup for one Extended CONNECT, called before Origin verification/session establishment.
typedef void(* wired_srvrun_on_step) (void *ctx, u64 now_ms)
 Per-step application hook (wired_srvrun_opt.on_step).
typedef qpack_field wired_http_field
 One response header field line: lowercase name and value views (RFC 9114 4.2).
typedef int(* wired_http_handler) (void *ctx, wired_http_exchange *x)
 Build (a round of) the response for a decoded request: like wired_srvloop_handler, but able to choose the status and add response header fields (see wired_http_exchange).

Functions

int wired_server_run (u16 port, wired_srvboot_id *id, wired_srvrun_handler h, wired_srvrun_obs obs)
 The complete server event loop: bind a UDP socket on port, then forever receive datagrams and drive them — a fresh client Initial cold-starts a connection (wired_srvboot_accept), any later datagram steps the live loop (wired_srvloop_step) — sealing every reply straight back.
int wired_server_run_opt (u16 port, wired_srvboot_id *id, wired_srvrun_handler h, wired_srvrun_obs obs, const wired_srvrun_opt *opt)
 Same as wired_server_run, plus opt-in polling-driver behavior.
usz wired_srvrun_env_size (void)
 Byte size of one wired_srvrun_env instance, for a caller allocating one (statically, or via an SDK-external allocator) to pass to wired_srvrun_env_init / wired_srvrun_serve_env.
void wired_srvrun_env_init (wired_srvrun_env *env)
 Zero-initialize env (its connection table, response/rx storage, and pacing scratch) before its first use with wired_srvrun_serve_env.
void wired_srvrun_env_wt_usage (const wired_srvrun_env *env, wired_srvrun_wt_usage *out)
 Snapshot env's WebTransport usage counters into *out.
int wired_srvrun_serve_env (wired_srvrun_env *env, u16 port, wired_srvboot_id *id, wired_srvrun_handler h, wired_srvrun_obs obs, const wired_srvrun_opt *opt)
 Same as wired_server_run_opt, but driven off caller-owned env instead of the SDK's single process-wide instance – lets a caller run more than one independent server loop in the same process (e.g.
int * wired_srvrun_shutdown_word (void)
 The process-wide graceful-shutdown word (RFC 9114 5.2): 0 until a shutdown is requested, then monotonically 1 (never reset outside test teardown).
int wired_server_broadcast_datagram (wired_span data)
 RFC 9221 5 / draft-ietf-webtrans-http3-15 SS4: broadcast data as a QUIC DATAGRAM to every connection with an active WebTransport session (queued for each such connection's own next step, same single-slot last-writer- wins contract as this SDK's per-connection DATAGRAM queue).
int wired_server_broadcast_datagram_ring (wired_span data)
 Queue one HTTP Datagram (RFC 9297) to EVERY active WebTransport session in the caller's server loop – the burst-safe sibling of wired_server_broadcast_datagram.
i64 wired_server_wt_open_uni (wired_wt_session *s, wired_span payload)
 Open a new server-initiated unidirectional stream on s's connection (RFC 9000 2.1: id 3 mod 4) and send the whole payload on it, closing with FIN on the final slice.
i64 wired_server_wt_open_bidi (wired_wt_session *s, wired_span payload)
 Same as wired_server_wt_open_uni, but a server-initiated bidirectional stream (RFC 9000 2.1: id 1 mod 4; signal prefix varint 0x41).
int wired_server_wt_stream_reply (wired_wt_session *s, u64 stream_id, wired_span payload)
 Send payload on this endpoint's send direction of the client-initiated bidirectional stream stream_id (a WebTransport data stream the client opened), closing with FIN on the final slice.
i64 wired_server_wt_open_uni_stream (wired_wt_session *s, wired_span payload)
 Same as wired_server_wt_open_uni, but WITHOUT closing the stream: no FIN is sent after payload's final slice, and the stream stays open for further wired_server_wt_stream_send rounds until one carries fin=1 (or wired_server_wt_stream_reset aborts it).
i64 wired_server_wt_open_bidi_stream (wired_wt_session *s, wired_span payload)
 Same as wired_server_wt_open_uni_stream, but a server-initiated bidirectional stream (RFC 9000 2.1: id 1 mod 4; signal prefix varint 0x41), its receive side pre-registered like wired_server_wt_open_bidi.
int wired_server_wt_stream_reply_open (wired_wt_session *s, u64 stream_id, wired_span payload)
 Same as wired_server_wt_stream_reply, but WITHOUT closing the stream – the opening round of a reply on a client-initiated bidi stream that stays open for further wired_server_wt_stream_send rounds.
int wired_server_wt_stream_send (wired_wt_session *s, u64 stream_id, wired_span payload, int fin)
 Append one more round of bytes to a stream opened with wired_server_wt_ open_uni_stream/open_bidi_stream/stream_reply_open: payload goes out at the stream's cumulative offset (RFC 9000 19.8), and fin=1 ends the stream with FIN on this round's final slice, after which the send slot frees itself once fully acknowledged (the one-shot opens' behavior).
int wired_server_wt_stream_priority (wired_wt_session *s, u64 stream_id, u8 urgency)
 Set the send urgency of a server-sent stream that still holds its send slot (RFC 9218 2.1: 0 most urgent .
int wired_server_wt_stream_schedule (wired_wt_session *s, u64 stream_id, const wired_wt_sched *k)
 Set a server-sent stream's full send class (see wired_wt_sched).
u64 wired_server_wt_est_kbps (wired_wt_session *s)
 The connection's current delivery-rate estimate for s, in kbps: BBR's bottleneck bandwidth once it has a sample, else cwnd / smoothed RTT.
int wired_server_wt_stream_fin (wired_wt_session *s, u64 stream_id)
 Ends a stream opened for appending with NO further bytes: a bare FIN on an otherwise-empty final round (RFC 9000 19.8 permits a zero-length STREAM frame carrying only FIN).
int wired_server_wt_stream_hold (wired_wt_session *s, u64 stream_id, int hold)
 Hold or release the receive flow-control credit of a client-initiated stream (RFC 9000 4.1/19.10): while held, the loop stops RAISING the advertised MAX_STREAM_DATA for stream_id as the app consumes its bytes, so the peer's remaining send window drains and it pauses – backpressure without discarding anything.
int wired_server_wt_stream_reset (wired_wt_session *s, u64 stream_id, u32 error_code)
 Abort a stream opened for appending: queue a standard RESET_STREAM (RFC 9000 19.4) on stream_id carrying error_code mapped into HTTP/3's WebTransport range (draft-ietf-webtrans-http3-15 SS4.4/8.2) and the stream's bytes-sent-so-far as its Final Size, delivered on one of the loop's next steps.
int wired_server_wt_stream_stop (wired_wt_session *s, u64 stream_id, u32 error_code)
 Asks the peer to stop sending on a PEER-initiated stream: queues one STOP_SENDING (RFC 9000 19.5) carrying error_code mapped into HTTP/3's WebTransport range, kept for resending until ACKed like a reset (RFC 9000 13.3).
int wired_server_wt_stream_inflight (wired_wt_session *s, u64 stream_id)
 1 while a send slot on s's connection still holds stream_id – its bytes not yet fully acknowledged, or the stream still open for appends – and 0 once the slot was reaped or stream_id never named a server-sent stream on this session.
int wired_server_wt_send_datagram_to (wired_wt_session *s, wired_span payload)
 Queue one HTTP Datagram (RFC 9297) to this session's peer: the SDK prefixes the quarter-stream-id varint (the session's CONNECT stream id / 4, RFC 9297 2.1) and sends it as a QUIC DATAGRAM (RFC 9221) on one of the loop's next steps.
int wired_server_wt_close_session (wired_wt_session *s, u32 app_error_code, wired_span message)
 draft-ietf-webtrans-http3-15 SS4.2/SS4.4/8.2 (WTH3-067): close s's WebTransport session: send a WT_CLOSE_SESSION capsule (app_error_code, message) followed immediately by FIN on the session's own CONNECT stream, then reset every other WT stream the session owns with WT_SESSION_GONE and transition the session to closed.
int wired_server_wt_drain_session (wired_wt_session *s)
 draft-ietf-webtrans-http3-15 4.7: ask the peer to wind s down by sending a WT_DRAIN_SESSION capsule on s's CONNECT stream.
int wired_server_session_is_raw (wired_wt_session *s)
 1 when s is the implicit session of a raw-QUIC application connection (wired_rawq_on_session), 0 for a WebTransport session or when s resolves to no live connection.
int wired_server_wt_occupancy (wired_wt_occupancy *out)
 Snapshot the calling loop's WebTransport occupancy into *out.
void wired_srvrun_broadcast_register (int index, int n_total, wired_srvinbox_ring *inbox_row, wired_srvrun_env *env)
 Register the calling thread as srvthreads worker index of n_total, with its own N-ring inbox row (inbox_row[j] receives broadcasts sent by worker j, j != index only – the caller's own broadcasts reach its own connections directly, not through this row, so double-delivery to itself never happens) and its own env (the connection table wired_server_broadcast_datagram fans out into when this thread is the caller).
void wired_srvrun_broadcast_unregister (void)
 Unregister the calling thread's broadcast registry entry (symmetric with wired_srvrun_broadcast_register), typically at worker shutdown.

Detailed Description

The complete server event loop: the sanctioned socket-owning layer over the socket-free srvboot/srvloop core.

Typedef Documentation

◆ wired_http_field

One response header field line: lowercase name and value views (RFC 9114 4.2).

Both must stay valid after the handler returns (static or ctx-owned storage): they are encoded once the call is over.

◆ wired_http_handler

typedef int(* wired_http_handler) (void *ctx, wired_http_exchange *x)

Build (a round of) the response for a decoded request: like wired_srvloop_handler, but able to choose the status and add response header fields (see wired_http_exchange).

Parameters
ctxthe opaque context registered alongside this callback
xthe exchange to fill in
Returns
1 to send x->body, 0 for a body-less response

◆ wired_rawq_on_session

typedef void(* wired_rawq_on_session) (void *app_ctx, wired_wt_session *s, wired_span alpn)

draft-ietf-moq-transport-19 3.1.5 / -22 6.2.2 (native QUIC): app-facing notification that a raw-QUIC application connection (its ALPN one of wired_srvboot_id.raw_alpns) got its implicit session.

The session is created when the handshake is confirmed and is reported before any of its stream bytes are delivered; it then flows through the same wt_on_stream_data/wt_on_datagram/wt_on_stream_reset/wt_on_session_close callbacks as a WebTransport session (wired_server_session_is_raw tells them apart). alpn is a view into the static raw_alpns configuration.

Parameters
app_ctxopaque context registered alongside this callback
sthe connection's implicit session
alpnthe negotiated ALPN protocol id, e.g. "moqt-19"

◆ wired_srvrun_env

Opaque: one server loop instance's mutable state (connection table, response/rx storage, pacing scratch).

wired_server_run/wired_server_run_opt drive a single process-wide instance of this internally; wired_srvrun_env_* plus wired_srvrun_serve_env let a caller allocate and run additional, independent instances (e.g. one per thread). Never dereference members directly – allocate wired_srvrun_env_size() bytes and pass the pointer through.

◆ wired_srvrun_on_step

typedef void(* wired_srvrun_on_step) (void *ctx, u64 now_ms)

Per-step application hook (wired_srvrun_opt.on_step).

Parameters
ctxopaque context registered alongside this callback
now_msthe loop's monotonic clock at this step

◆ wired_wt_on_datagram

typedef void(* wired_wt_on_datagram) (void *app_ctx, wired_wt_session *s, wired_span data)

draft-ietf-webtrans-http3-15 SS4: app-facing delivery of one received QUIC DATAGRAM (RFC 9221 5) associated with a WebTransport session, drained from wired_srvloop's rx_datagrams queue once per connection step.

data is a view into per-step scratch, not valid past the call.

Parameters
app_ctxopaque context registered alongside this callback
sthe session the datagram is associated with
datathe datagram's payload bytes

◆ wired_wt_on_session

typedef void(* wired_wt_on_session) (void *app_ctx, wired_wt_session *s, wired_span path, wired_span protocol)

WebTransport subprotocol negotiation (draft-ietf-webtrans-http3-15 SS3.4): app-facing notification that a WebTransport session was established (its 2xx accept response has been built).

path and protocol are views into per-connection/per-call scratch, not valid past the call.

Parameters
app_ctxopaque context registered alongside this callback
sthe session that was just established
paththe Extended CONNECT's :path value
protocolthe negotiated subprotocol (the raw token, not its sf-string encoding); empty when no subprotocol was negotiated

◆ wired_wt_on_session_close

typedef void(* wired_wt_on_session_close) (void *app_ctx, wired_wt_session *s)

App-facing notification that a WebTransport session ended server-side: its own CONNECT stream closed, it violated a WT flow-control limit, the server sent WT_CLOSE_SESSION, or its whole connection tore down (peer CONNECTION_CLOSE, boot failure, or the idle-timeout sweep).

Fires once per session, before the session object's storage can be reused by a later connection – an app keying its own per-session state on the wired_wt_session pointer MUST release that state here, or a reconnecting client landing in the reused slot inherits the dead session's identity. s is only valid for the duration of the call.

Parameters
app_ctxopaque context registered alongside this callback
sthe session that ended

◆ wired_wt_on_session_draining

typedef void(* wired_wt_on_session_draining) (void *app_ctx, wired_wt_session *s)

draft-ietf-webtrans-http3-15 4.7: the peer sent WT_DRAIN_SESSION on s's CONNECT stream – an advisory request to wind the session down soon.

The session stays open; the app decides when to close it. Fires once per session, however often the peer repeats the capsule. s is only valid for the duration of the call.

Parameters
app_ctxopaque context registered alongside this callback
sthe session the peer asked to drain

◆ wired_wt_on_stream_data

typedef void(* wired_wt_on_stream_data) (void *app_ctx, wired_wt_session *s, u64 stream_id, wired_span data, int fin)

draft-ietf-webtrans-http3-15 4.3: app-facing delivery of one reassembled chunk of a WebTransport bidi/uni stream's bytes, drained from wired_srvloop's wt_streams/wt_uni_streams once per connection step.

data is a view into per-step scratch, not valid past the call. fin=1 marks the stream's end.

Parameters
app_ctxopaque context registered alongside this callback
sthe session the stream is associated with
stream_idthe WT bidi/uni stream id
datathe stream's reassembled bytes so far past the signal/type byte
fin1 once the stream's FIN has been seen

◆ wired_wt_on_stream_reset

typedef void(* wired_wt_on_stream_reset) (void *app_ctx, wired_wt_session *s, u64 stream_id, int mapped, u32 app_error_code)

draft-ietf-webtrans-http3-15 4.4 (WTH3-040): app-facing delivery of a RESET_STREAM/STOP_SENDING received on one of session s's own WT bidi/uni streams.

"If a RESET_STREAM or STOP_SENDING frame is received with an error code outside the WT_APPLICATION_ERROR range, then the implementation should deliver this to the application as a stream reset with no application error code" – mapped is 1 when the wire error code fell inside the WT_APPLICATION_ERROR range (wired_wterrmap_from_http3 accepted it) and app_error_code is the recovered WebTransport application error code, or mapped is 0 (app_error_code left at 0, not itself meaningful) for a wire code outside that range or on a reserved codepoint.

Parameters
app_ctxopaque context registered alongside this callback
sthe session the stream is associated with
stream_idthe WT bidi/uni stream id the reset arrived on
mapped1 if app_error_code is a recovered WT application error code
app_error_codethe recovered code, valid only when mapped is 1

◆ wired_wt_resource_check

typedef void(* wired_wt_resource_check) (void *app_ctx, wired_span authority, wired_span path, wired_wt_resource_decision *out)

draft-ietf-webtrans-http3-15 SS3.2: app-facing resource lookup for one Extended CONNECT, called before Origin verification/session establishment.

authority/path are views into per-call scratch, not valid past the call. out is caller-zeroed before the call (a callback that never touches it accepts the resource, see wired_wt_resource_decision's own doc).

Parameters
app_ctxopaque context registered alongside this callback
authoritythe Extended CONNECT's :authority value
paththe Extended CONNECT's :path value
outthe verdict to fill in

Function Documentation

◆ wired_server_broadcast_datagram()

int wired_server_broadcast_datagram ( wired_span data)

RFC 9221 5 / draft-ietf-webtrans-http3-15 SS4: broadcast data as a QUIC DATAGRAM to every connection with an active WebTransport session (queued for each such connection's own next step, same single-slot last-writer- wins contract as this SDK's per-connection DATAGRAM queue).

Typically called from inside a wired_wt_on_datagram callback to fan a received message out to every other participant (e.g. a chat app) — that callback has no handle to the connection table itself, so this is the only way to reach connections other than the one that just received data. Callable only from inside the server's own loop (i.e. from a callback); this SDK's server loop is single-threaded and this call is neither signal-safe nor thread-safe.

Parameters
datapayload to broadcast; must fit the per-connection DATAGRAM cap
Returns
1 if queued for every active WT session, 0 if data exceeds the cap

Threaded fan-out: a caller running inside a srvthreads worker (registered via wired_srvrun_broadcast_register) is fanned out into ITS OWN registered env – srvthreads gives every worker its own connection table, so the single process-wide g_srvrun_env would be empty/unused for a registered worker and reach no one. With 2 or more workers registered, the payload is also pushed into every OTHER registered worker's inbox row (wired_srvinbox_push) so each one's own wired_srvrun_serve_env loop delivers it to its own WT sessions on a later step (srvrun.c drains the calling worker's inbox row once per step). An unregistered caller (the default, single-process wired_server_run(_opt) or a lone wired_srvrun_serve_env instance) fans out directly to the single g_srvrun_env.

◆ wired_server_broadcast_datagram_ring()

int wired_server_broadcast_datagram_ring ( wired_span data)

Queue one HTTP Datagram (RFC 9297) to EVERY active WebTransport session in the caller's server loop – the burst-safe sibling of wired_server_broadcast_datagram.

Where that API holds one pending payload per connection (a second broadcast in the same loop step overwrites the first, last-writer-wins), this one queues each target into the same bounded ring wired_server_wt_send_datagram_to uses, so several broadcasts inside one step – an audio burst, say – are all delivered on the loop's next step, none overwritten. Each target session's own quarter-stream-id varint (RFC 9297 2.1) is prefixed at queue time and the payload is copied, so it need not outlive the call. A session is a target only when its connection is up, this endpoint's SETTINGS have been sent (RFC 9297 2.1), and the session's CONNECT stream send side is still open (RFC 9297 2) – the same gates wired_server_wt_send_datagram_to applies. Frames exceeding the peer's advertised max_datagram_frame_size are dropped at send time (RFC 9221 3). Callable only from inside the server's own loop (a callback), same contract as wired_server_broadcast_datagram.

Single-process only: unlike wired_server_broadcast_datagram, this API does not push into the srvthreads inbox mesh – a registered worker reaches its OWN env's sessions only. Reaching other workers' sessions burst-safely would also need the inbox drain path to queue into the ring (it currently feeds the single-slot queue), not built yet.

Parameters
datathe HTTP Datagram payload (qsid prefix NOT included); each target's prefixed copy must fit a ring slot
Returns
1 if every target session was queued (including when there is no target at all), 0 when the ring filled up or the prefixed payload exceeds a ring slot for some target

◆ wired_server_run()

int wired_server_run ( u16 port,
wired_srvboot_id * id,
wired_srvrun_handler h,
wired_srvrun_obs obs )

The complete server event loop: bind a UDP socket on port, then forever receive datagrams and drive them — a fresh client Initial cold-starts a connection (wired_srvboot_accept), any later datagram steps the live loop (wired_srvloop_step) — sealing every reply straight back.

id is the fixed server identity, h the application's request responder. This owns the socket and blocks in recvfrom, the sanctioned socket-owning layer over the socket-free srvboot/srvloop core. RFC 9000 7: one connection at a time, in arrival order.

Graceful shutdown (RFC 9114 5.2): installs a SIGTERM handler before serving. On receipt, new connections stop being accepted, GOAWAY is sent once to every live connection, and the process exits once every connection has drained or a bounded grace period elapses. ponytail: a SIGTERM delivered before this handler is installed (a narrow startup race) falls back to the default action (immediate exit, no GOAWAY) — acceptable for a demo; a process supervisor should signal only after observing the "listening" log line.

Certificate hot reload (SIGHUP): when obs.cert_path/key_path are both set, installs a SIGHUP handler; on receipt, re-reads and re-decodes the PEM pair and updates *id in place (chain/chain_count/cert_seed only) so every connection cold-started afterward uses the new material. A connection already past its handshake never re-reads id, so a reload never disturbs it. id is therefore NOT const: the caller must keep it (and its backing PEM-derived buffers) alive and mutable for the whole run. A reload that fails to read or decode the new PEM pair leaves the previous identity in place.

Parameters
portUDP port to bind
idthe fixed server identity; updated in place on a SIGHUP reload
hthe application's request responder
obsoptional qlog/keylog file paths and cert reload paths, each 0 to disable
Returns
0 if the socket cannot be opened or bound; otherwise runs until shutdown completes (SIGTERM) or the process is killed.

◆ wired_server_run_opt()

int wired_server_run_opt ( u16 port,
wired_srvboot_id * id,
wired_srvrun_handler h,
wired_srvrun_obs obs,
const wired_srvrun_opt * opt )

Same as wired_server_run, plus opt-in polling-driver behavior.

opt must not be 0; wired_server_run itself passes an opt with every knob at its disabled default (all-zero except incoming_cpu, which is -1; see wired_srvrun_opt) so its behavior is byte-identical to before this was added.

Parameters
portUDP port to bind
idthe fixed server identity; updated in place on a SIGHUP reload
hthe application's request responder
obsoptional qlog/keylog file paths and cert reload paths, each 0 to disable
optbusy_poll / so_busy_poll_us knobs, see wired_srvrun_opt
Returns
same as wired_server_run.

◆ wired_server_session_is_raw()

int wired_server_session_is_raw ( wired_wt_session * s)

1 when s is the implicit session of a raw-QUIC application connection (wired_rawq_on_session), 0 for a WebTransport session or when s resolves to no live connection.

On a raw session the wired_server_wt_* send API applies the native-QUIC binding: no stream signal or datagram quarter-stream-id, reset codes sent verbatim, and close as a CONNECTION_CLOSE 0x1d carrying the code (draft-ietf-moq-transport-19 3.5, -22 6.6; RFC 9000 19.19). Callable only from inside the server's own loop (a callback).

Parameters
sthe session to ask about
Returns
1 raw QUIC, 0 otherwise

◆ wired_server_wt_close_session()

int wired_server_wt_close_session ( wired_wt_session * s,
u32 app_error_code,
wired_span message )

draft-ietf-webtrans-http3-15 SS4.2/SS4.4/8.2 (WTH3-067): close s's WebTransport session: send a WT_CLOSE_SESSION capsule (app_error_code, message) followed immediately by FIN on the session's own CONNECT stream, then reset every other WT stream the session owns with WT_SESSION_GONE and transition the session to closed.

Queued (not sent inline) for delivery on one of the loop's next steps, the same deferred shape as wired_server_wt_ send_datagram_to; a second call before the first drains overwrites the pending one (last-writer-wins, same policy as this SDK's other single-slot WT queues). Callable only from inside the server's own loop (a callback). On a raw-QUIC session (wired_server_session_is_raw) the close is instead the connection's application CONNECTION_CLOSE (0x1d, RFC 9000 19.19) carrying app_error_code verbatim and at most 48 bytes of message (draft-ietf-moq-transport-19 3.5, -22 6.6).

Parameters
sthe session to close
app_error_codethe WebTransport application error code to report
messageUTF-8 reason, message.n <= WTCAPSULE_CLOSE_MESSAGE_MAX (copied at call time, so it need not outlive the call); a longer message is truncated to the cap
Returns
1 queued, 0 when s resolves to no live connection

◆ wired_server_wt_drain_session()

int wired_server_wt_drain_session ( wired_wt_session * s)

draft-ietf-webtrans-http3-15 4.7: ask the peer to wind s down by sending a WT_DRAIN_SESSION capsule on s's CONNECT stream.

Queued for one of the loop's next steps, and sent at most once per session: a repeat call (or the drain the server's own GOAWAY already sent) succeeds without sending again. The session stays open. Callable only from inside the server's own loop (a callback).

Parameters
sthe session to drain
Returns
1 queued (or already drained), 0 when s resolves to no live connection (e.g. the session already closed) or is a raw-QUIC session, which has no transport-level drain (draft-ietf-moq-transport-19 3.6)

◆ wired_server_wt_est_kbps()

u64 wired_server_wt_est_kbps ( wired_wt_session * s)

The connection's current delivery-rate estimate for s, in kbps: BBR's bottleneck bandwidth once it has a sample, else cwnd / smoothed RTT.

It tracks what the congestion controller allows, so a sender that stays below its window (app-limited) may see it grow slowly.

Parameters
sthe session whose connection is asked
Returns
kbps, or 0 when unknown (no RTT sample yet, or s resolves to no live connection)

◆ wired_server_wt_occupancy()

int wired_server_wt_occupancy ( wired_wt_occupancy * out)

Snapshot the calling loop's WebTransport occupancy into *out.

Callable only from inside the server's own loop (a callback).

Parameters
outreceives the counts
Returns
1

◆ wired_server_wt_open_bidi()

i64 wired_server_wt_open_bidi ( wired_wt_session * s,
wired_span payload )

Same as wired_server_wt_open_uni, but a server-initiated bidirectional stream (RFC 9000 2.1: id 1 mod 4; signal prefix varint 0x41).

Parameters
sthe session whose connection the stream is opened on
payloadthe complete stream bytes, signal prefix included
Returns
the allocated stream id, or negative on failure

◆ wired_server_wt_open_bidi_stream()

i64 wired_server_wt_open_bidi_stream ( wired_wt_session * s,
wired_span payload )

Same as wired_server_wt_open_uni_stream, but a server-initiated bidirectional stream (RFC 9000 2.1: id 1 mod 4; signal prefix varint 0x41), its receive side pre-registered like wired_server_wt_open_bidi.

Parameters
sthe session whose connection the stream is opened on
payloadthe first round's bytes, signal prefix included
Returns
the allocated stream id, or negative on failure

◆ wired_server_wt_open_uni()

i64 wired_server_wt_open_uni ( wired_wt_session * s,
wired_span payload )

Open a new server-initiated unidirectional stream on s's connection (RFC 9000 2.1: id 3 mod 4) and send the whole payload on it, closing with FIN on the final slice.

payload must already carry the WebTransport stream signal prefix (draft-ietf-webtrans-http3-15 4.2: varint 0x54 + the CONNECT stream id, wired_wtwire_signal_put) – this SDK sends the bytes verbatim. A payload up to the send slot's own staging capacity (SRVRUN_WTSEND_BUF, 65536 bytes) is COPIED: the caller's storage is free the moment the call returns. Only a larger payload is held as a VIEW, and then the caller must keep it alive and unmoved until every byte has been acknowledged (the send slot frees itself then). Delivery is congestion/flow-control gated and paced like any response stream (RFC 9000 4.1 / RFC 9002 7). Callable only from inside the server's own loop (a callback), same contract as wired_server_broadcast_datagram.

Parameters
sthe session whose connection the stream is opened on
payloadthe complete stream bytes, signal prefix included
Returns
the allocated stream id, or negative when s resolves to no live connection or every send slot is busy

◆ wired_server_wt_open_uni_stream()

i64 wired_server_wt_open_uni_stream ( wired_wt_session * s,
wired_span payload )

Same as wired_server_wt_open_uni, but WITHOUT closing the stream: no FIN is sent after payload's final slice, and the stream stays open for further wired_server_wt_stream_send rounds until one carries fin=1 (or wired_server_wt_stream_reset aborts it).

The same view/liveness contract as wired_server_wt_open_uni applies to payload.

Parameters
sthe session whose connection the stream is opened on
payloadthe first round's bytes, signal prefix included
Returns
the allocated stream id, or negative on failure

◆ wired_server_wt_send_datagram_to()

int wired_server_wt_send_datagram_to ( wired_wt_session * s,
wired_span payload )

Queue one HTTP Datagram (RFC 9297) to this session's peer: the SDK prefixes the quarter-stream-id varint (the session's CONNECT stream id / 4, RFC 9297 2.1) and sends it as a QUIC DATAGRAM (RFC 9221) on one of the loop's next steps.

The payload is copied at queue time, so it need not outlive the call. Unlike wired_server_broadcast_datagram's single last-writer-wins slot, sends queue into a bounded ring, so a burst of many datagrams is delivered without overwriting. Frames exceeding the peer's advertised max_datagram_frame_size are dropped at send time (RFC 9221 3), matching this SDK's existing per-connection DATAGRAM policy.

Parameters
sthe session the datagram is addressed to
payloadthe HTTP Datagram payload (qsid prefix NOT included)
Returns
1 queued, 0 when s resolves to no live connection, this endpoint's SETTINGS have not been sent yet (RFC 9297 2.1), the ring is full, or the prefixed payload exceeds a ring slot

◆ wired_server_wt_stream_fin()

int wired_server_wt_stream_fin ( wired_wt_session * s,
u64 stream_id )

Ends a stream opened for appending with NO further bytes: a bare FIN on an otherwise-empty final round (RFC 9000 19.8 permits a zero-length STREAM frame carrying only FIN).

Use this instead of wired_server_wt_stream_send when the app has determined the stream is over but has no new bytes to send with it – e.g. the peer's own source stream closed with no trailing data of its own on that side (a WebTransport writer's close() can arrive as its own byte-less frame, separate from the data written just before it). The send slot frees itself once this round is fully acknowledged, same as wired_server_wt_stream_send's fin=1 round.

Parameters
sthe session whose connection carries the stream
stream_ida stream opened by one of the three open_*_stream calls, or already appended to via wired_server_wt_stream_send(fin=0)
Returns
1 accepted, negative when s resolves to no live connection, stream_id names no open send slot, or the previous round is still in flight

◆ wired_server_wt_stream_hold()

int wired_server_wt_stream_hold ( wired_wt_session * s,
u64 stream_id,
int hold )

Hold or release the receive flow-control credit of a client-initiated stream (RFC 9000 4.1/19.10): while held, the loop stops RAISING the advertised MAX_STREAM_DATA for stream_id as the app consumes its bytes, so the peer's remaining send window drains and it pauses – backpressure without discarding anything.

The advertisement is never lowered (an advertisement MUST NOT decrease), so bytes the peer was already granted still arrive and must be absorbed by the app; hold=0 resumes raising on one of the loop's next steps. A hold placed on a bidi stream before its first grant still lets that one grant through (it lifts the stream from the request-stream initial credit to the WebTransport buffer). Applies to the receive slot (bidi or uni) currently reassembling stream_id on s's connection. Like the other wired_server_wt_* calls, call this from within the loop's callbacks.

Parameters
sthe session whose connection carries the stream
stream_idthe client-initiated stream whose credit to hold
hold1 to freeze the advertised credit, 0 to resume raising
Returns
1 applied, negative when s resolves to no live connection or stream_id names no receive slot on it

◆ wired_server_wt_stream_inflight()

int wired_server_wt_stream_inflight ( wired_wt_session * s,
u64 stream_id )

1 while a send slot on s's connection still holds stream_id – its bytes not yet fully acknowledged, or the stream still open for appends – and 0 once the slot was reaped or stream_id never named a server-sent stream on this session.

A payload handed to wired_server_wt_open_uni above the slot's staging capacity is held as a VIEW (see its doc); this is the signal that the view may be reused.

Parameters
sthe session whose connection carries the stream
stream_ida stream id returned by one of the open_* calls
Returns
1 in flight, 0 otherwise

◆ wired_server_wt_stream_priority()

int wired_server_wt_stream_priority ( wired_wt_session * s,
u64 stream_id,
u8 urgency )

Set the send urgency of a server-sent stream that still holds its send slot (RFC 9218 2.1: 0 most urgent .

. 7, default 3). Each pump pass sends only from the most urgent streams that can send right now; streams of equal urgency keep sharing the pass in turn. The setting lasts until the stream's send slot is released.

Parameters
sthe session whose connection carries the stream
stream_ida stream holding an open send slot
urgency0..7, lower is more urgent
Returns
1 applied, negative when urgency is above 7, s resolves to no live connection, or stream_id names no open send slot

◆ wired_server_wt_stream_reply()

int wired_server_wt_stream_reply ( wired_wt_session * s,
u64 stream_id,
wired_span payload )

Send payload on this endpoint's send direction of the client-initiated bidirectional stream stream_id (a WebTransport data stream the client opened), closing with FIN on the final slice.

No prefix is added – the bytes go out verbatim, and the same view/liveness contract as wired_server_wt_open_uni applies.

Parameters
sthe session whose connection carries the stream
stream_idthe client-opened bidi stream to reply on
payloadthe bytes to send
Returns
1 accepted, 0 when s resolves to no live connection or every send slot is busy

◆ wired_server_wt_stream_reply_open()

int wired_server_wt_stream_reply_open ( wired_wt_session * s,
u64 stream_id,
wired_span payload )

Same as wired_server_wt_stream_reply, but WITHOUT closing the stream – the opening round of a reply on a client-initiated bidi stream that stays open for further wired_server_wt_stream_send rounds.

Parameters
sthe session whose connection carries the stream
stream_idthe client-opened bidi stream to reply on
payloadthe first round's bytes
Returns
1 accepted, 0 on failure

◆ wired_server_wt_stream_reset()

int wired_server_wt_stream_reset ( wired_wt_session * s,
u64 stream_id,
u32 error_code )

Abort a stream opened for appending: queue a standard RESET_STREAM (RFC 9000 19.4) on stream_id carrying error_code mapped into HTTP/3's WebTransport range (draft-ietf-webtrans-http3-15 SS4.4/8.2) and the stream's bytes-sent-so-far as its Final Size, delivered on one of the loop's next steps.

Resets queue into a small bounded latch (several streams can be aborted between steps – e.g. a relay fanning one source out to many subscribers); a FULL latch refuses the call and leaves the stream untouched, so a caller can retry once a later step drains it. On success the stream's send slot is freed at once, releasing the app's payload view and dropping any not-yet-sent bytes (RFC 9000 19.4: delivery is abandoned). No STOP_SENDING accompanies the reset: the streams this API opens are server-initiated uni streams, which have no peer-to-server half to stop (RFC 9000 19.5).

Parameters
sthe session whose connection carries the stream
stream_idthe stream to abort
error_codethe WebTransport application error code to report
Returns
1 queued (or nothing to do: the stream's send part already ended, its FIN ACKed or an earlier reset sent – no RESET_STREAM goes out), 0 when s resolves to no live connection or the reset latch is full (nothing changed; retry on a later step)

◆ wired_server_wt_stream_schedule()

int wired_server_wt_stream_schedule ( wired_wt_session * s,
u64 stream_id,
const wired_wt_sched * k )

Set a server-sent stream's full send class (see wired_wt_sched).

Each pump pass sends from the best (urgency, fine) class among streams that can send right now, one slice per stream; inside a nonzero flow only the streams with the lowest (order, tie) among that flow's ready streams of the class take part. A stream that cannot send never holds back another. The setting lasts until the send slot is released.

Parameters
sthe session whose connection carries the stream
stream_ida stream holding an open send slot
kthe class; k->urgency must be 0..7
Returns
1 applied, negative when k->urgency is above 7, s resolves to no live connection, or stream_id names no open send slot

◆ wired_server_wt_stream_send()

int wired_server_wt_stream_send ( wired_wt_session * s,
u64 stream_id,
wired_span payload,
int fin )

Append one more round of bytes to a stream opened with wired_server_wt_ open_uni_stream/open_bidi_stream/stream_reply_open: payload goes out at the stream's cumulative offset (RFC 9000 19.8), and fin=1 ends the stream with FIN on this round's final slice, after which the send slot frees itself once fully acknowledged (the one-shot opens' behavior).

An accepted round is COPIED into the slot's own staging (the caller's storage is free the moment the call returns) and pipelines onto the wire behind any earlier rounds still awaiting their ACKs – rounds queue up to the slot's staging capacity (SRVRUN_WTSEND_BUF, 65536 bytes of not-yet- ACKed rounds), and only a round that no longer fits is refused. A stream whose OPENING payload was oversized (held as a view) refuses appends until that view fully ACKs.

Parameters
sthe session whose connection carries the stream
stream_ida stream opened by one of the three calls above
payloadthis round's bytes; must be non-empty (the FIN rides the final slice, so a bare-FIN round has nothing to carry it)
fin1 to end the stream after this round, 0 to keep it open
Returns
1 accepted, negative when s resolves to no live connection, stream_id names no open send slot, payload is empty, the staging capacity is exhausted, or the session's WT_MAX_DATA limit would be exceeded

◆ wired_server_wt_stream_stop()

int wired_server_wt_stream_stop ( wired_wt_session * s,
u64 stream_id,
u32 error_code )

Asks the peer to stop sending on a PEER-initiated stream: queues one STOP_SENDING (RFC 9000 19.5) carrying error_code mapped into HTTP/3's WebTransport range, kept for resending until ACKed like a reset (RFC 9000 13.3).

The receive-side counterpart of wired_server_wt_stream_reset: a client uni stream has no server send part to reset, and a RESET_STREAM arriving for what the client sees as its send-only stream is connection-fatal at the client (RFC 9000 19.4).

Parameters
sthe session whose connection carries the stream
stream_idthe peer-initiated stream to stop
error_codethe WebTransport application error code to report
Returns
1 queued, 0 when s resolves to no live connection or the latch is full (nothing changed; retry on a later step)

◆ wired_srvrun_broadcast_register()

void wired_srvrun_broadcast_register ( int index,
int n_total,
wired_srvinbox_ring * inbox_row,
wired_srvrun_env * env )

Register the calling thread as srvthreads worker index of n_total, with its own N-ring inbox row (inbox_row[j] receives broadcasts sent by worker j, j != index only – the caller's own broadcasts reach its own connections directly, not through this row, so double-delivery to itself never happens) and its own env (the connection table wired_server_broadcast_datagram fans out into when this thread is the caller).

Called once by each worker before serving, typically right before wired_srvrun_serve_env. n_total, inbox_row and env are owned by the caller (srvthreads); srvrun only keeps pointers into them and never allocates or frees them itself, so all three must stay live and unmoved until wired_srvrun_broadcast_unregister.

Parameters
indexthis worker's 0-based index, < n_total
n_totaltotal worker count in the mesh, <= 16 (srvrun's fixed registry capacity)
inbox_rowthis worker's own row of n_total rings, row[j] fed by worker j's broadcasts (j != index; row[index] is never written)
envthis worker's own wired_srvrun_env, the connection table a broadcast this thread sends is fanned out into directly

◆ wired_srvrun_broadcast_unregister()

void wired_srvrun_broadcast_unregister ( void )

Unregister the calling thread's broadcast registry entry (symmetric with wired_srvrun_broadcast_register), typically at worker shutdown.

A no-op if the calling thread was never registered.

◆ wired_srvrun_env_wt_usage()

void wired_srvrun_env_wt_usage ( const wired_srvrun_env * env,
wired_srvrun_wt_usage * out )

Snapshot env's WebTransport usage counters into *out.

Parameters
envthe loop instance (the process-wide one for wired_server_run callers is not addressable; use wired_srvrun_serve_env's)
outreceives the totals

◆ wired_srvrun_serve_env()

int wired_srvrun_serve_env ( wired_srvrun_env * env,
u16 port,
wired_srvboot_id * id,
wired_srvrun_handler h,
wired_srvrun_obs obs,
const wired_srvrun_opt * opt )

Same as wired_server_run_opt, but driven off caller-owned env instead of the SDK's single process-wide instance – lets a caller run more than one independent server loop in the same process (e.g.

one per thread, each with its own env and its own bound port). Set opt->no_signal_handlers=1 for every instance but one, since SIGTERM/SIGHUP are process-wide.

Parameters
envcaller-owned state, sized wired_srvrun_env_size() and initialized with wired_srvrun_env_init before the first call
portUDP port to bind
idthe fixed server identity; updated in place on a SIGHUP reload
hthe application's request responder
obsoptional qlog/keylog file paths and cert reload paths, each 0 to disable
optbusy_poll / so_busy_poll_us / no_signal_handlers knobs
Returns
same as wired_server_run.

◆ wired_srvrun_shutdown_word()

int * wired_srvrun_shutdown_word ( void )

The process-wide graceful-shutdown word (RFC 9114 5.2): 0 until a shutdown is requested, then monotonically 1 (never reset outside test teardown).

Every wired_srvrun_serve_env/wired_server_run loop in the process polls this once per iteration (srvrun.c's srvrun_shutdown_requested) to stop accepting new connections and start draining live ones – the same word wired_sigterm_install's default handler sets. A caller running its own multi-threaded fan-out over wired_srvrun_serve_env (one instance per thread, wired_srvrun_opt.no_signal_handlers=1 on every instance but the one installing signals) uses the returned pointer to both observe the word (e.g. a timed futex wait) and set it (e.g. from its own signal handler), so every thread's loop sees the same 0->1 transition without a separate flag to keep in sync.

Returns
pointer to the shared shutdown word; never 0