DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
udp.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 udp.h
6 * @brief Layer 4 (Transport) - connectionless UDP datagram service.
7 *
8 * The transport layer's UDP counterpart to the TCP connection pool (see
9 * tcp.h / listener.h). It owns *all* lwIP UDP plumbing (`udp_pcb`,
10 * `pbuf`); higher layers (application services such as SNMP and the captive
11 * portal's DNS responder) bind a port and exchange datagrams through this API
12 * without ever touching lwIP. This keeps the OSI layering honest: transport
13 * concerns stay in the transport layer.
14 *
15 * Datagram delivery is callback-driven from the lwIP thread (no per-loop
16 * polling). The handler receives a contiguous payload and an opaque peer token
17 * valid only for the duration of the call; reply synchronously with
18 * det_udp_send(). On non-Arduino (host) builds the functions are no-op stubs so
19 * the services that use them stay host-compilable.
20 *
21 * @author Douglas Quigg (dstroy0)
22 * @date 2026
23 */
24
25#ifndef DETERMINISTICESPASYNCWEBSERVER_UDP_TRANSPORT_H
26#define DETERMINISTICESPASYNCWEBSERVER_UDP_TRANSPORT_H
27
28#include "ServerConfig.h"
29#include <stddef.h>
30#include <stdint.h>
31
32/**
33 * @brief Opaque sender of a received datagram.
34 *
35 * Wraps the lwIP source address / port / PCB. Valid only inside the
36 * DetUdpHandler call; pass it to det_udp_send() to reply. The concrete layout
37 * lives in udp.cpp so no lwIP type escapes the transport layer.
38 */
39struct DetUdpPeer;
40
41/**
42 * @brief Datagram handler invoked for each received UDP packet.
43 *
44 * @param data contiguous datagram payload (transport-owned scratch).
45 * @param len payload length in bytes.
46 * @param peer reply token (valid only during this call).
47 * @param ctx the opaque context passed to det_udp_listen().
48 */
49typedef void (*DetUdpHandler)(const uint8_t *data, size_t len, struct DetUdpPeer *peer, void *ctx);
50
51/**
52 * @brief Bind a UDP port and route incoming datagrams to @p handler.
53 *
54 * @param port UDP port to bind (e.g. 161 for SNMP, 53 for captive DNS).
55 * @param handler callback for each datagram.
56 * @param ctx opaque pointer forwarded to @p handler.
57 * @return true on success; false if no listener slot is free, the bind fails,
58 * or UDP is unavailable (host builds). ESP32 only; a host build returns false.
59 */
60bool det_udp_listen(uint16_t port, DetUdpHandler handler, void *ctx);
61
62/**
63 * @brief Send a datagram back to the peer captured during the handler call.
64 *
65 * @param peer the token handed to the DetUdpHandler.
66 * @param data payload bytes.
67 * @param len payload length.
68 * @return true if the datagram was queued for transmission.
69 */
70bool det_udp_send(struct DetUdpPeer *peer, const uint8_t *data, size_t len);
71
72/**
73 * @brief Send a UDP datagram to an arbitrary destination (outbound client).
74 *
75 * Unlike det_udp_send() - which replies to the peer of a received datagram -
76 * this sends to a host given as a dotted-quad IPv4 string and port, using a
77 * single shared outbound PCB. Fire-and-forget; for clients such as the syslog
78 * sender. ESP32 only; a host build returns false.
79 *
80 * @param dst_ip destination IPv4 address (e.g. "192.168.1.10").
81 * @param dst_port destination UDP port.
82 * @param data payload bytes.
83 * @param len payload length.
84 * @return true if the datagram was queued; false on a bad address, allocation
85 * failure, or a host build.
86 */
87bool det_udp_sendto(const char *dst_ip, uint16_t dst_port, const uint8_t *data, size_t len);
88
89/**
90 * @brief Copy a received peer's source IPv4 address (dotted-quad) and port out.
91 *
92 * The DetUdpPeer token is valid only inside the handler; a service that wants to
93 * message the peer later (e.g. CoAP Observe notifications) captures its address
94 * here and sends with det_udp_listener_sendto(). @return false on a host build or
95 * a too-small buffer.
96 */
97bool det_udp_peer_addr(const struct DetUdpPeer *peer, char *ip_out, size_t ip_cap, uint16_t *port_out);
98
99/**
100 * @brief Send a datagram from the listener bound on @p listen_port to an address.
101 *
102 * Unlike det_udp_sendto() (a shared ephemeral source port), this uses the bound
103 * listener's PCB, so the datagram's source is @p listen_port - required when a
104 * peer matches replies by the server endpoint (CoAP Observe notifications come
105 * from :5683). @return false if no listener is bound on @p listen_port.
106 */
107bool det_udp_listener_sendto(uint16_t listen_port, const char *dst_ip, uint16_t dst_port, const uint8_t *data,
108 size_t len);
109
110#if !defined(ARDUINO)
111// Host-only test hooks: capture the last datagram passed to det_udp_sendto() so a
112// unit test can inspect what an outbound UDP service (SNMP trap/inform, syslog,
113// telemetry) actually built. Off by default; enable per test. Mirrors the
114// tcp_capture() seam in the lwIP mock.
115void det_udp_capture_enable();
116void det_udp_capture_reset();
117const uint8_t *det_udp_captured(); ///< bytes of the last captured datagram (nullptr if none)
118size_t det_udp_captured_len(); ///< length of the last captured datagram
119
120// Deliver a datagram from (src_ip, src_port) to the handler bound to listen_port, driving the
121// receive path of a UDP service (CoAP Observe, DNS, SNMP) as if a peer had sent it.
122void det_udp_inject(uint16_t listen_port, const char *src_ip, uint16_t src_port, const uint8_t *data, size_t len);
123void det_udp_set_listener_sendto_result(bool ok); ///< force det_udp_listener_sendto() to fail (unreachable peer)
124void det_udp_reset_listeners(); ///< clear all bound listeners (per-test isolation)
125#endif
126
127#endif // DETERMINISTICESPASYNCWEBSERVER_UDP_TRANSPORT_H
User-facing configuration for DeterministicESPAsyncWebServer.
u16_t port
Definition udp.cpp:50
bool det_udp_peer_addr(const struct DetUdpPeer *peer, char *ip_out, size_t ip_cap, uint16_t *port_out)
Copy a received peer's source IPv4 address (dotted-quad) and port out.
Definition udp.cpp:224
void(* DetUdpHandler)(const uint8_t *data, size_t len, struct DetUdpPeer *peer, void *ctx)
Datagram handler invoked for each received UDP packet.
Definition udp.h:49
bool det_udp_sendto(const char *dst_ip, uint16_t dst_port, const uint8_t *data, size_t len)
Send a UDP datagram to an arbitrary destination (outbound client).
Definition udp.cpp:196
bool det_udp_send(struct DetUdpPeer *peer, const uint8_t *data, size_t len)
Send a datagram back to the peer captured during the handler call.
Definition udp.cpp:178
bool det_udp_listen(uint16_t port, DetUdpHandler handler, void *ctx)
Bind a UDP port and route incoming datagrams to handler.
Definition udp.cpp:151
bool det_udp_listener_sendto(uint16_t listen_port, const char *dst_ip, uint16_t dst_port, const uint8_t *data, size_t len)
Send a datagram from the listener bound on listen_port to an address.
Definition udp.cpp:234