ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
h2_conn.h
Go to the documentation of this file.
1// ProtoCore v1.0.16 - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file protocore_h2_conn.h
6 * @brief HTTP/2 connection + stream engine (RFC 9113) over the HPACK + frame layers.
7 *
8 * One H2Conn drives a single HTTP/2 connection: it consumes the client connection preface, the
9 * SETTINGS exchange, and the frame stream; reassembles each request's header block (HEADERS +
10 * CONTINUATION) and HPACK-decodes it; tracks per-stream state and connection / stream flow
11 * control; and answers control frames (SETTINGS ACK, PING ACK, WINDOW_UPDATE). Decoded requests
12 * and body data are handed to the application through callbacks, and protocore_h2_conn_respond() serializes
13 * a response as HEADERS + DATA frames. Outbound bytes go through a caller-supplied writer, so the
14 * engine has no transport dependency and is host-testable by feeding it a byte stream.
15 *
16 * Fixed storage, no heap: one frame-reassembly buffer, one header-block buffer, an HPACK decoder
17 * table, and a small stream table per connection (sizes from PROTOCORE_H2_*).
18 *
19 * @author Douglas Quigg (dstroy0)
20 * @date 2026
21 */
22
23#ifndef PROTOCORE_H2_CONN_H
24#define PROTOCORE_H2_CONN_H
25
26#include "protocore_config.h" // the entry point: the enable gate below, and the widths
27
28#if PROTOCORE_ENABLE_HTTP2
29
31
32#define PROTOCORE_H2_FRAME_HDR_CAP 16u
33/** @brief The widest frame a received frame provokes us to send: a header plus 8 opaque bytes. */
34#define PROTOCORE_H2_CTL_FRAME_MAX 17u
35/**
36 * @brief This module's draw on the plaintext pool, declared here and asserted in h2_conn.c.
37 *
38 * One borrow per connection from the secure pool's persistent end, split by offset into the engine
39 * context, the frame payload buffer, the header-block buffer, the HPACK emit scratch and the
40 * 9-octet frame header. HTTP/2 runs over TLS, so the bytes are secure and the connection owns them.
41 */
42#define PROTOCORE_H2_CONN_BORROW \
43 ((size_t)PROTOCORE_H2_CONN_RECORD + PROTOCORE_H2_MAX_FRAME + PROTOCORE_H2_HDR_BLOCK + PROTOCORE_H2_HDR_BLOCK + \
44 PROTOCORE_H2_FRAME_HDR_CAP)
45
46/** @brief Application callbacks the engine drives (all optional except write). */
47typedef struct
48{
49 /** @brief Send @p len bytes to the peer (through TLS/transport); must send all. */
50 void (*write)(void *io, const uint8_t *data, size_t len);
51 /** @brief One decoded request header on @p stream_id (pseudo-headers included). */
52 void (*on_header)(void *app, uint32_t stream_id, const char *name, size_t nlen, const char *val, size_t vlen);
53 /**
54 * @brief The request header block for @p stream_id is complete. @p end_stream: no body.
55 * @return false if the request is malformed; the engine resets the stream (RFC 9113 sec 8.1.1).
56 */
57 proto_bool (*on_headers_end)(void *app, uint32_t stream_id, proto_bool end_stream);
58 /** @brief Request body bytes on @p stream_id (@p end_stream marks the last). */
59 void (*on_data)(void *app, uint32_t stream_id, const uint8_t *data, size_t len, proto_bool end_stream);
60 void *io; ///< opaque, passed to write()
61 void *app; ///< opaque, passed to the on_* callbacks
62} H2Callbacks;
63
64/** @brief What ::H2ConnNs::init installs. */
65typedef struct
66{
67 const H2Callbacks *cb; ///< the callbacks the engine drives
68} H2ConnInitArgs;
69
70/** @brief The inbound bytes ::H2ConnNs::recv feeds through the state machine. */
71typedef struct
72{
73 const uint8_t *data; ///< the bytes that arrived
74 size_t len; ///< how many
75} H2ConnRecvArgs;
76
77/** @brief RFC 9113 sec 8.3: what one HEADERS + DATA response carries. */
78typedef struct
79{
80 uint32_t stream_id; ///< the stream it answers
81 int status; ///< the status it carries
82 const char *content_type; ///< its media type, or NULL
83 const char *body; ///< its body bytes
84 size_t body_len; ///< how many
85} H2ConnRespondArgs;
86
87/** @brief RFC 9113 sec 6.8: the error a graceful shutdown reports. */
88typedef struct
89{
90 uint32_t error; ///< the code the GOAWAY carries
91} H2ConnGoawayArgs;
92
93/**
94 * @brief One HTTP/2 connection's engine (RFC 9113).
95 *
96 * A caller sets the members a call takes, invokes it through ::H2Conn, and reads the outcome off
97 * the same handle.
98 *
99 * @var H2ConnNs::init_args the callbacks an init installs
100 * @var H2ConnNs::recv_args the bytes a feed carries
101 * @var H2ConnNs::respond_args what a serialized response carries
102 * @var H2ConnNs::goaway_args the error a shutdown reports
103 * @var H2ConnNs::ok a call's true/false outcome
104 * @var H2ConnNs::init start the engine and send our initial SETTINGS through cb.write
105 * @var H2ConnNs::recv feed inbound bytes; drives the machine, invokes callbacks, writes control frames
106 * @var H2ConnNs::respond serialize HEADERS + DATA on a stream and close it
107 * @var H2ConnNs::goaway send a GOAWAY to begin a graceful shutdown
108 *
109 * Every entry takes one connection's borrow. How those bytes are carved is h2_conn.c's and is
110 * never named here; ::PROTOCORE_H2_CONN_BORROW is how many a caller must hand over.
111 */
112typedef struct
113{
114 H2ConnInitArgs init_args; ///< the members ::H2ConnNs::init takes
115 H2ConnRecvArgs recv_args; ///< the members ::H2ConnNs::recv takes
116 H2ConnRespondArgs respond_args; ///< the members ::H2ConnNs::respond takes
117 H2ConnGoawayArgs goaway_args; ///< the members ::H2ConnNs::goaway takes
118 proto_bool ok; ///< a call's true/false outcome
119} H2ConnVars;
120
121/** @brief The operands and the outcome. */
122extern H2ConnVars H2ConnV;
123
124/** @brief The entries. */
125typedef struct
126{
127 void (*const init)(uint8_t *work);
128 void (*const recv)(uint8_t *work);
129 void (*const respond)(uint8_t *work);
130 void (*const goaway)(uint8_t *work);
131} H2ConnNs;
132
133// What the table binds, defined once in the .c and taking one parameter each: everything
134// else an entry needs is an operand in H2ConnV or a region of the borrow at a fixed offset.
135void protocore_h2_conn_init(uint8_t *work);
136void protocore_h2_conn_recv(uint8_t *work);
137void protocore_h2_conn_respond(uint8_t *work);
138void protocore_h2_conn_goaway(uint8_t *work);
139
140// `static const`, initialised HERE rather than `extern` against a definition in the .c: a
141// const object whose initializer every translation unit can see is a COMPILE-TIME FACT, so
142// `H2Conn.init(work)` resolves to a named function and becomes a DIRECT call. An extern table
143// leaves the call indirect and the symbol live at every level, -O2 -flto included.
144static const H2ConnNs H2Conn __attribute__((unused)) = {
145 .init = protocore_h2_conn_init,
146 .recv = protocore_h2_conn_recv,
147 .respond = protocore_h2_conn_respond,
148 .goaway = protocore_h2_conn_goaway,
149};
150
152
153#endif // PROTOCORE_ENABLE_HTTP2
154
155#endif // PROTOCORE_H2_CONN_H
#define PROTOCORE_BEGIN_DECLS
Give a header's declarations C linkage, so their symbol names carry no parameter types.
Definition types.h:96
_Bool proto_bool
The truth value.
Definition types.h:64
#define PROTOCORE_END_DECLS
Definition types.h:97