DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
ntp_server.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 ntp_server.h
6 * @brief NTP/SNTP time server (RFC 5905 / RFC 4330 server mode) on UDP/123.
7 *
8 * The device answers client NTP requests from its own clock, so a LAN with no path to the
9 * public NTP pool (offline, air-gapped, or behind a strict firewall) can still keep its
10 * devices in sync against this one. It is a stateless request/response: a client sends a
11 * 48-octet packet, the server fills in the reference/receive/transmit timestamps (echoing
12 * the client's transmit stamp as the origin so the client can compute round-trip delay)
13 * and sends it back. Zero heap; gated by DETWS_ENABLE_NTP_SERVER (default off).
14 *
15 * The response builder (ntp_server_build_response) is pure - it takes the request bytes and
16 * the current NTP-epoch time and writes the reply - so it is fully host-tested with no lwIP.
17 * ntp_server_begin() binds UDP/123 via the transport UDP service and drives it from
18 * `detws_time_now()` (seconds) plus a `detws_millis()`-derived sub-second fraction.
19 *
20 * @author Douglas Quigg (dstroy0)
21 * @date 2026
22 */
23
24#ifndef DETERMINISTICESPASYNCWEBSERVER_NTP_SERVER_H
25#define DETERMINISTICESPASYNCWEBSERVER_NTP_SERVER_H
26
27#include <stddef.h>
28#include <stdint.h>
29
30/** @brief One NTP packet on the wire is exactly 48 octets (no extension/auth fields). */
31#define NTP_PACKET_LEN 48u
32
33/** @brief Seconds between the NTP epoch (1900-01-01) and the Unix epoch (1970-01-01). */
34#define NTP_UNIX_OFFSET 2208988800u
35
36/** @brief Reference ID "LOCL" - an undisciplined local clock (RFC 5905 sec 7.3). */
37#define NTP_REFID_LOCL 0x4C4F434Cu
38
39/** @brief Reference ID "GPS " - a GPS-disciplined reference clock (use with stratum 1). */
40#define NTP_REFID_GPS 0x47505320u
41
42/**
43 * @brief Build a server (mode 4) reply to a client NTP request. Pure - no clock, no I/O.
44 *
45 * Echoes the request's protocol version, copies the client's transmit timestamp into the
46 * response's origin field, and stamps the reference / receive / transmit times with
47 * (@p ntp_secs, @p ntp_frac). Leap indicator 0, root dispersion ~1 s (a coarse clock).
48 *
49 * @param req the received request bytes.
50 * @param req_len length of @p req (must be >= NTP_PACKET_LEN).
51 * @param stratum stratum to advertise (1-15).
52 * @param refid reference identifier (e.g. NTP_REFID_LOCL).
53 * @param ntp_secs current time, seconds since the NTP epoch (Unix seconds + NTP_UNIX_OFFSET).
54 * @param ntp_frac sub-second fraction as a 32-bit binary fraction of a second.
55 * @param out output buffer.
56 * @param out_cap capacity of @p out (must be >= NTP_PACKET_LEN).
57 * @return NTP_PACKET_LEN on success, or 0 if a length is too small.
58 */
59size_t ntp_server_build_response(const uint8_t *req, size_t req_len, uint8_t stratum, uint32_t refid, uint32_t ntp_secs,
60 uint32_t ntp_frac, uint8_t *out, size_t out_cap);
61
62/**
63 * @brief Start answering NTP requests on UDP/123 from the device's own clock.
64 *
65 * Uses `detws_time_now()` for the seconds and `detws_millis()` for the sub-second fraction.
66 * While the device has no time (`detws_time_now()` returns 0) the server does not reply, so
67 * a client falls through to its next configured source rather than trusting an unset clock.
68 *
69 * @param stratum the stratum to advertise (1 for a GPS/reference clock, 2-15 for a relay).
70 * @param refid the reference identifier to advertise (NTP_REFID_LOCL, NTP_REFID_GPS, ...).
71 * @return true if the UDP listener bound; false on a host build or if the port is taken.
72 */
73bool ntp_server_begin(uint8_t stratum, uint32_t refid = NTP_REFID_LOCL);
74
75#endif // DETERMINISTICESPASYNCWEBSERVER_NTP_SERVER_H
#define NTP_REFID_LOCL
Reference ID "LOCL" - an undisciplined local clock (RFC 5905 sec 7.3).
Definition ntp_server.h:37
bool ntp_server_begin(uint8_t stratum, uint32_t refid=NTP_REFID_LOCL)
Start answering NTP requests on UDP/123 from the device's own clock.
size_t ntp_server_build_response(const uint8_t *req, size_t req_len, uint8_t stratum, uint32_t refid, uint32_t ntp_secs, uint32_t ntp_frac, uint8_t *out, size_t out_cap)
Build a server (mode 4) reply to a client NTP request. Pure - no clock, no I/O.