ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
feature_dependency_en.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 feature_dependency_en.h
6 * @brief The flags a build does not set: the ones another flag decides.
7 *
8 * Most features are independent and are stated directly in protocore_config.h. These are the rest -
9 * a flag whose value is read off another flag, or one an enabled feature forces on because it cannot
10 * work without it. Reached after every directly-stated flag is settled, so each reads final values.
11 *
12 * @author Douglas Quigg (dstroy0)
13 * @date 2026
14 */
15
16#ifndef PROTOCORE_DEPENDENCY_EN_H
17#define PROTOCORE_DEPENDENCY_EN_H
18
19#ifndef PROTOCORE_CONFIG_H
20#error "include protocore_config.h instead of this file - it is the entry point that states the feature flags"
21#endif
22/**
23 * @brief Streamlined NTRU Prime sntrup761x25519-sha512@openssh.com SSH KEX (default: tracks
24 * ::PROTOCORE_ENABLE_PQC_KEX).
25 *
26 * A second PQ/T hybrid alongside ML-KEM: sntrup761 (a lattice KEM with a conservative security
27 * margin, OpenSSH's long-standing default) crossed with X25519, SHA-512 exchange hash. On by
28 * default wherever the PQC hybrid is enabled so a PQC-capable peer gets both methods offered.
29 * It is heavier than ML-KEM on the worker stack - the server runs Encaps (~22 KB peak) and the
30 * reverse-SSH client runs KeyGen+Decaps (the FO re-encrypt peaks ~32 KB) - so a footprint-bound
31 * PQC build (e.g. a classic-ESP32 that only wants ML-KEM) can set this to 0 to drop sntrup761 and
32 * keep the lighter ::PROTOCORE_WORKER_STACK_PQC_MIN floor. Requires ::PROTOCORE_ENABLE_PQC_KEX.
33 */
34#ifndef PROTOCORE_ENABLE_SSH_SNTRUP761
35#define PROTOCORE_ENABLE_SSH_SNTRUP761 PROTOCORE_ENABLE_PQC_KEX
36#endif
37
38/**
39 * @brief Modbus RTU framing (serial / RS-485) over the same data model + PDU dispatch.
40 *
41 * Default off; implies PROTOCORE_ENABLE_MODBUS. Adds the RTU ADU codec
42 * `Modbus.rtu_process_adu` - a `[slave addr][PDU][CRC16]` frame (CRC16-Modbus,
43 * little-endian) around the existing host-tested PDU dispatch: a CRC mismatch or a
44 * non-matching unit address is dropped silently (no reply, per the spec), and a
45 * broadcast (address 0) is executed without a reply. The codec is pure and
46 * host-tested; feed it from a UART/RS-485 driver (the serial transport is the
47 * application's, framed by the 3.5-char inter-frame idle).
48 */
49#ifndef PROTOCORE_ENABLE_MODBUS_RTU
50#define PROTOCORE_ENABLE_MODBUS_RTU 0
51#endif
52// RTU is a framing over the same PDU codec, so it needs Modbus compiled in. Declared as a hard
53// dependency rather than OR-ed into a second flag the module then guards on: a derived flag is
54// invisible to the build. gen_modules.py reads a module's gate off its own source and matches
55// PROTOCORE_ENABLE_\w+ only, so a file wrapped in `#if PROTOCORE_NEED_MODBUS` had no gate as far as
56// CMake was concerned and was compiled into every target - the derived flag defeated the gating the
57// stated one is for. A build that wants RTU states Modbus too.
58
59/**
60 * @brief NMEA 2000 codec (`services/nmea2000`).
61 *
62 * Default off; implies PROTOCORE_ENABLE_J1939 (NMEA 2000 is J1939 at the transport layer). A
63 * zero-heap codec for the marine instrumentation network over CAN: it reuses the J1939 29-bit
64 * identifier codec and adds the NMEA-specific Fast Packet transport - `protocore_n2k_fastpacket_build_frame`
65 * splits a 9..223-octet message across frames (a control octet of sequence + frame counter,
66 * the first frame carrying the total length) and `protocore_n2k_fastpacket_feed` reassembles it;
67 * `protocore_n2k_build_single` wraps a single-frame message. Pure codec, host-tested. Drive it from the
68 * ESP32 TWAI peripheral or an MCP2515 over SPI to bridge an NMEA 2000 backbone onto Wi-Fi.
69 */
70#ifndef PROTOCORE_ENABLE_NMEA2000
71#define PROTOCORE_ENABLE_NMEA2000 0
72#endif
73// NMEA 2000 reuses the J1939 identifier codec, so it needs J1939 compiled in.
74
75/**
76 * @brief SenML (RFC 8428) measurement-pack builder (`services/senml`).
77 *
78 * Default off; implies PROTOCORE_ENABLE_CBOR (the SenML-CBOR form uses the CBOR writer). A
79 * zero-heap SenML-JSON + SenML-CBOR encoder over the shipped JSON / CBOR codecs: the caller
80 * fills a `SenmlRecord` array (base name/time, name, unit, one value, time) and
81 * `Senml.json_build` / `Senml.binary_build` (any protocore_codec) emit the whole Pack. Numbers are
82 * emitted as integers when integral (so timestamps keep precision), else floats. The standard
83 * measurement format for CoAP / LwM2M / HTTP telemetry. Pure codec, host-tested.
84 */
85#ifndef PROTOCORE_ENABLE_SENML
86#define PROTOCORE_ENABLE_SENML 0
87#endif
88// SenML's binary form is CBOR, so it needs the CBOR codec compiled in.
89
90/**
91 * @brief Sparkplug B payload + topic codec (`services/sparkplug`).
92 *
93 * Default off; implies PROTOCORE_ENABLE_PROTOBUF (the payload is a Protobuf message). A zero-heap
94 * builder for the Eclipse Sparkplug B industrial-IoT MQTT payload (`Sparkplug.build_payload` /
95 * `Sparkplug.build_metric`, over the protobuf codec) and its topic namespace
96 * (`Sparkplug.build_topic`, `spBv1.0/group/type/node[/device]`). Field numbers + datatype codes
97 * verified against Sparkplug 3.0.0 sec 6.4.1. Pure codec, host-tested; publish it with the MQTT client.
98 */
99#ifndef PROTOCORE_ENABLE_SPARKPLUG
100#define PROTOCORE_ENABLE_SPARKPLUG 0
101#endif
102// Sparkplug B payloads are protobuf messages, so it needs the protobuf codec compiled in.
103
104// The NTP server answers from protocore_time_now(), so with the registry off it holds no clock and drops
105// every request instead of serving a wrong one. That is a bind that never answers, so it fails here.
106
107// The adaptive announcer re-applies a TXT record through the responder and counts contention
108// through the promiscuous sink, so both are what it drives. Stated here so the module is one arm
109// rather than a capability test around half its own entries.
110
111/**
112 * @brief Opt-in CDN edge-cache tier (PROTOCORE_ENABLE_EDGE_CACHE, requires HTTP_CACHE).
113 *
114 * server/web/edge_cache is the caching reverse-proxy edge that network_drivers/presentation/http/httpcache is the
115 * origin-side groundwork for: a device sits in front of a remote upstream origin, fetches a response once, and serves
116 * subsequent hits from a bounded local store - honoring `Cache-Control` / `Expires` / `ETag` / `Last-Modified`,
117 * revalidating stale entries with conditional requests (`If-None-Match` / `If-Modified-Since` -> 304), and serving
118 * `Range` / `206` straight from the cache. A two-tier store: bounded RAM (L1, hot) plus an optional dbm/WAL-backed SD
119 * tier (L2, persistent, when PROTOCORE_ENABLE_DBM is set). Misses/revalidations fetch the origin asynchronously (the
120 * client request is suspended and resumed from the poll loop, never stalling the worker) and always fail open. Zero
121 * heap. Default off.
122 */
123#ifndef PROTOCORE_ENABLE_EDGE_CACHE
124#define PROTOCORE_ENABLE_EDGE_CACHE 0
125#endif
126// Opt-in TLS upstream origins: when set, a mapped `https://` origin is fetched over the shared client-TLS
127// session (protocore_tls_csess) instead of being rejected. One outbound TLS origin fetch at a time (the session is
128// a singleton, shared with MQTTS/wss); the handshake blocks the worker briefly at connect (like the MQTT/WS
129// clients). Needs the TLS engine + the ~48 KB arena - an S3 / PSRAM board is recommended.
130/* Derived sizing for the edge cache. Macros, not constexpr: PROTOCORE_EDGE_FETCH_BUF's default is
131 * computed from PROTOCORE_EDGE_MESH_RESP_MAX below and the requirement is enforced with an #error,
132 * and the preprocessor can evaluate neither `constexpr` nor `sizeof`. SRCBANNED rule 18. */
133
134/**
135 * @brief Opt-in mesh (sibling-cache) distribution for the edge cache (PROTOCORE_ENABLE_EDGE_MESH).
136 *
137 * Lets a fleet of edge nodes share one warm cache: on a full local miss, a node queries its configured
138 * sibling peers (over a plaintext PROTO_MESH TCP link) before hitting the origin, and pulls a
139 * fresh copy from whichever peer has it - so the origin is fetched once per fleet, not once per node. Pull
140 * (read-through) only: no push, no invalidation protocol, no consistency window - a stale sibling copy
141 * self-expires by its own TTL and the requester re-checks freshness on arrival. The transfer carries the
142 * object plus its freshness/age (RFC 9111 age propagation), so a sibling-fresh object serves for its
143 * remaining lifetime with zero origin contact. A serving node answers only from its local store (one hop,
144 * never re-querying its own origin/peers, so the fleet cannot loop). Peers are a static list
145 * (protocore_edge_cache_add_peer); auto-discovery is a follow-up. Zero heap. Default off.
146 */
147#ifndef PROTOCORE_ENABLE_EDGE_MESH
148#define PROTOCORE_ENABLE_EDGE_MESH 0
149#endif
150
151/**
152 * @brief Internal: the parser's streaming-body machinery (OTA, file upload, WebDAV PUT).
153 *
154 * Each streams the request body to a sink instead of buffering it into body[]; the
155 * parser support is shared and compiled when any of these features is enabled. The
156 * sink is a single global hook, so only one streaming consumer is active per build
157 * (the last to register wins) - do not combine OTA / upload / WebDAV streaming in
158 * the same firmware.
159 */
160#if PROTOCORE_ENABLE_OTA || PROTOCORE_ENABLE_UPLOAD || PROTOCORE_ENABLE_WEBDAV
161#define PROTOCORE_ENABLE_STREAM_BODY 1
162#else
163#define PROTOCORE_ENABLE_STREAM_BODY 0
164#endif
165
166/**
167 * @brief Internal: client-side TLS engine is compiled (HTTPS client, MQTTS, wss client, and/or a TLS edge-cache
168 * origin).
169 *
170 * The outbound HTTP client (one-shot exchange) and the MQTT / WebSocket clients
171 * and the edge cache's TLS origin fetch (persistent sessions) share the same
172 * client mbedTLS code in protocore_tls - the CA/pin trust config, the BIO typedefs,
173 * and the session API - gated by this.
174 */
175// Derived: these carry the expression their header used to hold.
176#ifndef PROTOCORE_ENABLE_AES128GCM
177#define PROTOCORE_ENABLE_AES128GCM \
178 (PROTOCORE_ENABLE_HTTP3 || PROTOCORE_ENABLE_DTLS || PROTOCORE_ENABLE_SMB || PROTOCORE_ENABLE_TLS)
179#endif
180#ifndef PROTOCORE_ENABLE_AESCCM
181#define PROTOCORE_ENABLE_AESCCM PROTOCORE_ENABLE_SMB
182#endif
183#ifndef PROTOCORE_ENABLE_HKDF
184#define PROTOCORE_ENABLE_HKDF (PROTOCORE_ENABLE_HTTP3 || PROTOCORE_ENABLE_DTLS || PROTOCORE_ENABLE_TLS)
185#endif
186// The HPACK/QPACK integer and Huffman string primitives (RFC 7541 sec 5), read by the HTTP/2 header
187// table and the HTTP/3 QPACK encoder.
188#ifndef PROTOCORE_ENABLE_HPACK_PRIM
189#define PROTOCORE_ENABLE_HPACK_PRIM (PROTOCORE_ENABLE_HTTP2 || PROTOCORE_ENABLE_HTTP3)
190#endif
191#ifndef PROTOCORE_ENABLE_SHA384
192#define PROTOCORE_ENABLE_SHA384 (PROTOCORE_ENABLE_HTTP3 || PROTOCORE_ENABLE_DTLS || PROTOCORE_ENABLE_TLS)
193#endif
194#ifndef PROTOCORE_ENABLE_HMAC_SHA384
195#define PROTOCORE_ENABLE_HMAC_SHA384 (PROTOCORE_ENABLE_HTTP3 || PROTOCORE_ENABLE_DTLS || PROTOCORE_ENABLE_TLS)
196#endif
197#ifndef PROTOCORE_ENABLE_HKDF_SHA384
198#define PROTOCORE_ENABLE_HKDF_SHA384 (PROTOCORE_ENABLE_HTTP3 || PROTOCORE_ENABLE_DTLS || PROTOCORE_ENABLE_TLS)
199#endif
200#ifndef PROTOCORE_ENABLE_SHA3
201#define PROTOCORE_ENABLE_SHA3 PROTOCORE_ENABLE_PQC_KEX
202#endif
203#ifndef PROTOCORE_ENABLE_MLKEM
204#define PROTOCORE_ENABLE_MLKEM PROTOCORE_ENABLE_PQC_KEX
205#endif
206#ifndef PROTOCORE_ENABLE_SNTRUP761
207#define PROTOCORE_ENABLE_SNTRUP761 PROTOCORE_ENABLE_SSH_SNTRUP761
208#endif
209
210// The file-transfer servers and file serving all reach storage through the filesystem accessor,
211// which is the HAL and points them at whatever is mounted. None of them needs the mount SERVICE:
212// they need the seam, and the seam fails closed when nothing is behind it. Requiring PROTOCORE_ENABLE_MNT
213// would drag the RAM backend's pool into every build that moves a file, to satisfy a type.
214
215#if PROTOCORE_ENABLE_SSH_KEYBOARD_INTERACTIVE && !PROTOCORE_SSH_ALLOW_PASSWORD
216#error \
217 "ProtoCore: PROTOCORE_ENABLE_SSH_KEYBOARD_INTERACTIVE is password-backed - it verifies the response through the password callback, so PROTOCORE_SSH_ALLOW_PASSWORD must stay 1 (or drop keyboard-interactive for publickey-only)"
218#endif
219
220// SFTP and SCP need the channel layer to carry them and the mount to store into (PROTOCORE_ENABLE_MNT is
221// required above). They do NOT need FILE_SERVING: that dependency was the fs::FS seam, and the seam
222// now lives with the vendor code in test/core_setup/, behind the mount backend.
223
224#endif // PROTOCORE_DEPENDENCY_EN_H