ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
inflate.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 inflate.h
6 * @brief RFC 1951 inflate, as SSH negotiates it.
7 */
8
9#ifndef PROTOCORE_TRANSPORT_INFLATE_H
10#define PROTOCORE_TRANSPORT_INFLATE_H
11
12#include "protocore_config.h" // the entry point: protocore_types.h for the widths
13
14#if PROTOCORE_ENABLE_SSH_ZLIB
15
17
18// This module holds nothing between calls, so it carves no borrow and states none. An entry
19// takes one all the same, and never reads it, so every namespace in the tree is invoked the
20// same way.
21
22/** @brief Sliding-window bytes the inflate needs (the full zlib 32 KB window OpenSSH may reference). */
23#define SSH_INFLATE_WINDOW 32768u
24
25/** @brief Bytes of un-decoded input the engine carries between packets (the flush-block tail). A
26 * well-behaved peer leaves only a handful; the bound also caps a peer that fails to flush cleanly. */
27#define SSH_INFLATE_CARRY 64u
28
29/**
30 * @brief Streaming client-to-server DEFLATE decompressor (one per SSH connection).
31 *
32 * The 32 KB circular @ref window is caller-supplied (it lives in PSRAM alongside the s2c compressor).
33 * ssh_inflate_init() binds it and resets the stream; the small carry/bit state is inline.
34 */
35typedef struct
36{
37 uint8_t *window; ///< 32 KB circular back-reference window (SSH_INFLATE_WINDOW bytes).
38 uint32_t wpos; ///< next write position in @ref window (0..SSH_INFLATE_WINDOW-1).
39 uint32_t whist; ///< bytes of valid history in @ref window (caps at SSH_INFLATE_WINDOW).
40 uint8_t carry[SSH_INFLATE_CARRY]; ///< un-decoded tail bytes from the previous packet (flush block).
41 uint8_t carry_len; ///< number of valid bytes in @ref carry.
42 uint8_t bit_off; ///< bits already consumed from carry[0] at the last block boundary (0..7).
43 proto_bool header_seen; ///< true once the leading 2-byte RFC 1950 zlib header was consumed.
44} SshInflate;
45
46/** @brief What init takes: z, window. */
47typedef struct
48{
49 SshInflate *z; ///< the decompressor to initialize
50 uint8_t *window; ///< back-reference window, >= SSH_INFLATE_WINDOW bytes
51} InflateInitArgs;
52
53/** @brief What packet takes: z, src, src_len, dst, dst_cap, out_len. */
54typedef struct
55{
56 SshInflate *z; ///< the decompressor
57 const uint8_t *src;
58 size_t src_len;
59 uint8_t *dst;
60 size_t dst_cap;
61 size_t *out_len; ///< set to the decompressed length on success (may be 0 if a packet carried only flush bits)
62} InflatePacketArgs;
63
64/**
65 * @brief RFC 1951 inflate, as SSH negotiates it.
66 *
67 * A caller sets the members a call takes, invokes it through ::Inflate with the bytes it runs
68 * out of, and reads the outcome off the same handle.
69 *
70 * Inflate.init_args.z = ...;
71 * Inflate.init_args.window = ...;
72 * Inflate.init(work);
73 *
74 * @var InflateNs::init_args what init takes: z, window
75 * @var InflateNs::packet_args what packet takes: z, src, src_len, dst, dst_cap, out_len
76 * @var InflateNs::ok a call's true/false outcome
77 * @var InflateNs::n 0 on success, -1 on a malformed stream, an output overflow, or a ...
78 * @var InflateNs::init bind a caller-owned 32 KB window to a decompressor and reset it to ...
79 * @var InflateNs::packet decompress one inbound packet payload, continuing the session's ...
80 *
81 * @c work is bytes the CALLER holds. This module reads none of them: it carries nothing
82 * between calls, so there is no state to keep and nothing to wipe. The parameter is there so
83 * a caller drives every namespace the same way.
84 */
85typedef struct
86{
87 InflateInitArgs init_args;
88 InflatePacketArgs packet_args;
89 proto_bool ok;
90 int n;
91} InflateVars;
92
93/** @brief The operands and the outcome. */
94extern InflateVars InflateV;
95
96/** @brief The entries. */
97typedef struct
98{
99 void (*const init)(uint8_t *work);
100 void (*const packet)(uint8_t *work);
101} InflateNs;
102
103// What the table binds, defined once in the .c and taking one parameter each: everything
104// else an entry needs is an operand in InflateV or a region of the borrow at a fixed offset.
105void protocore_inflate_init(uint8_t *work);
106void protocore_inflate_packet(uint8_t *work);
107
108// `static const`, initialised HERE rather than `extern` against a definition in the .c: a
109// const object whose initializer every translation unit can see is a COMPILE-TIME FACT, so
110// `Inflate.init(work)` resolves to a named function and becomes a DIRECT call. An extern table
111// leaves the call indirect and the symbol live at every level, -O2 -flto included.
112static const InflateNs Inflate __attribute__((unused)) = {
113 .init = protocore_inflate_init,
114 .packet = protocore_inflate_packet,
115};
116
118
119#endif // PROTOCORE_ENABLE_SSH_ZLIB
120
121#endif // PROTOCORE_TRANSPORT_INFLATE_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