DeterministicESPAsyncWebServer 1.2.0
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
sse.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file sse.cpp
6 * @brief Server-Sent Events connection pool implementation.
7 */
8
9#include "sse.h"
10#include "lwip/tcp.h"
11#include <stdio.h>
12#include <string.h>
13
15
17{
18 for (int i = 0; i < MAX_SSE_CONNS; i++)
19 {
20 sse_pool[i] = {};
21 sse_pool[i].sse_id = (uint8_t)i;
22 }
23}
24
25SseConn *sse_alloc(uint8_t slot_id, const char *path)
26{
27 for (int i = 0; i < MAX_SSE_CONNS; i++)
28 {
29 if (!sse_pool[i].active)
30 {
31 sse_pool[i] = {};
32 sse_pool[i].sse_id = (uint8_t)i;
33 sse_pool[i].slot_id = slot_id;
34 sse_pool[i].active = true;
35 strncpy(sse_pool[i].path, path, MAX_PATH_LEN - 1);
36 sse_pool[i].path[MAX_PATH_LEN - 1] = '\0';
37 return &sse_pool[i];
38 }
39 }
40 return nullptr;
41}
42
43SseConn *sse_find(uint8_t slot_id)
44{
45 for (int i = 0; i < MAX_SSE_CONNS; i++)
46 {
47 if (sse_pool[i].active && sse_pool[i].slot_id == slot_id)
48 return &sse_pool[i];
49 }
50 return nullptr;
51}
52
53void sse_free(uint8_t slot_id)
54{
55 for (int i = 0; i < MAX_SSE_CONNS; i++)
56 {
57 if (sse_pool[i].active && sse_pool[i].slot_id == slot_id)
58 {
59 sse_pool[i] = {};
60 sse_pool[i].sse_id = (uint8_t)i;
61 return;
62 }
63 }
64}
65
66bool sse_write(SseConn *sse, const char *data,
67 const char *event, const char *id)
68{
69 if (!data)
70 return false;
71
72 TcpConn *conn = &conn_pool[sse->slot_id];
73 if (conn->state != CONN_ACTIVE || !conn->pcb)
74 return false;
75
76 char buf[SSE_BUF_SIZE];
77 int pos = 0;
78 int rem = (int)sizeof(buf);
79
80 if (event && pos < rem)
81 pos += snprintf(buf + pos, (size_t)(rem - pos), "event: %s\n", event);
82 if (id && pos < rem)
83 pos += snprintf(buf + pos, (size_t)(rem - pos), "id: %s\n", id);
84 if (pos < rem)
85 pos += snprintf(buf + pos, (size_t)(rem - pos), "data: %s\n\n", data);
86
87 if (pos <= 0 || pos >= rem)
88 return false;
89
90 tcp_write(conn->pcb, buf, (u16_t)pos, TCP_WRITE_FLAG_COPY);
91 return true;
92}
#define MAX_PATH_LEN
Maximum URL path length (including leading /).
#define MAX_SSE_CONNS
Maximum simultaneous SSE connections.
#define SSE_BUF_SIZE
Output buffer size in bytes for a single SSE event.
void sse_init()
Initialise all SSE pool slots to inactive.
Definition sse.cpp:16
bool sse_write(SseConn *sse, const char *data, const char *event, const char *id)
Write one SSE event record to a client.
Definition sse.cpp:66
SseConn sse_pool[MAX_SSE_CONNS]
Pool of SSE connection state, one per MAX_SSE_CONNS.
Definition sse.cpp:14
SseConn * sse_find(uint8_t slot_id)
Find the SseConn for a given TCP slot, or nullptr.
Definition sse.cpp:43
SseConn * sse_alloc(uint8_t slot_id, const char *path)
Allocate an SseConn and bind it to a TCP slot.
Definition sse.cpp:25
void sse_free(uint8_t slot_id)
Free the SseConn associated with a TCP slot.
Definition sse.cpp:53
Layer 6 (Presentation) – Server-Sent Events connection pool.
SSE connection state stored in sse_pool[].
Definition sse.h:46
char path[MAX_PATH_LEN]
Definition sse.h:52
uint8_t sse_id
Index into sse_pool[] (set at init).
Definition sse.h:47
bool active
True when this entry is in use.
Definition sse.h:49
uint8_t slot_id
Owning TCP slot in conn_pool[].
Definition sse.h:48
A single TCP connection context.
Definition transport.h:69
volatile ConnState state
Lifecycle state; volatile for inter-task visibility.
Definition transport.h:71
struct tcp_pcb * pcb
lwIP PCB; null when slot is free.
Definition transport.h:72
TcpConn conn_pool[MAX_CONNS]
Static pool of connection contexts. Defined in transport.cpp.
Definition transport.cpp:25
@ CONN_ACTIVE
Live connection; PCB is valid.
Definition transport.h:57