ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
xmpp.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 xmpp.h
6 * @brief The XMPP stanza codec (RFC 6120 sec 8): four builders, an escape, and two start-tag reads.
7 *
8 * RFC 6120 sec 4.2 opens an XML stream by sending an initial stream header, and RFC 6120 sec 8
9 * carries three stanza kinds over that stream: `<message/>` (sec 8.2.1), `<presence/>` (sec 8.2.2)
10 * and `<iq/>` (sec 8.2.3). This module builds those four elements into a caller buffer and reads
11 * two things back out of a received one: the start-tag Name, and one attribute value.
12 *
13 * RFC 6120 sec 8.1 names the common attributes a stanza carries: 'to' (sec 8.1.1), 'from'
14 * (sec 8.1.2), 'id' (sec 8.1.3) and 'type' (sec 8.1.4). Each stanza kind takes its own 'type'
15 * values: message takes chat, error, groupchat, headline or normal (RFC 6121 sec 5.2.2); presence
16 * takes error, probe, subscribe, subscribed, unavailable, unsubscribe or unsubscribed, and its
17 * absence signals available (RFC 6121 sec 4.7.1); IQ takes get, set, result or error (RFC 6120
18 * sec 8.2.3).
19 *
20 * Character data and attribute values are written through the five predefined entities of XML 1.0
21 * (W3C REC-xml Fifth Edition sec 4.6: amp, lt, gt, apos, quot). XML is a W3C Recommendation, not an
22 * IETF RFC; RFC 6120 sec 11.1 is what makes those five the only entity references an XMPP stream
23 * may carry.
24 *
25 * The builders emit the members they are given and check nothing else. RFC 6120 sec 8.2.3 makes
26 * 'id' and 'type' REQUIRED on an IQ, and sec 8.4 requires one extension element on a get or a set;
27 * a caller that leaves those members NULL gets a stanza without them.
28 *
29 * A 'to' or 'from' value is a JID (RFC 7622 sec 3.1, which obsoletes RFC 6122). The text is copied
30 * through escaped, without the PRECIS preparation or the 1023-octet part limits of RFC 7622 sec 3.2
31 * through sec 3.4.
32 *
33 * STARTTLS (RFC 6120 sec 5), SASL (RFC 6120 sec 6) and resource binding (RFC 6120 sec 7) are
34 * negotiated elsewhere; this module frames text and holds no stream.
35 *
36 * The module exports one symbol, @ref Xmpp. Everything in xmpp.c has internal linkage.
37 *
38 * @author Douglas Quigg (dstroy0)
39 * @date 2026
40 */
41
42#ifndef PROTOCORE_XMPP_H
43#define PROTOCORE_XMPP_H
44
45#include "protocore_config.h" // the entry point: protocore_types.h for the widths
46
47#if PROTOCORE_ENABLE_XMPP
48
50
51/** @brief Where a call writes its octets. */
52typedef struct
53{
54 char *buf; ///< the buffer the call writes into
55 size_t cap; ///< how much room it has, the NUL included
56} XmppOutArgs;
57
58/** @brief The character data an escape reads (XML 1.0 sec 2.4). */
59typedef struct
60{
61 const char *in; ///< the octets to escape
62 size_t len; ///< how many of them
63} XmppTextArgs;
64
65/** @brief RFC 6120 sec 4.7: the addresses the initial stream header carries (sec 4.2). */
66typedef struct
67{
68 const char *from; ///< 'from' (sec 4.7.1), the initiating entity's JID; NULL leaves it out
69 const char *to; ///< 'to' (sec 4.7.2), the domainpart the initiator expects the receiver to service
70} XmppStreamArgs;
71
72/** @brief RFC 6120 sec 8.1: the common attributes a stanza carries. A NULL member leaves one out. */
73typedef struct
74{
75 const char *to; ///< 'to' (sec 8.1.1), the intended recipient's JID
76 const char *from; ///< 'from' (sec 8.1.2), the sending entity's JID
77 const char *type; ///< 'type' (sec 8.1.4), one of the values its stanza kind defines
78 const char *id; ///< 'id' (sec 8.1.3), REQUIRED on an IQ; only the IQ builder emits it
79} XmppCommonArgs;
80
81/** @brief What a stanza carries below its start-tag. A NULL member leaves that child out. */
82typedef struct
83{
84 const char *body; ///< the `<body/>` character data of a message (RFC 6121 sec 5.2.3), escaped on the way out
85 const char *extension; ///< the extension element of an IQ (RFC 6120 sec 8.4), copied through verbatim
86} XmppChildArgs;
87
88/** @brief The received stanza a read walks, and the attribute name it looks up. */
89typedef struct
90{
91 const char *xml; ///< the received octets
92 size_t len; ///< how many of them
93 const char *attr; ///< the attribute name to find in the start-tag (XML 1.0 sec 3.1)
94} XmppStanzaArgs;
95
96/**
97 * @brief The XMPP stanza codec.
98 *
99 * A caller sets the members a call takes, invokes it through ::Xmpp, and reads the outcome off the
100 * same handle.
101 *
102 * No slot member: every call works on the caller's octets and holds no stream, so no call names a
103 * row.
104 *
105 * @var XmppNs::out where the call writes its octets
106 * @var XmppNs::text the character data an escape reads
107 * @var XmppNs::stream the addresses the initial stream header carries (RFC 6120 sec 4.7)
108 * @var XmppNs::common the common attributes a stanza carries (RFC 6120 sec 8.1)
109 * @var XmppNs::child the `<body/>` or the extension element a stanza carries
110 * @var XmppNs::stanza the received stanza a read walks, and the attribute it names
111 * @var XmppNs::ok a call's true/false outcome
112 * @var XmppNs::n the octets written into @c out, excluding the NUL; 0 when the call failed
113 * @var XmppNs::escape write @c text through the five predefined entities (XML 1.0 sec 4.6)
114 * @var XmppNs::stream_open build the initial stream header from @c stream (RFC 6120 sec 4.2)
115 * @var XmppNs::message build a `<message/>` from @c common to, from and type, and @c child body
116 * (RFC 6120 sec 8.2.1, RFC 6121 sec 5.2)
117 * @var XmppNs::presence build a `<presence/>` from @c common type (RFC 6120 sec 8.2.2, RFC 6121
118 * sec 4.7)
119 * @var XmppNs::iq build an `<iq/>` from @c common type and id, and @c child extension
120 * (RFC 6120 sec 8.2.3, sec 8.4)
121 * @var XmppNs::stanza_name read the start-tag Name of @c stanza, the element's type (XML 1.0 sec 3.1)
122 * @var XmppNs::attr read the attribute value @c stanza names out of its start-tag, as the raw
123 * octets between the quotes with no entity expanded (XML 1.0 sec 3.1)
124 */
125typedef struct
126{
127 XmppOutArgs out; ///< where the octets land
128 XmppTextArgs text; ///< what an escape reads
129 XmppStreamArgs stream; ///< what the initial stream header addresses
130 XmppCommonArgs common; ///< what a stanza's start-tag says
131 XmppChildArgs child; ///< what a stanza carries below it
132 XmppStanzaArgs stanza; ///< what a read walks
133 proto_bool ok;
134 size_t n;
135} XmppVars;
136
137/** @brief The operands and the outcome. */
138extern XmppVars XmppV;
139
140/** @brief The entries. */
141typedef struct
142{
143 void (*const escape)(uint8_t *work);
144 void (*const stream_open)(uint8_t *work);
145 void (*const message)(uint8_t *work);
146 void (*const presence)(uint8_t *work);
147 void (*const iq)(uint8_t *work);
148 void (*const stanza_name)(uint8_t *work);
149 void (*const attr)(uint8_t *work);
150} XmppNs;
151
152// What the table binds, defined once in the .c and taking one parameter each: everything
153// else an entry needs is an operand in XmppV or a region of the borrow at a fixed offset.
154void protocore_xmpp_escape(uint8_t *work);
155void protocore_xmpp_stream_open(uint8_t *work);
156void protocore_xmpp_message(uint8_t *work);
157void protocore_xmpp_presence(uint8_t *work);
158void protocore_xmpp_iq(uint8_t *work);
159void protocore_xmpp_stanza_name(uint8_t *work);
160void protocore_xmpp_attr(uint8_t *work);
161
162// `static const`, initialised HERE rather than `extern` against a definition in the .c: a
163// const object whose initializer every translation unit can see is a COMPILE-TIME FACT, so
164// `Xmpp.escape(work)` resolves to a named function and becomes a DIRECT call. An extern table
165// leaves the call indirect and the symbol live at every level, -O2 -flto included.
166static const XmppNs Xmpp __attribute__((unused)) = {
167 .escape = protocore_xmpp_escape,
168 .stream_open = protocore_xmpp_stream_open,
169 .message = protocore_xmpp_message,
170 .presence = protocore_xmpp_presence,
171 .iq = protocore_xmpp_iq,
172 .stanza_name = protocore_xmpp_stanza_name,
173 .attr = protocore_xmpp_attr,
174};
175
177
178#endif // PROTOCORE_ENABLE_XMPP
179
180#endif // PROTOCORE_XMPP_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