wired
libc-free QUIC/HTTP3 SDK in C for x86_64-linux
Loading...
Searching...
No Matches
wired_srvloop Struct Reference

Per-connection state of the server wire loop, re-armed by wired_srvloop_init and driven by wired_srvloop_step. More...

#include <srvloop.h>

Data Fields

wired_h3srv_state h3
 HTTP/3 server response-layer state.
u8 cli_scid [20]
 the client's source id; DCID the server writes
u8 cli_scid_len
 cli_scid length in octets
u8 spare_cid [20]
 RFC 9000 5.1.1/19.15: one spare connection ID handed to the client in a NEW_CONNECTION_ID frame at confirmation, so it CAN migrate – a client holding no unused CID must not initiate migration (RFC 9000 9).
u8 spare_cid_len
 Length of spare_cid; 0 means none was issued.
u8 spare_cid_token [16]
 RFC 9000 10.3: the stateless reset token advertised for spare_cid.
u8 spare_cid_in_tp
 RFC 9000 9.6/5.1.1: 1 once the spare CID was delivered inside the preferred_address transport parameter (sequence 1) – the confirmation flight then stands down its NEW_CONNECTION_ID frame (the parameter already delivered the CID; a frame would re-issue the same sequence).
u64 tx_pn
 monotone packet number for sealed 1-RTT output
u64 hs_tx_pn
 monotone packet number for sealed Handshake output
u64 app_rx_pn
 last received 1-RTT (application) packet number to ACK
u64 app_rx_hi
 Largest 1-RTT packet number received, valid with app_rx_seen: the baseline for recovering a truncated pn (RFC 9000 A.3).
int app_rx_seen
 1 once a 1-RTT packet has been received (app_rx_pn valid)
u64 np_hi
 RFC 9000 9.3: largest application packet number (0-RTT or 1-RTT) that carried a non-probing frame, valid with np_seen.
int np_seen
 1 once np_hi holds a received packet number.
int step_np_new
 1 iff this step processed a short-header 1-RTT packet that was non-probing and numbered above every earlier non-probing one – the only packet allowed to move the caller's send path.
int drop_newer
 RFC 9000 9.6.2, set by the caller before a step: discard a 1-RTT packet numbered above every number received so far, before its frames or ACK bookkeeping (the connection moved to its preferred address and this datagram arrived on the old one).
u64 hs_rx_pn
 last received Handshake packet number to ACK (the client Finished's actual PN, which is not always 0)
u64 hs_rx_hi
 Largest Handshake packet number received, valid with hs_rx_seen.
int hs_rx_seen
 1 once a Handshake packet has been received
pnspaces_recv ack_recv
 RFC 9000 12.3/13.2.1/13.2.2/19.3: every packet number space's received-pn window (pnspaces_recv, independent per space – Initial is out of this loop's scope, srvboot's own layer) plus whether/when each space owes an ACK (ackpolicy, one instance per space since App and Handshake ack independently).
ackpolicy app_ack_policy
 App space's delayed-ACK timer.
ackpolicy hs_ack_policy
 Handshake space's delayed-ACK timer.
u8 ack_defer
 When 1, respond.c's bare-ACK packet (emit_ack_only) is suppressed for the current step: the driving loop (srvrun.c) piggybacks the pending App-space ACK onto the response slice it is about to send, or flushes it itself at step end if no slice went out.
u64 now_ms
 Monotonic ms this step is being driven at – the time source ackpolicy's delayed-ACK timer measures against.
int hs_done_sent
 1 once the confirmation (HANDSHAKE_DONE) has been emitted
int ticket_sent
 1 once the post-confirmation session ticket (NewSessionTicket, RFC 8446 4.6.1) has been emitted
u8 confirm_frames [320]
 The confirmation packet's frame payload (SETTINGS + session ticket + HANDSHAKE_DONE), captured at its one-time emit so a lost confirmation can be replayed verbatim under a fresh pn (wired_srvloop_reconfirm, RFC 9000 19.20).
u16 confirm_frames_len
 Bytes cached in confirm_frames; 0 until the confirmation was emitted (or when it did not fit, leaving no replay available).
wired_srvloop_handler on_request
 app response-body builder, 0 if unset
void * req_ctx
 opaque ctx passed to on_request
wired_srvloop_stream_slot streams [WIRED_SRVLOOP_MAX_STREAMS]
 RFC 9000 2.2: one reassembly slot per concurrent client bidi (request) stream, looked up/allocated by stream id (see stream_slot_find/alloc in srvloop.c).
wired_srvloop_closed req_closed
 RFC 9000 3.2: client bidi streams already answered and released – request streams and WT bidi streams share this id space.
wired_srvloop_wt_stream_slot wt_streams [WIRED_SRVLOOP_MAX_WT_STREAMS]
 draft-ietf-webtrans-http3-15 4.3: one reassembly slot per concurrent WT bidi stream, separate from streams[] above (see wired_srvloop_wt_stream_slot's doc for why).
wired_srvloop_wt_uni_stream_slot wt_uni_streams [WIRED_SRVLOOP_MAX_WT_UNI_STREAMS]
 draft-ietf-webtrans-http3-15 4.3: one reassembly slot per concurrent WT uni stream, separate from wt_streams[] above (different directionality, see wired_srvloop_wt_uni_stream_slot's doc).
int got_request
 Mirrors the most recently completed request this step, across whichever slot decoded it — the pre-existing single-stream API surface (got_request/ req), kept so existing callers reading these two fields directly need no change.
wired_h3reqdrive_req req
 the mirrored most-recently-completed request; valid only when got_request is set
u64 req_stream_id
 the client bidi stream id req was decoded from; valid only when got_request is set (mirrors req from whichever slot completed, same rule)
u8 done_slots [WIRED_SRVLOOP_MAX_STREAMS]
 Every slot whose request completed THIS step, in completion order – the multi-request counterpart of the single got_request/req mirror above (which only carries the last one).
usz done_n
 entries valid in done_slots this step
u8 incomplete_slots [WIRED_SRVLOOP_MAX_STREAMS]
 RFC 9114 4.1: every slot whose request stream terminated (FIN) THIS step WITHOUT producing a request (streams[i].req_incomplete) – the H3_REQUEST_INCOMPLETE counterpart of done_slots above.
usz incomplete_n
 entries valid in incomplete_slots this step
u64 malformed_slots
 RFC 9114 4.1.2: bit i is set when incomplete_slots holds slot i because its whole HEADERS was malformed rather than cut short – aborted with H3_MESSAGE_ERROR instead of H3_REQUEST_INCOMPLETE.
u8 frame_unexpected_slots [WIRED_SRVLOOP_MAX_STREAMS]
 RFC 9114 7.2.5/7.2.8 (9114-067/9114-073): every slot whose request stream carried a PUSH_PROMISE or HTTP/2-only reserved frame type this step (streams[i].req.frame_unexpected) – the H3_FRAME_UNEXPECTED counterpart of incomplete_slots above.
usz frame_unexpected_n
 entries valid in frame_unexpected_slots this step
int peer_closed
 1 once a peer CONNECTION_CLOSE frame was seen
u64 reset_slots
 RFC 9000 3.2: bit i is set when a RESET_STREAM this step ended slot i's request while it was still being received – not one completed or rejected this step (those lists' owners answer it).
usz reset_slotless_n
 RFC 9000 4.6: RESET_STREAMs this step that closed a request stream which never got a slot (its STREAM frames lost or dropped) – each still used one bidi stream credit, owed back once.
int resp_external
 1: the caller answers requests, not the loop
u64 ack_lo [32]
 ACK ranges (RFC 9000 19.3) seen in payloads opened this step, reset at the start of every wired_srvloop_step; overflow past the cap is dropped.
u64 ack_hi [32]
 range highs, ack_hi[0] from the frame's largest
usz ack_n
 ranges recorded this step
u8 ecn_ack_seen
 RFC 9000 19.3.2: the ECN counts of the type-0x03 ACK with the largest acknowledged packet number opened this step (13.4.2.1: a reordered older ACK must not overwrite them), reset with ack_n.
u64 ecn_ack_largest
 largest acknowledged pn of the ACK latched
u64 ecn_ack_ect0
 its cumulative ECT(0) count
u64 ecn_ack_ect1
 its cumulative ECT(1) count
u64 ecn_ack_ce
 its cumulative ECN-CE count
wired_srvloop_rx_datagram rx_datagrams [WIRED_SRVLOOP_MAX_RX_DATAGRAMS]
 RFC 9221 5: received QUIC DATAGRAM frame payloads queued for a future consumer to drain (Phase 7b Slice 2), oldest first.
usz rx_datagram_n
 count of entries valid in rx_datagrams, 0..WIRED_SRVLOOP_MAX_RX_DATAGRAMS.
u64 we_advertised_max_datagram
 RFC 9221 3: this connection's own advertised max_datagram_frame_size transport parameter value, 0 = not advertised (same sentinel convention as wired_srvboot_id.max_datagram_frame_size, which this is populated from at connection boot — see srvrun_boot_finish).
int datagram_violation
 1 once a received DATAGRAM frame violated RFC 9221 3 (exceeded we_advertised_max_datagram, or arrived when it was never advertised) — mirrors peer_closed's shape: dispatch.c only marks this, the caller driving the loop (srvrun.c's srvrun_on_step) checks it after the step and closes the connection.
u64 closed_stream_id
 RFC 9000 19.4/19.8 (draft-ietf-webtrans-http3-15 SS4.4): the client bidi stream id a FIN or RESET_STREAM closed THIS step (a STOP_SENDING is queued in peer_resets instead – it ends OUR half, not the peer's), valid only when closed_stream_seen is set.
int closed_stream_seen
 1 once closed_stream_id was set this step
u64 max_data_seen
 RFC 9000 19.9: highest MAX_DATA value seen across every 1-RTT payload opened this step (gather_max_data in dispatch.c) – the connection-level send credit ceiling this endpoint may now use.
int max_data_seen_flag
 1 once max_data_seen was set this step
u64 max_stream_data_stream_id [WIRED_SRVLOOP_MAX_STREAMS]
 RFC 9000 19.10: every distinct MAX_STREAM_DATA (stream id, value) seen this step, one slot per distinct stream id named (up to WIRED_SRVLOOP_MAX_STREAMS – a single step coalescing a MAX_STREAM_DATA per in-flight response, e.g.
u64 max_stream_data_value [WIRED_SRVLOOP_MAX_STREAMS]
 RFC 9000 19.10: the value carried by the same-indexed max_stream_data_stream_id slot.
usz max_stream_data_n
 Slots in max_stream_data_stream_id/_value actually used this step (0 to WIRED_SRVLOOP_MAX_STREAMS).
wired_srvloop_closed wt_uni_closed
 RFC 9000 3.2: client WT uni streams already released.
wired_srvloop_closed uni_typed
 RFC 9204 4.2 / RFC 9114 6.2: client uni streams whose leading type is already known (seen whole at offset 0, or read and let go by the encoder window) – their later chunks are never held as the encoder stream candidate (dispatch.c's qenc_may_hold).
int streams_blocked_seen_flag
 RFC 9000 19.14: 1 once a client bidi STREAMS_BLOCKED frame was seen in any 1-RTT payload opened this step (gather_streams_blocked in dispatch.c) – the peer's own reported limit value is not latched (srvrun.c computes the re-grant from its own receive-side slot state, RFC 9000 4.6/19.11, rather than trusting the peer's claim).
int streams_blocked_uni_seen_flag
 Same as streams_blocked_seen_flag, for a client UNI STREAMS_BLOCKED frame (0x17) – the two directions have independent stream limits (RFC 9000 4.6), so the caller re-announces MAX_STREAMS for exactly the direction the peer reported blocked.
u64 max_streams_uni_seen
 RFC 9000 19.11: highest MAX_STREAMS(uni) value seen in any 1-RTT payload opened this step (gather_max_streams_uni in dispatch.c) – the peer raising how many uni streams THIS endpoint may open toward it.
int max_streams_uni_seen_flag
 1 once max_streams_uni_seen was set this step; same convention as max_data_seen_flag.
u8 path_challenge_rx_data [WIRED_SRVLOOP_PATH_RX][PATH_DATA]
 RFC 9000 8.2.2: the peer's own PATH_CHALLENGE data latched by dispatch this step – the owning runner MUST answer it with a PATH_RESPONSE on the arrival path (srvrun_path_answer); one entry per PATH_CHALLENGE frame, path_challenge_rx_n of them.
usz path_challenge_rx_n
 Entries latched in path_challenge_rx_data; the owner resets it.
u8 path_response_data [PATH_DATA]
 RFC 9000 8.2.2/19.18: the 8-byte data of a PATH_RESPONSE frame seen in any 1-RTT payload opened this step (gather_path_response in dispatch.c), valid only when path_response_seen_flag is set.
int path_response_seen_flag
 1 once path_response_data was set this step; not reset across steps by this loop itself, same convention as max_data_seen_ flag and streams_blocked_seen_flag.
ncid_frame ncid_rx [WIRED_SRVLOOP_NCID_RX]
 RFC 9000 19.15: the well-formed NEW_CONNECTION_ID frames processed this step, in arrival order; the owner stores them.
usz ncid_rx_n
 Entries used in ncid_rx; reset at the start of every step.
int ncid_malformed
 RFC 9000 19.15: 1 once a malformed NEW_CONNECTION_ID arrived (Retire Prior To above its Sequence Number, or a bad length): the owner closes with FRAME_ENCODING_ERROR.
u64 ecn_ect0
 RFC 9000 13.4 / RFC 9002 19.3.2: this connection's cumulative count of received datagrams marked ECT(0)/ECT(1)/CE (RFC 3168), monotonically increasing across the connection's whole lifetime – an ACK frame reports this running total, not one step's delta (see app_ack_encode_ranges in respond.c).
u64 ecn_ect1
 ECT(1) running total (same lifecycle as ecn_ect0's doc above).
u64 ecn_ce
 CE running total (same lifecycle as ecn_ect0's doc above).
wired_srvloop_pending_priority pending_priority [WIRED_SRVLOOP_MAX_PENDING_PRIORITY]
 RFC 9218 10 / 9218-010: PRIORITY_UPDATE frames naming a request stream not yet open, buffered until wired_srvloop_slot_for claims that stream id (see wired_srvloop_priority_apply).
wired_srvloop_ctrl_stream ctrl
 RFC 9114 6.2.1: the peer's single control stream, reassembled so its frames (SETTINGS/GOAWAY/PRIORITY_UPDATE) can be walked once complete – see wired_srvloop_ctrl_stream's own doc.
h3_control peer_ctrl
 RFC 9114 7.2.4 / draft-ietf-webtrans-http3-15 SS3.1 (WTH3-009/042): the client control stream's own SETTINGS-ordering state, latched as each control-stream frame is walked (priority_ctrl.c's ctrl_note_generic) – peer_ctrl.settings_seen is 1 once the client's SETTINGS has actually arrived, gating WebTransport CONNECT dispatch (srvrun.c) until it has.
u64 peer_wt_initial [3]
 draft-ietf-webtrans-http3-16 SS5.5.1-5.5.3: the client SETTINGS' SETTINGS_WT_INITIAL_MAX_STREAMS_UNI, BIDI and SETTINGS_WT_INITIAL_MAX DATA, in that order (0 = absent, the draft's default), latched as the SETTINGS frame is walked (priority_ctrl.c).
u16 priupdate_violation
 RFC 9218 7.1 / RFC 9114 8.1: the H3 connection error code of the most recent rejected PRIORITY_UPDATE this step (H3_FRAME_UNEXPECTED / H3_ID_ERROR), 0 when none was rejected.
u16 qpack_stream_violation
 RFC 9204 4.2 (9204-028): the H3 connection error code of a second QPACK encoder or decoder unidirectional stream seen this step (H3_STREAM_CREATION_ERROR), 0 when none was rejected.
int wt_signal_mid_stream_violation
 draft-ietf-webtrans-http3-15 4.3: 1 once a STREAM frame this step carried the WT_STREAM signal varint (0x41) as its own leading bytes at a NON-zero stream offset – "Endpoints MUST NOT send WT_STREAM as a frame type on HTTP/3 streams other than the very first bytes of a request stream.
wired_srvloop_reset peer_resets [WIRED_SRVLOOP_RESET_Q]
 RFC 9000 19.4/19.5: every RESET_STREAM/STOP_SENDING this step carried, in arrival order, with its wire error code.
usz peer_reset_n
 frames queued this step
u32 peer_reset_count
 RFC 9000 19.4/19.5, RFC 9114 10.5 (CVE-2023-44487-class rapid reset): how many RESET_STREAM/STOP_SENDING frames the peer has sent since the caller last cleared this – every one counts, unlike closed_stream_id's last-one-wins latch, so the caller (srvrun.c) can rate-limit resets per time window and close with H3_EXCESSIVE_LOAD.
const char * qlog_path
 qlog attribution for received-side stream frame events (mirrors srvrun_conn.qlog_slot/srvrun_cfg.qlog_path, set once at connection setup – srvloop itself never opens or writes the file, dispatch.c only reads these two fields via wired_qlog_append).
u64 qlog_group
 srvrun_conn.qlog_slot's value for this conn
u64 req_next_id
 RFC 9114 5.2: one past the largest client request stream id a streams[] slot was ever claimed for (id + 4), 0 before any – the stream id a GOAWAY sent now carries.
wired_srvloop_on_body on_body
 Streams request bodies to the app (see wired_srvloop_on_body), its ctx being req_ctx; 0 buffers each request whole (the default).
int req_frame_error
 RFC 9114 7.1: 1 once a streamed request body ended inside a frame – a connection error of type H3_FRAME_ERROR.
int ctrl_overflow
 RFC 9114 6.2.1: 1 once the peer control stream's unparsed backlog no longer fit WIRED_SRVLOOP_CTRL_BUF_CAP (ctrl's doc).
int flow_control_violation
 RFC 9000 4.1: 1 once a request STREAM frame reached past its slot's window (req_over) – past the credit this server ever grants a request stream, which never exceeds the window.
u64 req_body_released
 RFC 9000 4.1: streamed request-body bytes consumed (window base) on every request slot released so far – with the live slots' bases, the request side of the connection-wide MAX_DATA ceiling (srvrun.c).
u64 wt_refused [WIRED_SRVLOOP_MAX_STREAMS]
 RFC 9114 8.1: client WT bidi streams whose signal frame found every wt_streams[] slot busy.
usz wt_refused_n
 Count of queued ids in wt_refused.
int wt_refused_overflow
 RFC 9000 4.6: 1 once the peer opened past MAX_STREAMS – a refusal found wt_refused full (see wt_refused), or a frame named a client stream at or past peer_stream_limit (its payload is then dropped).
u64 peer_stream_limit [2]
 RFC 9000 4.6: the client bidi ([0]) and uni ([1]) stream limits currently advertised, set by the caller before each step; 0 leaves that type unchecked.
usz ctrl_settings_len
 RFC 9114 6.2.1: bytes of control-stream type + SETTINGS actually sent (respond.c's build_settings_frame), where a later control-stream append such as GOAWAY must continue.

Detailed Description

Per-connection state of the server wire loop, re-armed by wired_srvloop_init and driven by wired_srvloop_step.

Field order follows the doc grouping (related fields stay next to their shared comment) rather than the padding-optimal order clang-tidy's Padding check would prefer – reordering ~60 densely-commented fields purely to shave padding risks silently misattributing a comment to the wrong field, for a struct that is never allocated in bulk.

Field Documentation

◆ ack_defer

u8 wired_srvloop::ack_defer

When 1, respond.c's bare-ACK packet (emit_ack_only) is suppressed for the current step: the driving loop (srvrun.c) piggybacks the pending App-space ACK onto the response slice it is about to send, or flushes it itself at step end if no slice went out.

A caller that never sets it (0, every plain srvloop user) keeps the original behavior.

◆ ack_lo

u64 wired_srvloop::ack_lo[32]

ACK ranges (RFC 9000 19.3) seen in payloads opened this step, reset at the start of every wired_srvloop_step; overflow past the cap is dropped.

32 matches ack_decode's own max range count (ack.h), so a single ACK frame's ranges are never truncated here before the caller (multiple per-stream send sessions, each keyed by pn) gets to consume them. range lows, parallel with ack_hi

◆ ack_recv

pnspaces_recv wired_srvloop::ack_recv

RFC 9000 12.3/13.2.1/13.2.2/19.3: every packet number space's received-pn window (pnspaces_recv, independent per space – Initial is out of this loop's scope, srvboot's own layer) plus whether/when each space owes an ACK (ackpolicy, one instance per space since App and Handshake ack independently).

Indexed by PNS_APP/PNS_HANDSHAKE (transport/conn/lifecycle/conn/pnspace.h).

◆ closed_stream_id

u64 wired_srvloop::closed_stream_id

RFC 9000 19.4/19.8 (draft-ietf-webtrans-http3-15 SS4.4): the client bidi stream id a FIN or RESET_STREAM closed THIS step (a STOP_SENDING is queued in peer_resets instead – it ends OUR half, not the peer's), valid only when closed_stream_seen is set.

Mirrors peer_closed's shape: dispatch.c only records it, the caller (srvrun.c) decides what a closed id means for whatever session it may belong to (e.g. a WebTransport CONNECT stream closing independently of the rest of the connection) — this loop has no notion of a WT session and does not interpret the id.

◆ confirm_frames

u8 wired_srvloop::confirm_frames[320]

The confirmation packet's frame payload (SETTINGS + session ticket + HANDSHAKE_DONE), captured at its one-time emit so a lost confirmation can be replayed verbatim under a fresh pn (wired_srvloop_reconfirm, RFC 9000 19.20).

Replaying from this cache, not rebuilding, keeps the ticket's random sealing nonce – and so the CRYPTO bytes at offset 0 – identical across copies (RFC 9000 2.2).

◆ ctrl

wired_srvloop_ctrl_stream wired_srvloop::ctrl

RFC 9114 6.2.1: the peer's single control stream, reassembled so its frames (SETTINGS/GOAWAY/PRIORITY_UPDATE) can be walked once complete – see wired_srvloop_ctrl_stream's own doc.

Not reset across steps by this loop itself (mirrors the streams[] reassembly convention).

◆ ctrl_overflow

int wired_srvloop::ctrl_overflow

RFC 9114 6.2.1: 1 once the peer control stream's unparsed backlog no longer fit WIRED_SRVLOOP_CTRL_BUF_CAP (ctrl's doc).

The caller (srvrun.c) closes with H3_EXCESSIVE_LOAD.

◆ ctrl_settings_len

usz wired_srvloop::ctrl_settings_len

RFC 9114 6.2.1: bytes of control-stream type + SETTINGS actually sent (respond.c's build_settings_frame), where a later control-stream append such as GOAWAY must continue.

Recorded, not recomputed: SETTINGS carries a random grease pair, so a re-encode may differ in length.

◆ done_slots

u8 wired_srvloop::done_slots[WIRED_SRVLOOP_MAX_STREAMS]

Every slot whose request completed THIS step, in completion order – the multi-request counterpart of the single got_request/req mirror above (which only carries the last one).

Reset at the start of every wired_srvloop_step; each entry indexes streams[], whose slot holds its own decoded req (views valid until that slot's next request begins).

◆ drop_newer

int wired_srvloop::drop_newer

RFC 9000 9.6.2, set by the caller before a step: discard a 1-RTT packet numbered above every number received so far, before its frames or ACK bookkeeping (the connection moved to its preferred address and this datagram arrived on the old one).

Older packets still process.

◆ ecn_ack_seen

u8 wired_srvloop::ecn_ack_seen

RFC 9000 19.3.2: the ECN counts of the type-0x03 ACK with the largest acknowledged packet number opened this step (13.4.2.1: a reordered older ACK must not overwrite them), reset with ack_n.

ecn_ack_seen == 0 with ack_n > 0 means this step's ACKs carried no ECN feedback – the caller's ECN validation (RFC 9000 13.4.2) consumes both cases. These are the PEER's counts about packets WE sent; the ecn_ect0/ect1/ce members further down are the opposite direction (our own receive-side running totals reported back in our ACKs). 1 once a type-0x03 ACK was opened this step

◆ ecn_ect0

u64 wired_srvloop::ecn_ect0

RFC 9000 13.4 / RFC 9002 19.3.2: this connection's cumulative count of received datagrams marked ECT(0)/ECT(1)/CE (RFC 3168), monotonically increasing across the connection's whole lifetime – an ACK frame reports this running total, not one step's delta (see app_ack_encode_ranges in respond.c).

Advanced by wired_srvloop_ecn_note, called once per received datagram with the ECN codepoint the UDP layer read from its IP_TOS cmsg (mmsg_buf.ecn in udp.h). 0 for all three until any ECN-marked datagram arrives.

◆ flow_control_violation

int wired_srvloop::flow_control_violation

RFC 9000 4.1: 1 once a request STREAM frame reached past its slot's window (req_over) – past the credit this server ever grants a request stream, which never exceeds the window.

The caller (srvrun.c) closes with FLOW_CONTROL_ERROR.

◆ frame_unexpected_slots

u8 wired_srvloop::frame_unexpected_slots[WIRED_SRVLOOP_MAX_STREAMS]

RFC 9114 7.2.5/7.2.8 (9114-067/9114-073): every slot whose request stream carried a PUSH_PROMISE or HTTP/2-only reserved frame type this step (streams[i].req.frame_unexpected) – the H3_FRAME_UNEXPECTED counterpart of incomplete_slots above.

A slot never appears in both lists: the decoder rejects the frame before FIN/completion accounting runs, so this takes priority. Reset at the start of every wired_srvloop_step.

◆ got_request

int wired_srvloop::got_request

Mirrors the most recently completed request this step, across whichever slot decoded it — the pre-existing single-stream API surface (got_request/ req), kept so existing callers reading these two fields directly need no change.

For the single-request-stream (id 0) case this is exactly the old behavior; wired_srvloop_step also updates it for whichever slot completed last if more than one did.

◆ incomplete_slots

u8 wired_srvloop::incomplete_slots[WIRED_SRVLOOP_MAX_STREAMS]

RFC 9114 4.1: every slot whose request stream terminated (FIN) THIS step WITHOUT producing a request (streams[i].req_incomplete) – the H3_REQUEST_INCOMPLETE counterpart of done_slots above.

A slot never appears in both lists: request_complete decodes at most once, so a completion is either a request (done_slots) or an incomplete stream (incomplete_slots). Reset at the start of every wired_srvloop_step.

◆ malformed_slots

u64 wired_srvloop::malformed_slots

RFC 9114 4.1.2: bit i is set when incomplete_slots holds slot i because its whole HEADERS was malformed rather than cut short – aborted with H3_MESSAGE_ERROR instead of H3_REQUEST_INCOMPLETE.

Reset at the start of every wired_srvloop_step.

◆ max_data_seen

u64 wired_srvloop::max_data_seen

RFC 9000 19.9: highest MAX_DATA value seen across every 1-RTT payload opened this step (gather_max_data in dispatch.c) – the connection-level send credit ceiling this endpoint may now use.

0 = none seen this step (the caller, srvrun.c, only raises its own running credit when this is higher than what it already holds; a lower or absent value here is a no-op per RFC 9000 4.1's "never decreases"). Not reset across steps by this loop itself – srvrun.c's own credit state is the only thing that persists across steps; this field is this step's observation only.

◆ max_stream_data_n

usz wired_srvloop::max_stream_data_n

Slots in max_stream_data_stream_id/_value actually used this step (0 to WIRED_SRVLOOP_MAX_STREAMS).

0 = none seen.

◆ max_stream_data_stream_id

u64 wired_srvloop::max_stream_data_stream_id[WIRED_SRVLOOP_MAX_STREAMS]

RFC 9000 19.10: every distinct MAX_STREAM_DATA (stream id, value) seen this step, one slot per distinct stream id named (up to WIRED_SRVLOOP_MAX_STREAMS – a single step coalescing a MAX_STREAM_DATA per in-flight response, e.g.

3 parallel GETs each raised by the peer at once, must not lose all but the last one the way a single-slot latch would: srvrun.c only checks ONE resp[] slot's credit per raise, so a dropped update leaves that stream's send credit stuck at its initial value forever, and a large streamed response silently stalls at that ceiling). A repeat stream id this step overwrites its own slot instead of consuming a second one (only the newest value matters, same as the old single-latch behavior for a given stream). srvrun.c drains every used slot once per step.

◆ max_stream_data_value

u64 wired_srvloop::max_stream_data_value[WIRED_SRVLOOP_MAX_STREAMS]

RFC 9000 19.10: the value carried by the same-indexed max_stream_data_stream_id slot.

Valid only for i < max_stream_data_n.

◆ max_streams_uni_seen

u64 wired_srvloop::max_streams_uni_seen

RFC 9000 19.11: highest MAX_STREAMS(uni) value seen in any 1-RTT payload opened this step (gather_max_streams_uni in dispatch.c) – the peer raising how many uni streams THIS endpoint may open toward it.

Same running-high-water/flag split as max_data_seen.

◆ ncid_malformed

int wired_srvloop::ncid_malformed

RFC 9000 19.15: 1 once a malformed NEW_CONNECTION_ID arrived (Retire Prior To above its Sequence Number, or a bad length): the owner closes with FRAME_ENCODING_ERROR.

Never cleared by this loop.

◆ now_ms

u64 wired_srvloop::now_ms

Monotonic ms this step is being driven at – the time source ackpolicy's delayed-ACK timer measures against.

The caller (e.g. srvrun.c) sets this once per step, sharing its own PTO/RTT time source (srvrun_step_ctx.now_ms) rather than adding a second clock; a caller that never sets it (0) simply never ages a pending ACK past the delay window via elapsed time alone (the two-eliciting-packets immediate-ack path still fires). Living on wired_srvloop rather than wired_srvloop_conn keeps wired_srvloop_step's existing signature and every current struct-literal call site unchanged.

◆ path_response_data

u8 wired_srvloop::path_response_data[PATH_DATA]

RFC 9000 8.2.2/19.18: the 8-byte data of a PATH_RESPONSE frame seen in any 1-RTT payload opened this step (gather_path_response in dispatch.c), valid only when path_response_seen_flag is set.

This loop has no notion of path validation (that lives in srvrun_conn.path, srvrun.c) – it only latches the raw bytes, mirroring max_data_seen's split of responsibility (gather here, interpret in the caller).

◆ peer_reset_count

u32 wired_srvloop::peer_reset_count

RFC 9000 19.4/19.5, RFC 9114 10.5 (CVE-2023-44487-class rapid reset): how many RESET_STREAM/STOP_SENDING frames the peer has sent since the caller last cleared this – every one counts, unlike closed_stream_id's last-one-wins latch, so the caller (srvrun.c) can rate-limit resets per time window and close with H3_EXCESSIVE_LOAD.

Never reset by this loop itself; srvrun.c clears it at its own window edge.

◆ peer_resets

wired_srvloop_reset wired_srvloop::peer_resets[WIRED_SRVLOOP_RESET_Q]

RFC 9000 19.4/19.5: every RESET_STREAM/STOP_SENDING this step carried, in arrival order, with its wire error code.

This loop has no notion of which stream id is a WT data stream, a CONNECT stream or a plain request stream – the caller (srvrun.c) resolves each entry and clears peer_reset_n. peer_reset_n keeps counting past WIRED_SRVLOOP_RESET_Q (entries beyond it are not stored) so the caller sees the overflow.

◆ pending_priority

RFC 9218 10 / 9218-010: PRIORITY_UPDATE frames naming a request stream not yet open, buffered until wired_srvloop_slot_for claims that stream id (see wired_srvloop_priority_apply).

Not reset across steps by this loop itself – a pending entry lives until its stream opens or the table is re-armed by wired_srvloop_init.

◆ priupdate_violation

u16 wired_srvloop::priupdate_violation

RFC 9218 7.1 / RFC 9114 8.1: the H3 connection error code of the most recent rejected PRIORITY_UPDATE this step (H3_FRAME_UNEXPECTED / H3_ID_ERROR), 0 when none was rejected.

Mirrors datagram_violation's shape: dispatch.c only latches it, the caller driving the loop decides how to close the connection over it.

◆ qlog_path

const char* wired_srvloop::qlog_path

qlog attribution for received-side stream frame events (mirrors srvrun_conn.qlog_slot/srvrun_cfg.qlog_path, set once at connection setup – srvloop itself never opens or writes the file, dispatch.c only reads these two fields via wired_qlog_append).

0/unset means no qlog path configured, matching every other qlog_path-gated caller's no-op convention.

◆ qpack_stream_violation

u16 wired_srvloop::qpack_stream_violation

RFC 9204 4.2 (9204-028): the H3 connection error code of a second QPACK encoder or decoder unidirectional stream seen this step (H3_STREAM_CREATION_ERROR), 0 when none was rejected.

Mirrors priupdate_violation's shape: dispatch.c only latches it via wired_h3srv_on_peer_qpack, the caller driving the loop decides how to close the connection over it.

◆ req_closed

wired_srvloop_closed wired_srvloop::req_closed

RFC 9000 3.2: client bidi streams already answered and released – request streams and WT bidi streams share this id space.

Re-admitted "zombies" once filled the table until genuinely new streams were dropped.

◆ req_frame_error

int wired_srvloop::req_frame_error

RFC 9114 7.1: 1 once a streamed request body ended inside a frame – a connection error of type H3_FRAME_ERROR.

dispatch.c only latches it; the caller (srvrun.c) closes the connection and clears it.

◆ reset_slotless_n

usz wired_srvloop::reset_slotless_n

RFC 9000 4.6: RESET_STREAMs this step that closed a request stream which never got a slot (its STREAM frames lost or dropped) – each still used one bidi stream credit, owed back once.

Reset at the start of every wired_srvloop_step.

◆ reset_slots

u64 wired_srvloop::reset_slots

RFC 9000 3.2: bit i is set when a RESET_STREAM this step ended slot i's request while it was still being received – not one completed or rejected this step (those lists' owners answer it).

A slot answered in an earlier step is re-armed and so set too; the caller keeps it while its response is in flight. Reset at the start of every wired_srvloop_step.

◆ rx_datagram_n

usz wired_srvloop::rx_datagram_n

count of entries valid in rx_datagrams, 0..WIRED_SRVLOOP_MAX_RX_DATAGRAMS.

Once the queue is full, a newly arrived datagram is dropped (matching RFC 9221's unreliable-delivery semantics) rather than overwriting an already-queued one — this is the receive-side counterpart of the send side's single-slot "last write wins", chosen because losing an already-arrived datagram to a same-step overwrite is worse.

◆ rx_datagrams

RFC 9221 5: received QUIC DATAGRAM frame payloads queued for a future consumer to drain (Phase 7b Slice 2), oldest first.

Filled by gather_rx_datagrams in dispatch.c alongside the request/WT-stream gathering above — a single 1-RTT packet may coalesce a DATAGRAM frame with a request or WT stream frame, so this runs independently of both.

◆ spare_cid

u8 wired_srvloop::spare_cid[20]

RFC 9000 5.1.1/19.15: one spare connection ID handed to the client in a NEW_CONNECTION_ID frame at confirmation, so it CAN migrate – a client holding no unused CID must not initiate migration (RFC 9000 9).

Issued by the owning runner at slot open (which also routes it); spare_cid_len 0 means none was issued and no frame is sent.

◆ streams

RFC 9000 2.2: one reassembly slot per concurrent client bidi (request) stream, looked up/allocated by stream id (see stream_slot_find/alloc in srvloop.c).

streams[0] is claimed for stream id 0 on the connection's first request, exactly as the old single-slot fields were — so a connection that only ever uses stream 0 behaves identically to before.

◆ streams_blocked_seen_flag

int wired_srvloop::streams_blocked_seen_flag

RFC 9000 19.14: 1 once a client bidi STREAMS_BLOCKED frame was seen in any 1-RTT payload opened this step (gather_streams_blocked in dispatch.c) – the peer's own reported limit value is not latched (srvrun.c computes the re-grant from its own receive-side slot state, RFC 9000 4.6/19.11, rather than trusting the peer's claim).

Not reset across steps by this loop itself, same convention as max_data_seen_ flag: this step's observation only.

◆ we_advertised_max_datagram

u64 wired_srvloop::we_advertised_max_datagram

RFC 9221 3: this connection's own advertised max_datagram_frame_size transport parameter value, 0 = not advertised (same sentinel convention as wired_srvboot_id.max_datagram_frame_size, which this is populated from at connection boot — see srvrun_boot_finish).

Used by dispatch.c's DATAGRAM gathering to reject a frame the peer had no right to send (datagram_recv_ok).

◆ wt_refused

u64 wired_srvloop::wt_refused[WIRED_SRVLOOP_MAX_STREAMS]

RFC 9114 8.1: client WT bidi streams whose signal frame found every wt_streams[] slot busy.

dispatch.c only queues them; the caller (srvrun.c) refuses each with H3_REQUEST_REJECTED, gives its stream credit back, and clears wt_refused_n. The bidi credit never has more than WIRED_SRVLOOP_MAX_STREAMS new streams outstanding, so the queue cannot overflow for a peer that honors MAX_STREAMS.

◆ wt_refused_overflow

int wired_srvloop::wt_refused_overflow

RFC 9000 4.6: 1 once the peer opened past MAX_STREAMS – a refusal found wt_refused full (see wt_refused), or a frame named a client stream at or past peer_stream_limit (its payload is then dropped).

The caller (srvrun.c) closes with STREAM_LIMIT_ERROR and clears it.

◆ wt_signal_mid_stream_violation

int wired_srvloop::wt_signal_mid_stream_violation

draft-ietf-webtrans-http3-15 4.3: 1 once a STREAM frame this step carried the WT_STREAM signal varint (0x41) as its own leading bytes at a NON-zero stream offset – "Endpoints MUST NOT send WT_STREAM as a frame type on HTTP/3 streams other than the very first bytes of a request stream.

Receiving this frame type in any other circumstances MUST be treated as a connection error of type H3_FRAME_ERROR." Mirrors datagram_violation's shape: dispatch.c only latches it, the caller driving the loop (srvrun.c) closes the connection over it. Not reset across steps by this loop itself, same convention as max_data_seen_flag (the caller consumes and clears it every step).

◆ wt_streams

draft-ietf-webtrans-http3-15 4.3: one reassembly slot per concurrent WT bidi stream, separate from streams[] above (see wired_srvloop_wt_stream_slot's doc for why).

Reachable here so a future slice can wire an app-facing callback over it; this slice only reassembles and associates with the connection's WT session, it does not deliver.

◆ wt_uni_closed

wired_srvloop_closed wired_srvloop::wt_uni_closed

RFC 9000 3.2: client WT uni streams already released.

Exact ids, not a high-watermark ("reject any id <= the highest released" also refused NEW lower-id streams loss-delayed past a faster one's whole lifetime, losing a whole chat message), and not a short ring (a MoQT publisher's many short uni streams pushed an id out of an 8-entry ring, and its late duplicate re-claimed a slot and was delivered twice).


The documentation for this struct was generated from the following file: