DeterministicESPAsyncWebServer v6.28.0
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
sockpool.h
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 sockpool.h
6 * @brief Dynamic socket recycling: an LRU connection-slot pool (DETWS_ENABLE_SOCKPOOL).
7 *
8 * A device serves a bounded number of concurrent connections. When the pool saturates, the right move is
9 * not to drop the new connection but to *recycle* the least-recently-active slot (the one most likely to
10 * be a dead / idle keep-alive) and hand it to the new peer, returning the evicted id so the transport can
11 * close it cleanly. This is the transport-pool half left open by `services/netadapt`.
12 *
13 * This is that pure policy: a fixed table of connection slots (each an id + last-used tick), with acquire
14 * (free slot, else LRU-recycle), touch (mark active), release, and find. The app owns the real sockets;
15 * this owns *which* slot a connection lives in and which to reclaim under pressure. No heap, no stdlib,
16 * host-testable.
17 */
18
19#ifndef DETERMINISTICESPASYNCWEBSERVER_SOCKPOOL_H
20#define DETERMINISTICESPASYNCWEBSERVER_SOCKPOOL_H
21
22#include "ServerConfig.h"
23#include <stddef.h>
24#include <stdint.h>
25
26#if DETWS_ENABLE_SOCKPOOL
27
28/** @brief One connection slot. */
29struct SockSlot
30{
31 bool in_use;
32 uint32_t id; ///< application connection id (e.g. a socket fd / handle).
33 uint32_t last_used; ///< tick of the last acquire/touch (for LRU).
34};
35
36/** @brief A fixed pool of connection slots (storage is caller-owned). */
37struct SockPool
38{
39 SockSlot *slots;
40 size_t n;
41};
42
43/** @brief Acquire outcome (the sole return of detws_sockpool_acquire). */
44enum class SockAcq : uint8_t
45{
46 SOCK_ACQ_FREE = 0, ///< a free slot was used.
47 SOCK_ACQ_RECYCLED = 1, ///< the pool was full; the LRU slot was recycled (see evicted_id).
48 SOCK_ACQ_FAIL = 2 ///< the pool has zero slots / bad args.
49};
50
51/** @brief Initialize a pool over caller storage; all slots start free. */
52void detws_sockpool_init(SockPool *p, SockSlot *slots, size_t n);
53
54/**
55 * @brief Acquire a slot for connection @p id at tick @p now.
56 *
57 * Uses a free slot if one exists, otherwise recycles the least-recently-used in-use slot. On a recycle,
58 * @p evicted_id (may be null) receives the id that was kicked out so the caller can close that socket.
59 * @param idx (may be null) receives the chosen slot index.
60 * @return SOCK_ACQ_FREE / SOCK_ACQ_RECYCLED / SOCK_ACQ_FAIL.
61 */
62SockAcq detws_sockpool_acquire(SockPool *p, uint32_t id, uint32_t now, size_t *idx, uint32_t *evicted_id);
63
64/** @brief Mark slot @p idx active at tick @p now (refreshes its LRU position). */
65void detws_sockpool_touch(SockPool *p, size_t idx, uint32_t now);
66
67/** @brief Free slot @p idx. @return true if it was a valid, in-use slot. */
68bool detws_sockpool_release(SockPool *p, size_t idx);
69
70/** @brief Find the slot holding connection @p id. @p idx (may be null) gets the index. @return found. */
71bool detws_sockpool_find(const SockPool *p, uint32_t id, size_t *idx);
72
73/** @brief Count of in-use slots. */
74size_t detws_sockpool_in_use(const SockPool *p);
75
76#endif // DETWS_ENABLE_SOCKPOOL
77#endif // DETERMINISTICESPASYNCWEBSERVER_SOCKPOOL_H
User-facing configuration for DeterministicESPAsyncWebServer.