ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
mdns_service.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 mdns_service.h
6 * @brief Optional mDNS / DNS-SD advertisement (PROTOCORE_ENABLE_MDNS).
7 *
8 * Responds for `<hostname>.local` and advertises an `_http._tcp` service, with optional TXT records
9 * and extra service types.
10 *
11 * Two backends, chosen by PROTOCORE_HAS_VENDOR_MDNS. Where the SDK ships a responder the wrapper drives
12 * that one, because it also probes and resolves name conflicts. Where it does not, the portable
13 * responder answers RFC 6762 / RFC 6763 queries on 224.0.0.251:5353 over the UDP listener: A for the
14 * host, PTR for the enumeration name and each service type, and SRV + TXT per instance. It advertises
15 * rather than defends - no probing, no conflict resolution - so two devices given the same hostname
16 * on one link both answer to it.
17 *
18 * @author Douglas Quigg (dstroy0)
19 * @date 2026
20 */
21
22#ifndef PROTOCORE_MDNS_SERVICE_H
23#define PROTOCORE_MDNS_SERVICE_H
24
25#include "protocore_config.h" // the entry point: protocore_types.h for the widths
26
27#if PROTOCORE_ENABLE_MDNS
28
30
31// PROTOCORE_MDNS_SERVICE_BORROW - the bytes this module runs out of - is stated in protocore_config.h, which sums
32// it into its arena. A caller takes them once and passes the pointer to every call. How they
33// are carved is this module's and is never named here.
34
35/** @brief What begin takes: hostname, http_port. */
36typedef struct
37{
38 const char *hostname; ///< Host label without the `.local` suffix (e.g. "mydevice")
39 uint16_t http_port; ///< TCP port the HTTP server listens on (default 80)
40} MdnsServiceBeginArgs;
41
42/** @brief What txt takes: key, value. */
43typedef struct
44{
45 const char *key;
46 const char *value;
47} MdnsServiceTxtArgs;
48
49/** @brief What add_service takes: service_type, proto, port. */
50typedef struct
51{
52 const char *service_type; ///< DNS-SD service type, e.g. `"_https"`
53 const char *proto; ///< `"_tcp"` or `"_udp"`
54 uint16_t port; ///< TCP/UDP port the service listens on
55} MdnsServiceAddServiceArgs;
56
57/**
58 * @brief Optional mDNS / DNS-SD advertisement (PROTOCORE_ENABLE_MDNS).
59 *
60 * A caller sets the members a call takes, invokes it through ::MdnsService with the bytes it runs
61 * out of, and reads the outcome off the same handle.
62 *
63 * MdnsService.begin_args.hostname = ...;
64 * MdnsService.begin_args.http_port = ...;
65 * MdnsService.begin(work);
66 * // MdnsService.ok is what the call reports
67 *
68 * @var MdnsServiceNs::begin_args what begin takes: hostname, http_port
69 * @var MdnsServiceNs::txt_args what txt takes: key, value
70 * @var MdnsServiceNs::add_service_args what add_service takes: service_type, proto, port
71 * @var MdnsServiceNs::ok true if the responder started; false if disabled at compile time, ...
72 * @var MdnsServiceNs::begin start mDNS responder and advertise an HTTP service. Call once after ...
73 * @var MdnsServiceNs::txt add a TXT key/value record to the advertised `_http._tcp` service. ...
74 * @var MdnsServiceNs::add_service advertise an additional service, e.g. `("_https", "_tcp", 443)`
75 *
76 * @c work is PROTOCORE_MDNS_SERVICE_BORROW bytes the CALLER took, at an address it knows. It is not held past the call,
77 * so nothing here aliases it. How those bytes are carved is this module's and is never named here.
78 */
79typedef struct
80{
81 MdnsServiceBeginArgs begin_args;
82 MdnsServiceTxtArgs txt_args;
83 MdnsServiceAddServiceArgs add_service_args;
84 proto_bool ok;
85} MdnsServiceVars;
86
87/** @brief The operands and the outcome. */
88extern MdnsServiceVars MdnsServiceV;
89
90/** @brief The entries. */
91typedef struct
92{
93 void (*const begin)(uint8_t *work);
94 void (*const txt)(uint8_t *work);
95 void (*const add_service)(uint8_t *work);
96} MdnsServiceNs;
97
98// What the table binds, defined once in the .c and taking one parameter each: everything
99// else an entry needs is an operand in MdnsServiceV or a region of the borrow at a fixed offset.
100void protocore_mdns_service_begin(uint8_t *work);
101void protocore_mdns_service_txt(uint8_t *work);
102void protocore_mdns_service_add_service(uint8_t *work);
103
104// `static const`, initialised HERE rather than `extern` against a definition in the .c: a
105// const object whose initializer every translation unit can see is a COMPILE-TIME FACT, so
106// `MdnsService.begin(work)` resolves to a named function and becomes a DIRECT call. An extern table
107// leaves the call indirect and the symbol live at every level, -O2 -flto included.
108static const MdnsServiceNs MdnsService __attribute__((unused)) = {
109 .begin = protocore_mdns_service_begin,
110 .txt = protocore_mdns_service_txt,
111 .add_service = protocore_mdns_service_add_service,
112};
113
114/**
115 * @brief The PROTOCORE_MDNS_SERVICE_BORROW bytes this module's state lives in.
116 *
117 * Stated beside the namespace rather than on it: an entry takes a borrow, and this is where
118 * that borrow comes from. Taken once from the end of the pool, which no mark and no release
119 * walks, so the state lasts the life of the program.
120 *
121 * @return the span.
122 */
123uint8_t *protocore_mdns_service_span(void);
124
126
127#endif // PROTOCORE_ENABLE_MDNS
128
129#endif // PROTOCORE_MDNS_SERVICE_H
#define PROTOCORE_BEGIN_DECLS
Give a header's declarations C linkage, so their symbol names carry no parameter types.
Definition types.h:96
_Bool proto_bool
The truth value.
Definition types.h:64
#define PROTOCORE_END_DECLS
Definition types.h:97