ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
evt.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 evt.h
6 * @brief What the stack callbacks post to a listener's queue: the event type and the record.
7 *
8 * Separate from common.h because this is all the layers above the transport need. A listener sizes
9 * its queue storage on ::TcpEvt, the session layer switches on ::EvtType, and the presentation
10 * layer names EVT_CONNECT; none of them touches a connection slot's fields. common.h carries those,
11 * and the ring cursors in them are `_Atomic`, which is C11 and not C++ - so a header that reaches
12 * the sketches through protocore.h cannot be the one that declares them.
13 *
14 * @author Douglas Quigg (dstroy0)
15 * @date 2026
16 */
17
18#ifndef PROTOCORE_TCP_EVT_H
19#define PROTOCORE_TCP_EVT_H
20
21#include "protocore_config.h" // the entry point: the widths, PROTO_ENUM_PACKED, static_assert
22
23/**
24 * @brief Lifecycle state of a connection pool slot.
25 *
26 * NOT the RFC 9293 sec 3.3.2 connection state machine. That machine (LISTEN, SYN-RECEIVED,
27 * ESTABLISHED, FIN-WAIT-1/2, CLOSE-WAIT, CLOSING, LAST-ACK, TIME-WAIT) belongs to the stack under
28 * this layer; these three name only whether the pool slot is available. A test mapping CONN_* to
29 * RFC state names 1:1 is testing the wrong thing.
30 *
31 * Transitions, as the code performs them:
32 * - `CONN_FREE -> CONN_ACTIVE` accept callback fires.
33 * - `CONN_ACTIVE -> CONN_CLOSING` the dwell that precedes a close begins.
34 * - `CONN_CLOSING -> CONN_FREE` the peer ACKed the outbound data (snd_queuelen == 0), the dwell
35 * timed out, or data arrived that could no longer be delivered.
36 * - `CONN_ACTIVE -> CONN_FREE` local close, remote FIN, stack error, or the idle sweep.
37 *
38 * Every terminal edge detaches the control block and frees the slot before handing it to the stack,
39 * so the slot's lifetime ends before the connection's does; the FIN and its retransmission are the
40 * stack's from that point (RFC 9293 sec 3.6).
41 *
42 * Here rather than in common.h because the signaling layer reads a slot's state and reaches this
43 * layer through protocore.h; the enum is one packed byte and carries no `_Atomic`.
44 */
46{
47 CONN_FREE, ///< Slot is available; no control block is attached.
48 CONN_ACTIVE, ///< Live connection; the control block is valid.
49 CONN_CLOSING ///< Transmit-drain dwell: holding the slot until the peer ACKs what was sent. No
50 ///< FIN has been emitted yet - it goes out as the slot is released.
52static_assert(sizeof(ConnState) == 1,
53 "ConnState must stay one byte (PROTO_ENUM_PACKED); TcpConn and conn_pool[] size themselves on it");
54
55/**
56 * @brief Type of connection event posted to a listener's event queue.
57 *
58 * EVT_DISCONNECT and EVT_ERROR are the two a close is reported through, and they are distinct
59 * because RFC 9293 sec 3.6 MUST-12 requires the layer above to be told whether a connection closed
60 * normally or was aborted.
61 */
63{
64 EVT_CONNECT, ///< New connection accepted.
65 EVT_DATA, ///< Data received; bytes are already in the ring buffer.
66 EVT_DISCONNECT, ///< Remote peer closed the connection gracefully.
67 EVT_ERROR ///< The stack reported an error (the control block may already be freed).
69static_assert(sizeof(EvtType) == 1,
70 "EvtType must stay one byte (PROTO_ENUM_PACKED); every listener's queue storage sizes itself on TcpEvt");
71
72/**
73 * @brief Event record posted from the stack callbacks to the session layer.
74 *
75 * Copied into the queue by value, so nothing in it points at a slot whose lifetime ends before the
76 * record is drained.
77 */
78typedef struct TcpEvt
79{
80 EvtType type; ///< What happened.
81 uint8_t slot_id; ///< Which connection slot is affected.
82 size_t data_len; ///< Bytes copied (EVT_DATA only); 0 for other types.
84
85// ---------------------------------------------------------------------------
86// Observability (PROTOCORE_ENABLE_OBSERVABILITY) - connection event hook + counters
87// ---------------------------------------------------------------------------
88#if PROTOCORE_ENABLE_OBSERVABILITY
89
90/** @brief Why a connection event fired (the reason for a transition or notice). */
91typedef enum PROTO_ENUM_PACKED
92{
93 PROTOCORE_CONN_R_ACCEPT, ///< New connection accepted (CONN_FREE -> CONN_ACTIVE).
94 PROTOCORE_CONN_R_CLOSE_REMOTE, ///< Peer closed gracefully (FIN received).
95 PROTOCORE_CONN_R_CLOSE_LOCAL, ///< Application initiated the close.
96 PROTOCORE_CONN_R_ERROR, ///< The stack reported a fatal error on the connection.
97 PROTOCORE_CONN_R_TIMEOUT, ///< Idle-timeout sweep reaped the slot.
98 PROTOCORE_CONN_R_ABORT, ///< Forced abort (server stop / pool reset / data after close).
99 PROTOCORE_CONN_R_DRAINED, ///< CONN_CLOSING slot finished draining -> closed.
100 PROTOCORE_CONN_R_BACKPRESSURE, ///< RX segment refused (ring full); no state change.
101 PROTOCORE_CONN_R_DEFER_DROP ///< Event queue full; an event was dropped (no state change).
102} protocore_conn_reason;
103static_assert(sizeof(protocore_conn_reason) == 1, "protocore_conn_reason must stay one byte (PROTO_ENUM_PACKED)");
104
105/** @brief Snapshot of the transport's lifetime counters (plus a live gauge). */
106typedef struct protocore_conn_counters
107{
108 uint32_t accepts; ///< Connections accepted.
109 uint32_t closes_remote; ///< Closed by peer FIN.
110 uint32_t closes_local; ///< Closed by the application.
111 uint32_t closes_error; ///< Closed by a stack error.
112 uint32_t closes_timeout; ///< Reaped by the idle-timeout sweep.
113 uint32_t closes_abort; ///< Force-aborted (stop / reset / data after close).
114 uint32_t backpressure; ///< RX segments refused for lack of ring space.
115 uint32_t defer_drops; ///< Deferred events dropped because the queue was full.
116 uint32_t closing_gauge; ///< Slots currently in CONN_CLOSING (live, not cumulative).
117} protocore_conn_counters;
118
119/**
120 * @brief Callback fired on every connection state transition.
121 *
122 * Runs in whichever task drove the transition (the stack's callback context for
123 * accept / recv / error, a worker for close / timeout), so keep it short and non-blocking and do
124 * not call back into the server from it. @p old_state == @p new_state for the
125 * non-transition notices (backpressure, defer-drop).
126 */
127typedef void (*protocore_conn_event_cb)(uint8_t slot, ConnState old_state, ConnState new_state,
128 protocore_conn_reason reason);
129
130// Internal notify points (protocol/protocol.c), reached via the macros below so the protocol
131// engine and the server's accept path both record through one path.
132void protocore_obs_transition(uint8_t slot, ConnState olds, ConnState news, protocore_conn_reason reason);
133void protocore_obs_notice(uint8_t slot, ConnState st, protocore_conn_reason reason);
134#define PROTOCORE_OBS_TRANSITION(slot, olds, news, reason) protocore_obs_transition((slot), (olds), (news), (reason))
135#define PROTOCORE_OBS_NOTICE(slot, st, reason) protocore_obs_notice((slot), (st), (reason))
136
137#else // !PROTOCORE_ENABLE_OBSERVABILITY
138
139// Compile to nothing; the arguments (incl. protocore_conn_reason names, only declared
140// when the feature is on) are dropped unparsed by the preprocessor.
141#define PROTOCORE_OBS_TRANSITION(slot, olds, news, reason) ((void)0)
142#define PROTOCORE_OBS_NOTICE(slot, st, reason) ((void)0)
143
144#endif // PROTOCORE_ENABLE_OBSERVABILITY
145
146#endif // PROTOCORE_TCP_EVT_H
PROTO_ENUM_PACKED
Application protocol spoken on a listener port or connection slot.
enum PROTO_ENUM_PACKED EvtType
Type of connection event posted to a listener's event queue.
enum PROTO_ENUM_PACKED ConnState
Lifecycle state of a connection pool slot.
@ CONN_CLOSING
Definition evt.h:49
@ EVT_CONNECT
New connection accepted.
Definition evt.h:64
@ CONN_FREE
Slot is available; no control block is attached.
Definition evt.h:47
@ EVT_DISCONNECT
Remote peer closed the connection gracefully.
Definition evt.h:66
@ CONN_ACTIVE
Live connection; the control block is valid.
Definition evt.h:48
@ EVT_ERROR
The stack reported an error (the control block may already be freed).
Definition evt.h:67
@ EVT_DATA
Data received; bytes are already in the ring buffer.
Definition evt.h:65
Event record posted from the stack callbacks to the session layer.
Definition evt.h:79
EvtType type
What happened.
Definition evt.h:80
size_t data_len
Bytes copied (EVT_DATA only); 0 for other types.
Definition evt.h:82
uint8_t slot_id
Which connection slot is affected.
Definition evt.h:81