ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
wamp.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 wamp.h
6 * @brief WAMP (Web Application Messaging Protocol) codec (PROTOCORE_ENABLE_WAMP) - zero-heap
7 * message builders plus a positional element reader, riding the shipped WebSocket layer.
8 *
9 * WAMP is specified by the WAMP project at wamp-proto.org, not by the IETF. The document is
10 * distributed in Internet-Draft format as "WAMP Basic Profile" and carries no RFC number; every
11 * section cited in this module is that document's.
12 *
13 * WAMP sec 3.3: a message is a list whose first element is the message type code, and the
14 * application payload is always the tail of that list. SUBSCRIBE is
15 * `[SUBSCRIBE, Request|id, Options|dict, Topic|uri]` (sec 3.4.2.3). The builders drive the shared
16 * @ref Json writer to emit these lists into the caller's buffer: Options|dict and Details|dict
17 * default to `{}`, and Arguments|list / ArgumentsKw|dict are pre-formatted JSON literals or are
18 * left off (sec 3.7). The reader is a positional scanner over one received list - the message
19 * type code, an id at a position, or a URI - which is what WELCOME, SUBSCRIBED, EVENT, RESULT,
20 * INVOCATION and ERROR handling reads.
21 *
22 * WAMP sec 2.3.1 names the WebSocket subprotocol this JSON serialization rides, `wamp.2.json`,
23 * where every frame is a text frame. The connection and the session / subscription / registration
24 * tables are the application's; this is the message codec.
25 *
26 * The module exports one symbol, @ref Wamp. Everything in wamp.c has internal linkage.
27 *
28 * @author Douglas Quigg (dstroy0)
29 * @date 2026
30 */
31
32#ifndef PROTOCORE_WAMP_H
33#define PROTOCORE_WAMP_H
34
35#include "protocore_config.h" // the entry point: protocore_types.h for the widths
36
37#if PROTOCORE_ENABLE_WAMP
38
40
41// Message type codes, WAMP sec 3.5 (the Basic Profile table).
42#define WAMP_HELLO 1
43#define WAMP_WELCOME 2
44#define WAMP_ABORT 3
45#define WAMP_GOODBYE 6
46#define WAMP_ERROR 8
47#define WAMP_PUBLISH 16
48#define WAMP_PUBLISHED 17
49#define WAMP_SUBSCRIBE 32
50#define WAMP_SUBSCRIBED 33
51#define WAMP_UNSUBSCRIBE 34
52#define WAMP_UNSUBSCRIBED 35
53#define WAMP_EVENT 36
54#define WAMP_CALL 48
55#define WAMP_RESULT 50
56#define WAMP_REGISTER 64
57#define WAMP_REGISTERED 65
58#define WAMP_UNREGISTER 66
59#define WAMP_UNREGISTERED 67
60#define WAMP_INVOCATION 68
61#define WAMP_YIELD 70
62
63/** @brief Where a built message list lands. */
64typedef struct
65{
66 char *buf; ///< the buffer a build writes the message list into
67 size_t cap; ///< how much room it has, the NUL included
68} WampOutArgs;
69
70/** @brief The ids a message names: integers in 1..2^53 (WAMP sec 2.1.2). */
71typedef struct
72{
73 uint64_t request; ///< Request|id, the outgoing request every non-session message carries
74 uint64_t subscription; ///< SUBSCRIBED.Subscription|id, what an UNSUBSCRIBE drops (sec 3.4.2.5)
75 uint64_t registration; ///< REGISTERED.Registration|id, what an UNREGISTER drops (sec 3.4.3.5)
76} WampIdArgs;
77
78/** @brief The URI element a message names (WAMP sec 2.1.1). */
79typedef struct
80{
81 const char *realm; ///< Realm|uri, the realm a HELLO joins (sec 3.4.1.1)
82 const char *reason; ///< Reason|uri, why a GOODBYE closes the session (sec 3.4.1.4)
83 const char *topic; ///< Topic|uri, what a SUBSCRIBE or a PUBLISH names (sec 3.4.2.1, 3.4.2.3)
84 const char *procedure; ///< Procedure|uri, what a CALL or a REGISTER names (sec 3.4.3.1, 3.4.3.3)
85} WampUriArgs;
86
87/** @brief The dict and list elements a message carries, each a pre-formatted JSON literal. */
88typedef struct
89{
90 const char *details; ///< Details|dict of a HELLO or a GOODBYE; NULL emits `{}`
91 const char *options; ///< Options|dict of a SUBSCRIBE, PUBLISH, CALL, REGISTER or YIELD; NULL emits `{}`
92 const char *arguments; ///< Arguments|list, the payload's positional half; NULL leaves the element off
93 const char *arguments_kw; ///< ArgumentsKw|dict, its keyword half; NULL leaves the element off
94} WampPayloadArgs;
95
96/** @brief One received message list and the element position a read names (WAMP sec 3.3). */
97typedef struct
98{
99 const char *msg; ///< the received message, a NUL-terminated JSON list
100 size_t index; ///< the element a read names, 0 being the message type code
101 char *uri_out; ///< where a URI read copies the element, quotes stripped
102 size_t uri_cap; ///< how much room that has, the NUL included
103} WampParseArgs;
104
105/**
106 * @brief The WAMP message codec: the builders and the positional element reader.
107 *
108 * A caller sets the members a call takes, invokes it through ::Wamp, and reads the outcome off the
109 * same handle.
110 *
111 * No slot member: the codec owns no rows, so a build names its buffer and a read names its message.
112 *
113 * @var WampNs::out the buffer a build writes into
114 * @var WampNs::id the ids a message names (sec 2.1.2)
115 * @var WampNs::uri the URI element a message names (sec 2.1.1)
116 * @var WampNs::payload the Details / Options dicts and the Arguments / ArgumentsKw payload
117 * @var WampNs::parse the received message, the element a read names, and where a URI lands
118 * @var WampNs::ok a call's true/false outcome
119 * @var WampNs::n the byte count a build wrote, or the length of the element @c text names
120 * @var WampNs::u64 the id a read reports (sec 2.1.2)
121 * @var WampNs::i32 the message type code a read reports (sec 3.5)
122 * @var WampNs::text the raw element a slice names, pointing into @c parse.msg
123 * @var WampNs::build_hello `[HELLO, Realm|uri, Details|dict]` (sec 3.4.1.1)
124 * @var WampNs::build_goodbye `[GOODBYE, Details|dict, Reason|uri]` (sec 3.4.1.4)
125 * @var WampNs::build_subscribe `[SUBSCRIBE, Request|id, Options|dict, Topic|uri]` (sec 3.4.2.3)
126 * @var WampNs::build_unsubscribe `[UNSUBSCRIBE, Request|id, SUBSCRIBED.Subscription|id]` (sec 3.4.2.5)
127 * @var WampNs::build_publish `[PUBLISH, Request|id, Options|dict, Topic|uri]`, the payload
128 * appended when set (sec 3.4.2.1)
129 * @var WampNs::build_call `[CALL, Request|id, Options|dict, Procedure|uri]`, the payload
130 * appended when set (sec 3.4.3.1)
131 * @var WampNs::build_register `[REGISTER, Request|id, Options|dict, Procedure|uri]` (sec 3.4.3.3)
132 * @var WampNs::build_unregister `[UNREGISTER, Request|id, REGISTERED.Registration|id]` (sec 3.4.3.5)
133 * @var WampNs::build_yield `[YIELD, INVOCATION.Request|id, Options|dict]`, the payload
134 * appended when set (sec 3.4.3.8)
135 * @var WampNs::element slice the raw element at @c parse.index into @c text and @c n
136 * @var WampNs::get_type read the message type code into @c i32, naming element 0 itself (sec 3.5)
137 * @var WampNs::get_id read the id at @c parse.index into @c u64 (sec 2.1.2)
138 * @var WampNs::get_uri copy the URI at @c parse.index into @c parse.uri_out, quotes stripped
139 */
140typedef struct
141{
142 WampOutArgs out; ///< where a built message lands
143 WampIdArgs id; ///< the ids a message names
144 WampUriArgs uri; ///< the URI a message names
145 WampPayloadArgs payload; ///< the dicts and the payload lists a message carries
146 WampParseArgs parse; ///< the received message and the element a read names
147 proto_bool ok;
148 size_t n;
149 uint64_t u64;
150 int32_t i32;
151 const char *text;
152} WampVars;
153
154/** @brief The operands and the outcome. */
155extern WampVars WampV;
156
157/** @brief The entries. */
158typedef struct
159{
160 void (*const build_hello)(uint8_t *work);
161 void (*const build_goodbye)(uint8_t *work);
162 void (*const build_subscribe)(uint8_t *work);
163 void (*const build_unsubscribe)(uint8_t *work);
164 void (*const build_publish)(uint8_t *work);
165 void (*const build_call)(uint8_t *work);
166 void (*const build_register)(uint8_t *work);
167 void (*const build_unregister)(uint8_t *work);
168 void (*const build_yield)(uint8_t *work);
169 void (*const element)(uint8_t *work);
170 void (*const get_type)(uint8_t *work);
171 void (*const get_id)(uint8_t *work);
172 void (*const get_uri)(uint8_t *work);
173} WampNs;
174
175// What the table binds, defined once in the .c and taking one parameter each: everything
176// else an entry needs is an operand in WampV or a region of the borrow at a fixed offset.
177void protocore_wamp_build_hello(uint8_t *work);
178void protocore_wamp_build_goodbye(uint8_t *work);
179void protocore_wamp_build_subscribe(uint8_t *work);
180void protocore_wamp_build_unsubscribe(uint8_t *work);
181void protocore_wamp_build_publish(uint8_t *work);
182void protocore_wamp_build_call(uint8_t *work);
183void protocore_wamp_build_register(uint8_t *work);
184void protocore_wamp_build_unregister(uint8_t *work);
185void protocore_wamp_build_yield(uint8_t *work);
186void protocore_wamp_element(uint8_t *work);
187void protocore_wamp_get_type(uint8_t *work);
188void protocore_wamp_get_id(uint8_t *work);
189void protocore_wamp_get_uri(uint8_t *work);
190
191// `static const`, initialised HERE rather than `extern` against a definition in the .c: a
192// const object whose initializer every translation unit can see is a COMPILE-TIME FACT, so
193// `Wamp.build_hello(work)` resolves to a named function and becomes a DIRECT call. An extern table
194// leaves the call indirect and the symbol live at every level, -O2 -flto included.
195static const WampNs Wamp __attribute__((unused)) = {
196 .build_hello = protocore_wamp_build_hello,
197 .build_goodbye = protocore_wamp_build_goodbye,
198 .build_subscribe = protocore_wamp_build_subscribe,
199 .build_unsubscribe = protocore_wamp_build_unsubscribe,
200 .build_publish = protocore_wamp_build_publish,
201 .build_call = protocore_wamp_build_call,
202 .build_register = protocore_wamp_build_register,
203 .build_unregister = protocore_wamp_build_unregister,
204 .build_yield = protocore_wamp_build_yield,
205 .element = protocore_wamp_element,
206 .get_type = protocore_wamp_get_type,
207 .get_id = protocore_wamp_get_id,
208 .get_uri = protocore_wamp_get_uri,
209};
210
212
213#endif // PROTOCORE_ENABLE_WAMP
214
215#endif // PROTOCORE_WAMP_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