1 /*
2 * Copyright (c) 2024, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #ifndef MULTICAST_DNS_HPP_
30 #define MULTICAST_DNS_HPP_
31
32 #include "openthread-core-config.h"
33
34 #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
35
36 #include <openthread/mdns.h>
37 #include <openthread/platform/mdns_socket.h>
38
39 #include "common/as_core_type.hpp"
40 #include "common/clearable.hpp"
41 #include "common/debug.hpp"
42 #include "common/equatable.hpp"
43 #include "common/error.hpp"
44 #include "common/heap_allocatable.hpp"
45 #include "common/heap_array.hpp"
46 #include "common/heap_data.hpp"
47 #include "common/heap_string.hpp"
48 #include "common/linked_list.hpp"
49 #include "common/locator.hpp"
50 #include "common/owned_ptr.hpp"
51 #include "common/owning_list.hpp"
52 #include "common/timer.hpp"
53 #include "net/dns_types.hpp"
54
55 #if OPENTHREAD_CONFIG_MULTICAST_DNS_AUTO_ENABLE_ON_INFRA_IF && !OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
56 #error "OPENTHREAD_CONFIG_MULTICAST_DNS_AUTO_ENABLE_ON_INFRA_IF requires OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE"
57 #endif
58
59 /**
60 * @file
61 * This file includes definitions for the Multicast DNS per RFC 6762.
62 */
63
64 /**
65 * Represents an opaque (and empty) type for an mDNS iterator.
66 */
67 struct otMdnsIterator
68 {
69 };
70
71 namespace ot {
72 namespace Dns {
73 namespace Multicast {
74
75 extern "C" void otPlatMdnsHandleReceive(otInstance *aInstance,
76 otMessage *aMessage,
77 bool aIsUnicast,
78 const otPlatMdnsAddressInfo *aAddress);
79
80 /**
81 * Implements Multicast DNS (mDNS) core.
82 */
83 class Core : public InstanceLocator, private NonCopyable
84 {
85 friend void otPlatMdnsHandleReceive(otInstance *aInstance,
86 otMessage *aMessage,
87 bool aIsUnicast,
88 const otPlatMdnsAddressInfo *aAddress);
89
90 public:
91 /**
92 * Initializes a `Core` instance.
93 *
94 * @param[in] aInstance The OpenThread instance.
95 */
96 explicit Core(Instance &aInstance);
97
98 typedef otMdnsRequestId RequestId; ///< A request Identifier.
99 typedef otMdnsRegisterCallback RegisterCallback; ///< Registration callback.
100 typedef otMdnsConflictCallback ConflictCallback; ///< Conflict callback.
101 typedef otMdnsEntryState EntryState; ///< Host/Service/Key entry state.
102 typedef otMdnsHost Host; ///< Host information.
103 typedef otMdnsService Service; ///< Service information.
104 typedef otMdnsKey Key; ///< Key information.
105 typedef otMdnsBrowser Browser; ///< Browser.
106 typedef otMdnsBrowseCallback BrowseCallback; ///< Browser callback.
107 typedef otMdnsBrowseResult BrowseResult; ///< Browser result.
108 typedef otMdnsSrvResolver SrvResolver; ///< SRV resolver.
109 typedef otMdnsSrvCallback SrvCallback; ///< SRV callback.
110 typedef otMdnsSrvResult SrvResult; ///< SRV result.
111 typedef otMdnsTxtResolver TxtResolver; ///< TXT resolver.
112 typedef otMdnsTxtCallback TxtCallback; ///< TXT callback.
113 typedef otMdnsTxtResult TxtResult; ///< TXT result.
114 typedef otMdnsAddressResolver AddressResolver; ///< Address resolver.
115 typedef otMdnsAddressCallback AddressCallback; ///< Address callback
116 typedef otMdnsAddressResult AddressResult; ///< Address result.
117 typedef otMdnsAddressAndTtl AddressAndTtl; ///< Address and TTL.
118 typedef otMdnsIterator Iterator; ///< An entry iterator.
119 typedef otMdnsCacheInfo CacheInfo; ///< Cache information.
120
121 /**
122 * Represents a socket address info.
123 */
124 class AddressInfo : public otPlatMdnsAddressInfo, public Clearable<AddressInfo>, public Equatable<AddressInfo>
125 {
126 public:
127 /**
128 * Initializes the `AddressInfo` clearing all the fields.
129 */
AddressInfo(void)130 AddressInfo(void) { Clear(); }
131
132 /**
133 * Gets the IPv6 address.
134 *
135 * @returns the IPv6 address.
136 */
GetAddress(void) const137 const Ip6::Address &GetAddress(void) const { return AsCoreType(&mAddress); }
138 };
139
140 /**
141 * Enables or disables the mDNS module.
142 *
143 * mDNS module should be enabled before registration any host, service, or key entries. Disabling mDNS will
144 * immediately stop all operations and any communication (multicast or unicast tx) and remove any previously
145 * registered entries without sending any "goodbye" announcements or invoking their callback. When disabled,
146 * all browsers and resolvers are stopped and all cached information is cleared.
147 *
148 * @param[in] aEnable Whether to enable or disable.
149 * @param[in] aInfraIfIndex The network interface index for mDNS operation. Value is ignored when disabling.
150 *
151 * @retval kErrorNone Enabled or disabled the mDNS module successfully.
152 * @retval kErrorAlready mDNS is already enabled on an enable request, or is already disabled on a disable request.
153 * @retval kErrorFailed Failed to enable/disable mDNS.
154 */
155 Error SetEnabled(bool aEnable, uint32_t aInfraIfIndex);
156
157 /**
158 * Indicates whether or not mDNS module is enabled.
159 *
160 * @retval TRUE The mDNS module is enabled.
161 * @retval FALSE The mDNS module is disabled.
162 */
IsEnabled(void) const163 bool IsEnabled(void) const { return mIsEnabled; }
164
165 #if OPENTHREAD_CONFIG_MULTICAST_DNS_AUTO_ENABLE_ON_INFRA_IF
166 /**
167 * Notifies `AdvertisingProxy` that `InfraIf` state changed.
168 */
169 void HandleInfraIfStateChanged(void);
170 #endif
171
172 /**
173 * Sets whether mDNS module is allowed to send questions requesting unicast responses referred to as "QU" questions.
174 *
175 * The "QU" question request unicast response in contrast to "QM" questions which request multicast responses.
176 * When allowed, the first probe will be sent as a "QU" question.
177 *
178 * This can be used to address platform limitation where platform cannot accept unicast response received on mDNS
179 * port.
180 *
181 * @param[in] aAllow Indicates whether or not to allow "QU" questions.
182 */
SetQuestionUnicastAllowed(bool aAllow)183 void SetQuestionUnicastAllowed(bool aAllow) { mIsQuestionUnicastAllowed = aAllow; }
184
185 /**
186 * Indicates whether mDNS module is allowed to send "QU" questions requesting unicast response.
187 *
188 * @retval TRUE The mDNS module is allowed to send "QU" questions.
189 * @retval FALSE The mDNS module is not allowed to send "QU" questions.
190 */
IsQuestionUnicastAllowed(void) const191 bool IsQuestionUnicastAllowed(void) const { return mIsQuestionUnicastAllowed; }
192
193 /**
194 * Sets the conflict callback.
195 *
196 * @param[in] aCallback The conflict callback. Can be `nullptr` is not needed.
197 */
SetConflictCallback(ConflictCallback aCallback)198 void SetConflictCallback(ConflictCallback aCallback) { mConflictCallback = aCallback; }
199
200 /**
201 * Registers or updates a host.
202 *
203 * The fields in @p aHost follow these rules:
204 *
205 * - The `mHostName` field specifies the host name to register (e.g., "myhost"). MUST NOT contain the domain name.
206 * - The `mAddresses` is array of IPv6 addresses to register with the host. `mAddressesLength` provides the number
207 * of entries in `mAddresses` array.
208 * - The `mAddresses` array can be empty with zero `mAddressesLength`. In this case, mDNS will treat it as if host
209 * is unregistered and stop advertising any addresses for this the host name.
210 * - The `mTtl` specifies the TTL if non-zero. If zero, the mDNS core will choose a default TTL to use.
211 *
212 * This method can be called again for the same `mHostName` to update a previously registered host entry, for
213 * example, to change the list of addresses of the host. In this case, the mDNS module will send "goodbye"
214 * announcements for any previously registered and now removed addresses and announce any newly added addresses.
215 *
216 * The outcome of the registration request is reported back by invoking the provided @p aCallback with
217 * @p aRequestId as its input and one of the following `aError` inputs:
218 *
219 * - `kErrorNone` indicates registration was successful
220 * - `kErrorDuplicated` indicates a name conflict, i.e., the name is already claimed by another mDNS responder.
221 *
222 * For caller convenience, the OpenThread mDNS module guarantees that the callback will be invoked after this
223 * method returns, even in cases of immediate registration success. The @p aCallback can be `nullptr` if caller
224 * does not want to be notified of the outcome.
225 *
226 * @param[in] aHost The host to register.
227 * @param[in] aRequestId The ID associated with this request.
228 * @param[in] aCallback The callback function pointer to report the outcome (can be `nullptr` if not needed).
229 *
230 * @retval kErrorNone Successfully started registration. @p aCallback will report the outcome.
231 * @retval kErrorInvalidState mDNS module is not enabled.
232 */
233 Error RegisterHost(const Host &aHost, RequestId aRequestId, RegisterCallback aCallback);
234
235 /**
236 * Unregisters a host.
237 *
238 * The fields in @p aHost follow these rules:
239 *
240 * - The `mHostName` field specifies the host name to unregister (e.g., "myhost"). MUST NOT contain the domain name.
241 * - The rest of the fields in @p aHost structure are ignored in an `UnregisterHost()` call.
242 *
243 * If there is no previously registered host with the same name, no action is performed.
244 *
245 * If there is a previously registered host with the same name, the mDNS module will send "goodbye" announcement
246 * for all previously advertised address records.
247 *
248 * @param[in] aHost The host to unregister.
249 *
250 * @retval kErrorNone Successfully unregistered host.
251 * @retval kErrorInvalidState mDNS module is not enabled.
252 */
253 Error UnregisterHost(const Host &aHost);
254
255 /**
256 * Registers or updates a service.
257 *
258 * The fields in @p aService follow these rules:
259 *
260 * - The `mServiceInstance` specifies the service instance label. It is treated as a single DNS label. It may
261 * contain dot `.` character which is allowed in a service instance label.
262 * - The `mServiceType` specifies the service type (e.g., "_tst._udp"). It is treated as multiple dot `.` separated
263 * labels. It MUST NOT contain the domain name.
264 * - The `mHostName` field specifies the host name of the service. MUST NOT contain the domain name.
265 * - The `mSubTypeLabels` is an array of strings representing sub-types associated with the service. Each array
266 * entry is a sub-type label. The `mSubTypeLabels can be `nullptr` if there are no sub-types. Otherwise, the
267 * array length is specified by `mSubTypeLabelsLength`.
268 * - The `mTxtData` and `mTxtDataLength` specify the encoded TXT data. The `mTxtData` can be `nullptr` or
269 * `mTxtDataLength` can be zero to specify an empty TXT data. In this case mDNS module will use a single zero
270 * byte `[ 0 ]` as empty TXT data.
271 * - The `mPort`, `mWeight`, and `mPriority` specify the service's parameters (as specified in DNS SRV record).
272 * - The `mTtl` specifies the TTL if non-zero. If zero, the mDNS module will use default TTL for service entry.
273 *
274 * This method can be called again for the same `mServiceInstance` and `mServiceType` to update a previously
275 * registered service entry, for example, to change the sub-types list or update any parameter such as port, weight,
276 * priority, TTL, or host name. The mDNS module will send announcements for any changed info, e.g., will send
277 * "goodbye" announcements for any removed sub-types and announce any newly added sub-types.
278 *
279 * Regarding the invocation of the @p aCallback, this method behaves in the same way as described in
280 * `RegisterHost()`.
281 *
282 * @param[in] aService The service to register.
283 * @param[in] aRequestId The ID associated with this request.
284 * @param[in] aCallback The callback function pointer to report the outcome (can be `nullptr` if not needed).
285 *
286 * @retval kErrorNone Successfully started registration. @p aCallback will report the outcome.
287 * @retval kErrorInvalidState mDNS module is not enabled.
288 */
289 Error RegisterService(const Service &aService, RequestId aRequestId, RegisterCallback aCallback);
290
291 /**
292 * Unregisters a service.
293 *
294 * The fields in @p aService follow these rules:
295
296 * - The `mServiceInstance` specifies the service instance label. It is treated as a single DNS label. It may
297 * contain dot `.` character which is allowed in a service instance label.
298 * - The `mServiceType` specifies the service type (e.g., "_tst._udp"). It is treated as multiple dot `.` separated
299 * labels. It MUST NOT contain the domain name.
300 * - The rest of the fields in @p aService structure are ignored in a`otMdnsUnregisterService()` call.
301 *
302 * If there is no previously registered service with the same name, no action is performed.
303 *
304 * If there is a previously registered service with the same name, the mDNS module will send "goodbye"
305 * announcements for all related records.
306 *
307 * @param[in] aService The service to unregister.
308 *
309 * @retval kErrorNone Successfully unregistered service.
310 * @retval kErrorInvalidState mDNS module is not enabled.
311 */
312 Error UnregisterService(const Service &aService);
313
314 /**
315 * Registers or updates a key record.
316 *
317 * The fields in @p aKey follow these rules:
318 *
319 * - If the key is associated with a host entry, the `mName` field specifies the host name and the `mServiceType`
320 * MUST be `nullptr`.
321 * - If the key is associated with a service entry, the `mName` filed specifies the service instance label (always
322 * treated as a single label) and the `mServiceType` filed specifies the service type (e.g. "_tst._udp"). In this
323 * case the DNS name for key record is `<mName>.<mServiceTye>`.
324 * - The `mKeyData` field contains the key record's data with `mKeyDataLength` as its length in byes.
325 * - The `mTtl` specifies the TTL if non-zero. If zero, the mDNS module will use default TTL for the key entry.
326 *
327 * This method can be called again for the same name to updated a previously registered key entry, for example,
328 * to change the key data or TTL.
329 *
330 * Regarding the invocation of the @p aCallback, this method behaves in the same way as described in
331 * `RegisterHost()`.
332 *
333 * @param[in] aKey The key record to register.
334 * @param[in] aRequestId The ID associated with this request.
335 * @param[in] aCallback The callback function pointer to report the outcome (can be `nullptr` if not needed).
336 *
337 * @retval kErrorNone Successfully started registration. @p aCallback will report the outcome.
338 * @retval kErrorInvalidState mDNS module is not enabled.
339 */
340 Error RegisterKey(const Key &aKey, RequestId aRequestId, RegisterCallback aCallback);
341
342 /**
343 * Unregisters a key record on mDNS.
344 *
345 * The fields in @p aKey follow these rules:
346 *
347 * - If the key is associated with a host entry, the `mName` field specifies the host name and the `mServiceType`
348 * MUST be `nullptr`.
349 * - If the key is associated with a service entry, the `mName` filed specifies the service instance label (always
350 * treated as a single label) and the `mServiceType` field specifies the service type (e.g. "_tst._udp"). In this
351 * case the DNS name for key record is `<mName>.<mServiceTye>`.
352 * - The rest of the fields in @p aKey structure are ignored in a`otMdnsUnregisterKey()` call.
353 *
354 * If there is no previously registered key with the same name, no action is performed.
355 *
356 * If there is a previously registered key with the same name, the mDNS module will send "goodbye" announcements
357 * for the key record.
358 *
359 * @param[in] aKey The key to unregister.
360 *
361 * @retval kErrorNone Successfully unregistered key
362 * @retval kErrorInvalidState mDNS module is not enabled.
363 */
364 Error UnregisterKey(const Key &aKey);
365
366 /**
367 * Starts a service browser.
368 *
369 * Initiates a continuous search for the specified `mServiceType` in @p aBrowser. For sub-type services, use
370 * `mSubTypeLabel` to define the sub-type, for base services, set `mSubTypeLabel` to NULL.
371 *
372 * Discovered services are reported through the `mCallback` function in @p aBrowser. Services that have been
373 * removed are reported with a TTL value of zero. The callback may be invoked immediately with cached information
374 * (if available) and potentially before this method returns. When cached results are used, the reported TTL value
375 * will reflect the original TTL from the last received response.
376 *
377 * Multiple browsers can be started for the same service, provided they use different callback functions.
378 *
379 * @param[in] aBrowser The browser to be started.
380 *
381 * @retval kErrorNone Browser started successfully.
382 * @retval kErrorInvalidState mDNS module is not enabled.
383 * @retval kErrorAlready An identical browser (same service and callback) is already active.
384 */
385 Error StartBrowser(const Browser &aBrowser);
386
387 /**
388 * Stops a service browser.
389 *
390 * No action is performed if no matching browser with the same service and callback is currently active.
391 *
392 * @param[in] aBrowser The browser to stop.
393 *
394 * @retval kErrorNone Browser stopped successfully.
395 * @retval kErrorInvalidSatet mDNS module is not enabled.
396 */
397 Error StopBrowser(const Browser &aBrowser);
398
399 /**
400 * Starts an SRV record resolver.
401 *
402 * Initiates a continuous SRV record resolver for the specified service in @p aResolver.
403 *
404 * Discovered information is reported through the `mCallback` function in @p aResolver. When the service is removed
405 * it is reported with a TTL value of zero. In this case, `mHostName` may be NULL and other result fields (such as
406 * `mPort`) should be ignored.
407 *
408 * The callback may be invoked immediately with cached information (if available) and potentially before this
409 * method returns. When cached result is used, the reported TTL value will reflect the original TTL from the last
410 * received response.
411 *
412 * Multiple resolvers can be started for the same service, provided they use different callback functions.
413 *
414 * @param[in] aResolver The resolver to be started.
415 *
416 * @retval kErrorNone Resolver started successfully.
417 * @retval kErrorInvalidState mDNS module is not enabled.
418 * @retval kErrorAlready An identical resolver (same service and callback) is already active.
419 */
420 Error StartSrvResolver(const SrvResolver &aResolver);
421
422 /**
423 * Stops an SRV record resolver.
424 *
425 * No action is performed if no matching resolver with the same service and callback is currently active.
426 *
427 * @param[in] aResolver The resolver to stop.
428 *
429 * @retval kErrorNone Resolver stopped successfully.
430 * @retval kErrorInvalidState mDNS module is not enabled.
431 */
432 Error StopSrvResolver(const SrvResolver &aResolver);
433
434 /**
435 * Starts a TXT record resolver.
436 *
437 * Initiates a continuous TXT record resolver for the specified service in @p aResolver.
438 *
439 * Discovered information is reported through the `mCallback` function in @p aResolver. When the TXT record is
440 * removed it is reported with a TTL value of zero. In this case, `mTxtData` may be NULL, and other result fields
441 * (such as `mTxtDataLength`) should be ignored.
442 *
443 * The callback may be invoked immediately with cached information (if available) and potentially before this
444 * method returns. When cached result is used, the reported TTL value will reflect the original TTL from the last
445 * received response.
446 *
447 * Multiple resolvers can be started for the same service, provided they use different callback functions.
448 *
449 * @param[in] aResolver The resolver to be started.
450 *
451 * @retval kErrorNone Resolver started successfully.
452 * @retval kErrorInvalidState mDNS module is not enabled.
453 * @retval kErrorAlready An identical resolver (same service and callback) is already active.
454 */
455 Error StartTxtResolver(const TxtResolver &aResolver);
456
457 /**
458 * Stops a TXT record resolver.
459 *
460 * No action is performed if no matching resolver with the same service and callback is currently active.
461 *
462 * @param[in] aResolver The resolver to stop.
463 *
464 * @retval kErrorNone Resolver stopped successfully.
465 * @retval kErrorInvalidState mDNS module is not enabled.
466 */
467 Error StopTxtResolver(const TxtResolver &aResolver);
468
469 /**
470 * Starts an IPv6 address resolver.
471 *
472 * Initiates a continuous IPv6 address resolver for the specified host name in @p aResolver.
473 *
474 * Discovered addresses are reported through the `mCallback` function in @p aResolver. The callback is invoked
475 * whenever addresses are added or removed, providing an updated list. If all addresses are removed, the callback
476 * is invoked with an empty list (`mAddresses` will be NULL, and `mAddressesLength` will be zero).
477 *
478 * The callback may be invoked immediately with cached information (if available) and potentially before this
479 * method returns. When cached result is used, the reported TTL values will reflect the original TTL from the last
480 * received response.
481 *
482 * Multiple resolvers can be started for the same host name, provided they use different callback functions.
483 *
484 * @param[in] aResolver The resolver to be started.
485 *
486 * @retval kErrorNone Resolver started successfully.
487 * @retval kErrorInvalidState mDNS module is not enabled.
488 * @retval kErrorAlready An identical resolver (same host and callback) is already active.
489 */
490 Error StartIp6AddressResolver(const AddressResolver &aResolver);
491
492 /**
493 * Stops an IPv6 address resolver.
494 *
495 * No action is performed if no matching resolver with the same host name and callback is currently active.
496 *
497 * @param[in] aResolver The resolver to stop.
498 *
499 * @retval kErrorNone Resolver stopped successfully.
500 * @retval kErrorInvalidState mDNS module is not enabled.
501 */
502 Error StopIp6AddressResolver(const AddressResolver &aResolver);
503
504 /**
505 * Starts an IPv4 address resolver.
506 *
507 * Initiates a continuous IPv4 address resolver for the specified host name in @p aResolver.
508 *
509 * Discovered addresses are reported through the `mCallback` function in @p aResolver. The IPv4 addresses are
510 * represented using the IPv4-mapped IPv6 address format in `mAddresses` array. The callback is invoked whenever
511 * addresses are added or removed, providing an updated list. If all addresses are removed, the callback is invoked
512 * with an empty list (`mAddresses` will be NULL, and `mAddressesLength` will be zero).
513 *
514 * The callback may be invoked immediately with cached information (if available) and potentially before this
515 * method returns. When cached result is used, the reported TTL values will reflect the original TTL from the last
516 * received response.
517 *
518 * Multiple resolvers can be started for the same host name, provided they use different callback functions.
519 *
520 * @param[in] aResolver The resolver to be started.
521 *
522 * @retval kErrorNone Resolver started successfully.
523 * @retval kErrorInvalidState mDNS module is not enabled.
524 * @retval kErrorAlready An identical resolver (same host and callback) is already active.
525 */
526 Error StartIp4AddressResolver(const AddressResolver &aResolver);
527
528 /**
529 * Stops an IPv4 address resolver.
530 *
531 * No action is performed if no matching resolver with the same host name and callback is currently active.
532 *
533 * @param[in] aResolver The resolver to stop.
534 *
535 * @retval kErrorNone Resolver stopped successfully.
536 * @retval kErrorInvalidState mDNS module is not enabled.
537 */
538 Error StopIp4AddressResolver(const AddressResolver &aResolver);
539
540 /**
541 * Sets the max size threshold for mDNS messages.
542 *
543 * This method is mainly intended for testing. The max size threshold is used to break larger messages.
544 *
545 * @param[in] aMaxSize The max message size threshold.
546 */
SetMaxMessageSize(uint16_t aMaxSize)547 void SetMaxMessageSize(uint16_t aMaxSize) { mMaxMessageSize = aMaxSize; }
548
549 #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
550
551 /**
552 * Allocates a new iterator.
553 *
554 * @returns A pointer to the newly allocated iterator or `nullptr` if it fails to allocate.
555 */
556 Iterator *AllocateIterator(void);
557
558 /**
559 * Frees a previously allocated iterator.
560 *
561 * @param[in] aIterator The iterator to free.
562 */
563 void FreeIterator(Iterator &aIterator);
564
565 /**
566 * Iterates over registered host entries.
567 *
568 * On success, @p aHost is populated with information about the next host. Pointers within the `Host` structure
569 * (like `mName`) remain valid until the next call to any OpenThread stack's public or platform API/callback.
570 *
571 * @param[in] aIterator The iterator to use.
572 * @param[out] aHost A `Host` to return the information about the next host entry.
573 * @param[out] aState An `EntryState` to return the entry state.
574 *
575 * @retval kErrorNone @p aHost, @p aState, & @p aIterator are updated successfully.
576 * @retval kErrorNotFound Reached the end of the list.
577 * @retval kErrorInvalidArg @p aIterator is not valid.
578 */
579 Error GetNextHost(Iterator &aIterator, Host &aHost, EntryState &aState) const;
580
581 /**
582 * Iterates over registered service entries.
583 *
584 * On success, @p aService is populated with information about the next service. Pointers within the `Service`
585 * structure (like `mServiceType`) remain valid until the next call to any OpenThread stack's public or platform
586 * API/callback.
587 *
588 * @param[out] aService A `Service` to return the information about the next service entry.
589 * @param[out] aState An `EntryState` to return the entry state.
590 *
591 * @retval kErrorNone @p aService, @p aState, & @p aIterator are updated successfully.
592 * @retval kErrorNotFound Reached the end of the list.
593 * @retval kErrorInvalidArg @p aIterator is not valid.
594 */
595 Error GetNextService(Iterator &aIterator, Service &aService, EntryState &aState) const;
596
597 /**
598 * Iterates over registered key entries.
599 *
600 * On success, @p aKey is populated with information about the next key. Pointers within the `Key` structure
601 * (like `mName`) remain valid until the next call to any OpenThread stack's public or platform API/callback.
602 *
603 * @param[out] aKey A `Key` to return the information about the next key entry.
604 * @param[out] aState An `EntryState` to return the entry state.
605 *
606 * @retval kErrorNone @p aKey, @p aState, & @p aIterator are updated successfully.
607 * @retval kErrorNotFound Reached the end of the list.
608 * @retval kErrorInvalidArg @p aIterator is not valid.
609 */
610 Error GetNextKey(Iterator &aIterator, Key &aKey, EntryState &aState) const;
611
612 /**
613 * Iterates over browsers.
614 *
615 * On success, @p aBrowser is populated with information about the next browser. Pointers within the `Browser`
616 * structure remain valid until the next call to any OpenThread stack's public or platform API/callback.
617 *
618 * @param[in] aIterator The iterator to use.
619 * @param[out] aBrowser A `Browser` to return the information about the next browser.
620 * @param[out] aInfo A `CacheInfo` to return additional information.
621 *
622 * @retval kErrorNone @p aBrowser, @p aInfo, & @p aIterator are updated successfully.
623 * @retval kErrorNotFound Reached the end of the list.
624 * @retval kErrorInvalidArg @p aIterator is not valid.
625 */
626 Error GetNextBrowser(Iterator &aIterator, Browser &aBrowser, CacheInfo &aInfo) const;
627
628 /**
629 * Iterates over SRV resolvers.
630 *
631 * On success, @p aResolver is populated with information about the next resolver. Pointers within the `SrvResolver`
632 * structure remain valid until the next call to any OpenThread stack's public or platform API/callback.
633 *
634 * @param[in] aIterator The iterator to use.
635 * @param[out] aResolver An `SrvResolver` to return the information about the next resolver.
636 * @param[out] aInfo A `CacheInfo` to return additional information.
637 *
638 * @retval kErrorNone @p aResolver, @p aInfo, & @p aIterator are updated successfully.
639 * @retval kErrorNotFound Reached the end of the list.
640 * @retval kErrorInvalidArg @p aIterator is not valid.
641 */
642 Error GetNextSrvResolver(Iterator &aIterator, SrvResolver &aResolver, CacheInfo &aInfo) const;
643
644 /**
645 * Iterates over TXT resolvers.
646 *
647 * On success, @p aResolver is populated with information about the next resolver. Pointers within the `TxtResolver`
648 * structure remain valid until the next call to any OpenThread stack's public or platform API/callback.
649 *
650 * @param[in] aIterator The iterator to use.
651 * @param[out] aResolver A `TxtResolver` to return the information about the next resolver.
652 * @param[out] aInfo A `CacheInfo` to return additional information.
653 *
654 * @retval kErrorNone @p aResolver, @p aInfo, & @p aIterator are updated successfully.
655 * @retval kErrorNotFound Reached the end of the list.
656 * @retval kErrorInvalidArg @p aIterator is not valid.
657 */
658 Error GetNextTxtResolver(Iterator &aIterator, TxtResolver &aResolver, CacheInfo &aInfo) const;
659
660 /**
661 * Iterates over IPv6 address resolvers.
662 *
663 * On success, @p aResolver is populated with information about the next resolver. Pointers within the
664 * `AddressResolver` structure remain valid until the next call to any OpenThread stack's public or platform
665 * API/callback.
666 *
667 * @param[in] aIterator The iterator to use.
668 * @param[out] aResolver An `AddressResolver to return the information about the next resolver.
669 * @param[out] aInfo A `CacheInfo` to return additional information.
670 *
671 * @retval kErrorNone @p aResolver, @p aInfo, & @p aIterator are updated successfully.
672 * @retval kErrorNotFound Reached the end of the list.
673 * @retval kErrorInvalidArg @p aIterator is not valid.
674 */
675 Error GetNextIp6AddressResolver(Iterator &aIterator, AddressResolver &aResolver, CacheInfo &aInfo) const;
676
677 /**
678 * Iterates over IPv4 address resolvers.
679 *
680 * On success, @p aResolver is populated with information about the next resolver. Pointers within the
681 * `AddressResolver` structure remain valid until the next call to any OpenThread stack's public or platform
682 * API/callback.
683 *
684 * @param[in] aIterator The iterator to use.
685 * @param[out] aResolver An `AddressResolver to return the information about the next resolver.
686 * @param[out] aInfo A `CacheInfo` to return additional information.
687 *
688 * @retval kErrorNone @p aResolver, @p aInfo, & @p aIterator are updated successfully.
689 * @retval kErrorNotFound Reached the end of the list.
690 * @retval kErrorInvalidArg @p aIterator is not valid.
691 */
692 Error GetNextIp4AddressResolver(Iterator &aIterator, AddressResolver &aResolver, CacheInfo &aInfo) const;
693
694 #endif // OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
695
696 private:
697 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
698
699 static constexpr uint16_t kUdpPort = 5353;
700
701 static constexpr bool kDefaultQuAllowed = OPENTHREAD_CONFIG_MULTICAST_DNS_DEFAULT_QUESTION_UNICAST_ALLOWED;
702
703 static constexpr uint32_t kMaxMessageSize = 1200;
704
705 static constexpr uint8_t kNumberOfProbes = 3;
706 static constexpr uint32_t kMinProbeDelay = 20; // In msec
707 static constexpr uint32_t kMaxProbeDelay = 250; // In msec
708 static constexpr uint32_t kProbeWaitTime = 250; // In msec
709
710 static constexpr uint8_t kNumberOfAnnounces = 3;
711 static constexpr uint32_t kAnnounceInterval = 1000; // In msec - time between first two announces
712
713 static constexpr uint8_t kNumberOfInitalQueries = 3;
714 static constexpr uint32_t kInitialQueryInterval = 1000; // In msec - time between first two queries
715
716 static constexpr uint32_t kMinInitialQueryDelay = 20; // msec
717 static constexpr uint32_t kMaxInitialQueryDelay = 120; // msec
718 static constexpr uint32_t kRandomDelayReuseInterval = 2; // msec
719
720 static constexpr uint32_t kMinResponseDelay = 20; // msec
721 static constexpr uint32_t kMaxResponseDelay = 120; // msec
722 static constexpr uint32_t kResponseAggregationMaxDelay = 500; // msec
723
724 static constexpr uint32_t kUnspecifiedTtl = 0;
725 static constexpr uint32_t kDefaultTtl = 120;
726 static constexpr uint32_t kDefaultKeyTtl = kDefaultTtl;
727 static constexpr uint32_t kLegacyUnicastNsecTtl = 10;
728 static constexpr uint32_t kNsecTtl = 4500;
729 static constexpr uint32_t kServicesPtrTtl = 4500;
730
731 static constexpr uint16_t kClassQuestionUnicastFlag = (1U << 15);
732 static constexpr uint16_t kClassCacheFlushFlag = (1U << 15);
733 static constexpr uint16_t kClassMask = (0x7fff);
734
735 static constexpr uint16_t kUnspecifiedOffset = 0;
736
737 static constexpr uint8_t kNumSections = 4;
738
739 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
740
741 enum Section : uint8_t
742 {
743 kQuestionSection,
744 kAnswerSection,
745 kAuthoritySection,
746 kAdditionalDataSection,
747 };
748
749 enum AppendOutcome : uint8_t
750 {
751 kAppendedFullNameAsCompressed,
752 kAppendedLabels,
753 };
754
755 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
756 // Forward declarations
757
758 struct EntryContext;
759 class TxMessage;
760 class RxMessage;
761 class ServiceEntry;
762 class ServiceType;
763 class EntryIterator;
764
765 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
766
767 struct EmptyChecker
768 {
769 // Used in `Matches()` to find empty entries (with no record) to remove and free.
770 };
771
772 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
773
774 struct ExpireChecker
775 {
776 // Used in `Matches()` to find expired entries in a list.
777
ExpireCheckerot::Dns::Multicast::Core::ExpireChecker778 explicit ExpireChecker(TimeMilli aNow) { mNow = aNow; }
779
780 TimeMilli mNow;
781 };
782
783 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
784
785 class Callback : public Clearable<Callback>
786 {
787 public:
Callback(void)788 Callback(void) { Clear(); }
789 Callback(RequestId aRequestId, RegisterCallback aCallback);
790
IsEmpty(void) const791 bool IsEmpty(void) const { return (mCallback == nullptr); }
792 void InvokeAndClear(Instance &aInstance, Error aError);
793
794 private:
795 RequestId mRequestId;
796 RegisterCallback mCallback;
797 };
798
799 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
800
801 class RecordCounts : public Clearable<RecordCounts>
802 {
803 public:
RecordCounts(void)804 RecordCounts(void) { Clear(); }
805
GetFor(Section aSection) const806 uint16_t GetFor(Section aSection) const { return mCounts[aSection]; }
Increment(Section aSection)807 void Increment(Section aSection) { mCounts[aSection]++; }
808 void ReadFrom(const Header &aHeader);
809 void WriteTo(Header &aHeader) const;
810 bool IsEmpty(void) const;
811
812 private:
813 uint16_t mCounts[kNumSections];
814 };
815
816 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
817
818 struct AnswerInfo
819 {
GetAnswerTimeot::Dns::Multicast::Core::AnswerInfo820 TimeMilli GetAnswerTime(void) const { return (mQueryRxTime + mAnswerDelay); }
821
822 uint16_t mQuestionRrType;
823 uint16_t mAnswerDelay;
824 TimeMilli mQueryRxTime;
825 bool mIsProbe;
826 bool mUnicastResponse;
827 bool mLegacyUnicastResponse;
828 };
829
830 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
831
832 class AddressArray : public Heap::Array<Ip6::Address>
833 {
834 public:
835 bool Matches(const Ip6::Address *aAddresses, uint16_t aNumAddresses) const;
836 void SetFrom(const Ip6::Address *aAddresses, uint16_t aNumAddresses);
837 };
838
839 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
840
841 class FireTime
842 {
843 public:
FireTime(void)844 FireTime(void) { ClearFireTime(); }
ClearFireTime(void)845 void ClearFireTime(void) { mHasFireTime = false; }
HasFireTime(void) const846 bool HasFireTime(void) const { return mHasFireTime; }
GetFireTime(void) const847 TimeMilli GetFireTime(void) const { return mFireTime; }
848 void SetFireTime(TimeMilli aFireTime);
849
850 protected:
851 void ScheduleFireTimeOn(TimerMilli &aTimer);
852 void UpdateNextFireTimeOn(NextFireTime &aNextFireTime) const;
853
854 private:
855 TimeMilli mFireTime;
856 bool mHasFireTime;
857 };
858
859 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
860
861 class RecordInfo : public Clearable<RecordInfo>, private NonCopyable
862 {
863 public:
864 // Keeps track of record state and timings.
865
866 static constexpr uint32_t kMaxLegacyUnicastTtl = 10; // seconds
867
RecordInfo(void)868 RecordInfo(void) { Clear(); }
869
IsPresent(void) const870 bool IsPresent(void) const { return mIsPresent; }
871
872 template <typename UintType> void UpdateProperty(UintType &aProperty, UintType aValue);
873 void UpdateProperty(AddressArray &aAddrProperty, const Ip6::Address *aAddrs, uint16_t aNumAddrs);
874 void UpdateProperty(Heap::String &aStringProperty, const char *aString);
875 void UpdateProperty(Heap::Data &aDataProperty, const uint8_t *aData, uint16_t aLength);
876
877 uint32_t GetTtl(bool aIsLegacyUnicast = false) const;
878 void UpdateTtl(uint32_t aTtl);
879
880 void StartAnnouncing(void);
881 bool ShouldAppendTo(EntryContext &aContext);
882 bool CanAnswer(void) const;
883 void ScheduleAnswer(const AnswerInfo &aInfo);
884 Error ExtendAnswerDelay(EntryContext &aContext);
885 void UpdateStateAfterAnswer(const TxMessage &aResponse);
886 void UpdateFireTimeOn(FireTime &aFireTime);
887 void DetermineNextAggrTxTime(NextFireTime &aNextAggrTxTime) const;
888 uint32_t GetDurationSinceLastMulticast(TimeMilli aTime) const;
889 Error GetLastMulticastTime(TimeMilli &aLastMulticastTime) const;
890
891 // `AppendState` methods: Used to track whether the record
892 // is appended in a message, or needs to be appended in
893 // Additional Data section.
894
MarkAsNotAppended(void)895 void MarkAsNotAppended(void) { mAppendState = kNotAppended; }
896 void MarkAsAppended(TxMessage &aTxMessage, Section aSection);
897 void MarkToAppendInAdditionalData(void);
898 bool IsAppended(void) const;
899 bool CanAppend(void) const;
ShouldAppendInAdditionalDataSection(void) const900 bool ShouldAppendInAdditionalDataSection(void) const { return (mAppendState == kToAppendInAdditionalData); }
901
902 private:
903 enum AppendState : uint8_t
904 {
905 kNotAppended,
906 kToAppendInAdditionalData,
907 kAppendedInMulticastMsg,
908 kAppendedInUnicastMsg,
909 };
910
GetAnswerTime(void) const911 TimeMilli GetAnswerTime(void) const { return mQueryRxTime + mAnswerDelay; }
912
913 static constexpr uint32_t kMinIntervalBetweenMulticast = 1000; // msec
914 static constexpr uint32_t kLastMulticastTimeAge = 10 * Time::kOneHourInMsec;
915
916 static_assert(kNotAppended == 0, "kNotAppended MUST be zero, so `Clear()` works correctly");
917
918 bool mIsPresent : 1;
919 bool mMulticastAnswerPending : 1;
920 bool mUnicastAnswerPending : 1;
921 bool mIsLastMulticastValid : 1;
922 bool mCanExtendAnswerDelay : 1;
923 uint8_t mAnnounceCounter;
924 AppendState mAppendState;
925 Section mAppendSection;
926 uint16_t mAnswerDelay;
927 uint32_t mTtl;
928 TimeMilli mAnnounceTime;
929 TimeMilli mQueryRxTime;
930 TimeMilli mLastMulticastTime;
931 };
932
933 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
934
935 class Entry : public InstanceLocatorInit, public FireTime, private NonCopyable
936 {
937 // Base class for `HostEntry` and `ServiceEntry`.
938
939 friend class ServiceType;
940
941 public:
942 enum State : uint8_t
943 {
944 kProbing = OT_MDNS_ENTRY_STATE_PROBING,
945 kRegistered = OT_MDNS_ENTRY_STATE_REGISTERED,
946 kConflict = OT_MDNS_ENTRY_STATE_CONFLICT,
947 kRemoving = OT_MDNS_ENTRY_STATE_REMOVING,
948 };
949
GetState(void) const950 State GetState(void) const { return mState; }
HasKeyRecord(void) const951 bool HasKeyRecord(void) const { return mKeyRecord.IsPresent(); }
952 void Register(const Key &aKey, const Callback &aCallback);
953 void Unregister(const Key &aKey);
954 void InvokeCallbacks(void);
955 void ClearAppendState(void);
956 Error CopyKeyInfoTo(Key &aKey, EntryState &aState) const;
957
958 protected:
959 static constexpr uint32_t kMinIntervalProbeResponse = 250; // msec
960 static constexpr uint8_t kTypeArraySize = 8; // We can have SRV, TXT and KEY today.
961
962 struct TypeArray : public Array<uint16_t, kTypeArraySize> // Array of record types for NSEC record
963 {
Addot::Dns::Multicast::Core::Entry::TypeArray964 void Add(uint16_t aType) { SuccessOrAssert(PushBack(aType)); }
965 };
966
967 struct RecordAndType
968 {
969 RecordInfo &mRecord;
970 uint16_t mType;
971 };
972
973 typedef void (*NameAppender)(Entry &aEntry, TxMessage &aTxMessage, Section aSection);
974
975 Entry(void);
976 void Init(Instance &aInstance);
977 void SetCallback(const Callback &aCallback);
ClearCallback(void)978 void ClearCallback(void) { mCallback.Clear(); }
979 void MarkToInvokeCallbackUnconditionally(void);
980 void StartProbing(void);
981 void SetStateToConflict(void);
982 void SetStateToRemoving(void);
983 void UpdateRecordsState(const TxMessage &aResponse);
984 void AppendQuestionTo(TxMessage &aTxMessage) const;
985 void AppendKeyRecordTo(TxMessage &aTxMessage, Section aSection, NameAppender aNameAppender);
986 void AppendNsecRecordTo(TxMessage &aTxMessage,
987 Section aSection,
988 const TypeArray &aTypes,
989 NameAppender aNameAppender);
990 bool ShouldAnswerNsec(TimeMilli aNow) const;
991 void DetermineNextFireTime(void);
992 void DetermineNextAggrTxTime(NextFireTime &aNextAggrTxTime) const;
993 void ScheduleTimer(void);
994 void AnswerProbe(const AnswerInfo &aInfo, RecordAndType *aRecords, uint16_t aRecordsLength);
995 void AnswerNonProbe(const AnswerInfo &aInfo, RecordAndType *aRecords, uint16_t aRecordsLength);
996 void ScheduleNsecAnswer(const AnswerInfo &aInfo);
997
998 template <typename EntryType> void HandleTimer(EntryContext &aContext);
999
1000 RecordInfo mKeyRecord;
1001
1002 private:
1003 void SetState(State aState);
1004 void ClearKey(void);
1005 void ScheduleCallbackTask(void);
1006 void CheckMessageSizeLimitToPrepareAgain(TxMessage &aTxMessage, bool &aPrepareAgain);
GetNsecAnswerTime(void) const1007 TimeMilli GetNsecAnswerTime(void) const { return mNsecQueryRxTime + mNsecAnswerDelay; }
1008
1009 State mState;
1010 uint8_t mProbeCount;
1011 bool mMulticastNsecPending : 1;
1012 bool mUnicastNsecPending : 1;
1013 bool mAppendedNsec : 1;
1014 bool mBypassCallbackStateCheck : 1;
1015 uint16_t mNsecAnswerDelay;
1016 TimeMilli mNsecQueryRxTime;
1017 Heap::Data mKeyData;
1018 Callback mCallback;
1019 Callback mKeyCallback;
1020 };
1021
1022 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1023
1024 class HostEntry : public Entry, public LinkedListEntry<HostEntry>, public Heap::Allocatable<HostEntry>
1025 {
1026 friend class LinkedListEntry<HostEntry>;
1027 friend class Entry;
1028 friend class ServiceEntry;
1029
1030 public:
1031 HostEntry(void);
Init(Instance & aInstance,const Host & aHost)1032 Error Init(Instance &aInstance, const Host &aHost) { return Init(aInstance, aHost.mHostName); }
Init(Instance & aInstance,const Key & aKey)1033 Error Init(Instance &aInstance, const Key &aKey) { return Init(aInstance, aKey.mName); }
1034 bool IsEmpty(void) const;
1035 bool Matches(const Name &aName) const;
1036 bool Matches(const Host &aHost) const;
1037 bool Matches(const Key &aKey) const;
1038 bool Matches(const Heap::String &aName) const;
Matches(State aState) const1039 bool Matches(State aState) const { return GetState() == aState; }
Matches(const HostEntry & aEntry) const1040 bool Matches(const HostEntry &aEntry) const { return (this == &aEntry); }
1041 void Register(const Host &aHost, const Callback &aCallback);
1042 void Register(const Key &aKey, const Callback &aCallback);
1043 void Unregister(const Host &aHost);
1044 void Unregister(const Key &aKey);
1045 void AnswerQuestion(const AnswerInfo &aInfo);
1046 void HandleTimer(EntryContext &aContext);
1047 void ClearAppendState(void);
1048 void PrepareResponse(EntryContext &aContext);
1049 void HandleConflict(void);
1050 void DetermineNextAggrTxTime(NextFireTime &aNextAggrTxTime) const;
1051 #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
1052 Error CopyInfoTo(Host &aHost, EntryState &aState) const;
1053 Error CopyInfoTo(Key &aKey, EntryState &aState) const;
1054 #endif
1055
1056 private:
1057 Error Init(Instance &aInstance, const char *aName);
1058 void ClearHost(void);
1059 void ScheduleToRemoveIfEmpty(void);
1060 void PrepareProbe(TxMessage &aProbe);
1061 void StartAnnouncing(void);
1062 void PrepareResponseRecords(EntryContext &aContext);
1063 void UpdateRecordsState(const TxMessage &aResponse);
1064 void DetermineNextFireTime(void);
1065 void AppendAddressRecordsTo(TxMessage &aTxMessage, Section aSection);
1066 void AppendKeyRecordTo(TxMessage &aTxMessage, Section aSection);
1067 void AppendNsecRecordTo(TxMessage &aTxMessage, Section aSection);
1068 void AppendNameTo(TxMessage &aTxMessage, Section aSection);
1069
1070 static void AppendEntryName(Entry &aEntry, TxMessage &aTxMessage, Section aSection);
1071
1072 HostEntry *mNext;
1073 Heap::String mName;
1074 RecordInfo mAddrRecord;
1075 AddressArray mAddresses;
1076 uint16_t mNameOffset;
1077 };
1078
1079 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1080
1081 class ServiceEntry : public Entry, public LinkedListEntry<ServiceEntry>, public Heap::Allocatable<ServiceEntry>
1082 {
1083 friend class LinkedListEntry<ServiceEntry>;
1084 friend class Entry;
1085 friend class ServiceType;
1086
1087 public:
1088 ServiceEntry(void);
1089 Error Init(Instance &aInstance, const Service &aService);
1090 Error Init(Instance &aInstance, const Key &aKey);
1091 bool IsEmpty(void) const;
1092 bool Matches(const Name &aFullName) const;
1093 bool Matches(const Service &aService) const;
1094 bool Matches(const Key &aKey) const;
Matches(State aState) const1095 bool Matches(State aState) const { return GetState() == aState; }
Matches(const ServiceEntry & aEntry) const1096 bool Matches(const ServiceEntry &aEntry) const { return (this == &aEntry); }
1097 bool MatchesServiceType(const Name &aServiceType) const;
1098 bool CanAnswerSubType(const char *aSubLabel) const;
1099 void Register(const Service &aService, const Callback &aCallback);
1100 void Register(const Key &aKey, const Callback &aCallback);
1101 void Unregister(const Service &aService);
1102 void Unregister(const Key &aKey);
1103 void AnswerServiceNameQuestion(const AnswerInfo &aInfo);
1104 void AnswerServiceTypeQuestion(const AnswerInfo &aInfo, const char *aSubLabel);
1105 bool ShouldSuppressKnownAnswer(uint32_t aTtl, const char *aSubLabel) const;
1106 void HandleTimer(EntryContext &aContext);
1107 void ClearAppendState(void);
1108 void PrepareResponse(EntryContext &aContext);
1109 void HandleConflict(void);
1110 void DetermineNextAggrTxTime(NextFireTime &aNextAggrTxTime) const;
1111 #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
1112 Error CopyInfoTo(Service &aService, EntryState &aState, EntryIterator &aIterator) const;
1113 Error CopyInfoTo(Key &aKey, EntryState &aState) const;
1114 #endif
1115
1116 private:
1117 class SubType : public LinkedListEntry<SubType>, public Heap::Allocatable<SubType>, private ot::NonCopyable
1118 {
1119 public:
1120 Error Init(const char *aLabel);
Matches(const char * aLabel) const1121 bool Matches(const char *aLabel) const { return NameMatch(mLabel, aLabel); }
1122 bool Matches(const EmptyChecker &aChecker) const;
1123 bool IsContainedIn(const Service &aService) const;
1124
1125 SubType *mNext;
1126 Heap::String mLabel;
1127 RecordInfo mPtrRecord;
1128 uint16_t mSubServiceNameOffset;
1129 };
1130
1131 Error Init(Instance &aInstance, const char *aServiceInstance, const char *aServiceType);
1132 void ClearService(void);
1133 void ScheduleToRemoveIfEmpty(void);
1134 void PrepareProbe(TxMessage &aProbe);
1135 void StartAnnouncing(void);
1136 void PrepareResponseRecords(EntryContext &aContext);
1137 void UpdateRecordsState(const TxMessage &aResponse);
1138 void DetermineNextFireTime(void);
1139 void DiscoverOffsetsAndHost(HostEntry *&aHost);
1140 void UpdateServiceTypes(void);
1141 void AppendSrvRecordTo(TxMessage &aTxMessage, Section aSection);
1142 void AppendTxtRecordTo(TxMessage &aTxMessage, Section aSection);
1143 void AppendPtrRecordTo(TxMessage &aTxMessage, Section aSection, SubType *aSubType = nullptr);
1144 void AppendKeyRecordTo(TxMessage &aTxMessage, Section aSection);
1145 void AppendNsecRecordTo(TxMessage &aTxMessage, Section aSection);
1146 void AppendServiceNameTo(TxMessage &TxMessage, Section aSection, bool aPerformNameCompression = true);
1147 void AppendServiceTypeTo(TxMessage &aTxMessage, Section aSection);
1148 void AppendSubServiceTypeTo(TxMessage &aTxMessage, Section aSection);
1149 void AppendSubServiceNameTo(TxMessage &aTxMessage, Section aSection, SubType &aSubType);
1150 void AppendHostNameTo(TxMessage &aTxMessage, Section aSection);
1151
1152 static void AppendEntryName(Entry &aEntry, TxMessage &aTxMessage, Section aSection);
1153
1154 static const uint8_t kEmptyTxtData[];
1155
1156 ServiceEntry *mNext;
1157 Heap::String mServiceInstance;
1158 Heap::String mServiceType;
1159 RecordInfo mPtrRecord;
1160 RecordInfo mSrvRecord;
1161 RecordInfo mTxtRecord;
1162 OwningList<SubType> mSubTypes;
1163 Heap::String mHostName;
1164 Heap::Data mTxtData;
1165 uint16_t mPriority;
1166 uint16_t mWeight;
1167 uint16_t mPort;
1168 uint16_t mServiceNameOffset;
1169 uint16_t mServiceTypeOffset;
1170 uint16_t mSubServiceTypeOffset;
1171 uint16_t mHostNameOffset;
1172 bool mIsAddedInServiceTypes;
1173 };
1174
1175 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1176
1177 class ServiceType : public InstanceLocatorInit,
1178 public FireTime,
1179 public LinkedListEntry<ServiceType>,
1180 public Heap::Allocatable<ServiceType>,
1181 private NonCopyable
1182 {
1183 // Track a service type to answer to `_services._dns-sd._udp.local`
1184 // queries.
1185
1186 friend class LinkedListEntry<ServiceType>;
1187
1188 public:
1189 Error Init(Instance &aInstance, const char *aServiceType);
1190 bool Matches(const Name &aServiceTypeName) const;
1191 bool Matches(const Heap::String &aServiceType) const;
Matches(const ServiceType & aServiceType) const1192 bool Matches(const ServiceType &aServiceType) const { return (this == &aServiceType); }
IncrementNumEntries(void)1193 void IncrementNumEntries(void) { mNumEntries++; }
DecrementNumEntries(void)1194 void DecrementNumEntries(void) { mNumEntries--; }
GetNumEntries(void) const1195 uint16_t GetNumEntries(void) const { return mNumEntries; }
1196 void ClearAppendState(void);
1197 void AnswerQuestion(const AnswerInfo &aInfo);
1198 bool ShouldSuppressKnownAnswer(uint32_t aTtl) const;
1199 void HandleTimer(EntryContext &aContext);
1200 void PrepareResponse(EntryContext &aContext);
1201 void DetermineNextAggrTxTime(NextFireTime &aNextAggrTxTime) const;
1202
1203 private:
1204 void PrepareResponseRecords(EntryContext &aContext);
1205 void AppendPtrRecordTo(TxMessage &aResponse, uint16_t aServiceTypeOffset);
1206
1207 ServiceType *mNext;
1208 Heap::String mServiceType;
1209 RecordInfo mServicesPtr;
1210 uint16_t mNumEntries; // Number of service entries providing this service type.
1211 };
1212
1213 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1214
1215 class TxMessage : public InstanceLocator, private NonCopyable
1216 {
1217 public:
1218 enum Type : uint8_t
1219 {
1220 kMulticastProbe,
1221 kMulticastQuery,
1222 kMulticastResponse,
1223 kUnicastResponse,
1224 kLegacyUnicastResponse,
1225 };
1226
1227 TxMessage(Instance &aInstance, Type aType, uint16_t aQueryId = 0);
1228 TxMessage(Instance &aInstance, Type aType, const AddressInfo &aUnicastDest, uint16_t aQueryId);
GetType(void) const1229 Type GetType(void) const { return mType; }
1230 Message &SelectMessageFor(Section aSection);
1231 AppendOutcome AppendLabel(Section aSection, const char *aLabel, uint16_t &aCompressOffset);
1232 AppendOutcome AppendMultipleLabels(Section aSection, const char *aLabels, uint16_t &aCompressOffset);
1233 void AppendServiceType(Section aSection, const char *aServiceType, uint16_t &aCompressOffset);
1234 void AppendDomainName(Section aSection);
1235 void AppendServicesDnssdName(Section aSection);
1236 void AddQuestionFrom(const Message &aMessage);
IncrementRecordCount(Section aSection)1237 void IncrementRecordCount(Section aSection) { mRecordCounts.Increment(aSection); }
1238 void CheckSizeLimitToPrepareAgain(bool &aPrepareAgain);
1239 void SaveCurrentState(void);
1240 void RestoreToSavedState(void);
1241 void Send(void);
1242
1243 private:
1244 static constexpr bool kIsSingleLabel = true;
1245
1246 void Init(Type aType, uint16_t aMessageId = 0);
1247 void Reinit(void);
1248 bool IsOverSizeLimit(void) const;
1249 AppendOutcome AppendLabels(Section aSection,
1250 const char *aLabels,
1251 bool aIsSingleLabel,
1252 uint16_t &aCompressOffset);
1253 bool ShouldClearAppendStateOnReinit(const Entry &aEntry) const;
1254
1255 static void SaveOffset(uint16_t &aCompressOffset, const Message &aMessage, Section aSection);
1256
1257 RecordCounts mRecordCounts;
1258 OwnedPtr<Message> mMsgPtr;
1259 OwnedPtr<Message> mExtraMsgPtr;
1260 RecordCounts mSavedRecordCounts;
1261 uint16_t mSavedMsgLength;
1262 uint16_t mSavedExtraMsgLength;
1263 uint16_t mDomainOffset; // Offset for domain name `.local.` for name compression.
1264 uint16_t mUdpOffset; // Offset to `_udp.local.`
1265 uint16_t mTcpOffset; // Offset to `_tcp.local.`
1266 uint16_t mServicesDnssdOffset; // Offset to `_services._dns-sd`
1267 AddressInfo mUnicastDest;
1268 Type mType;
1269 };
1270
1271 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1272
1273 struct EntryContext : private NonCopyable // Used when preparing entry response (e.g. from `HandleEntryTimer()`).
1274 {
1275 EntryContext(Instance &aInstance, TxMessage::Type aResponseType);
1276 EntryContext(Instance &aInstance, TxMessage::Type aResponseType, const AddressInfo &aDest, uint16_t aQueryId);
1277
GetNowot::Dns::Multicast::Core::EntryContext1278 TimeMilli GetNow(void) const { return mNextFireTime.GetNow(); }
1279
1280 NextFireTime mNextFireTime;
1281 TxMessage mProbeMessage;
1282 TxMessage mResponseMessage;
1283 TimeMilli mNextAggrTxTime;
1284 };
1285
1286 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1287
1288 class RxMessage : public InstanceLocatorInit,
1289 public Heap::Allocatable<RxMessage>,
1290 public LinkedListEntry<RxMessage>,
1291 private NonCopyable
1292 {
1293 friend class LinkedListEntry<RxMessage>;
1294
1295 public:
1296 enum ProcessOutcome : uint8_t
1297 {
1298 kProcessed,
1299 kSaveAsMultiPacket,
1300 };
1301
1302 Error Init(Instance &aInstance,
1303 OwnedPtr<Message> &aMessagePtr,
1304 bool aIsUnicast,
1305 const AddressInfo &aSenderAddress);
IsQuery(void) const1306 bool IsQuery(void) const { return mIsQuery; }
IsTruncated(void) const1307 bool IsTruncated(void) const { return mTruncated; }
IsSelfOriginating(void) const1308 bool IsSelfOriginating(void) const { return mIsSelfOriginating; }
GetRecordCounts(void) const1309 const RecordCounts &GetRecordCounts(void) const { return mRecordCounts; }
GetSenderAddress(void) const1310 const AddressInfo &GetSenderAddress(void) const { return mSenderAddress; }
1311 void ClearProcessState(void);
1312 ProcessOutcome ProcessQuery(bool aShouldProcessTruncated);
1313 void ProcessResponse(void);
1314
1315 private:
1316 typedef void (RxMessage::*RecordProcessor)(const Name &aName,
1317 const ResourceRecord &aRecord,
1318 uint16_t aRecordOffset);
1319
1320 struct Question : public Clearable<Question>
1321 {
Questionot::Dns::Multicast::Core::RxMessage::Question1322 Question(void) { Clear(); }
1323 void ClearProcessState(void);
1324
1325 Entry *mEntry; // Entry which can provide answer (if any).
1326 uint16_t mNameOffset; // Offset to start of question name.
1327 uint16_t mRrType; // The question record type.
1328 bool mIsRrClassInternet : 1; // Is the record class Internet or Any.
1329 bool mIsProbe : 1; // Is a probe (contains a matching record in Authority section).
1330 bool mUnicastResponse : 1; // Is QU flag set (requesting a unicast response).
1331 bool mCanAnswer : 1; // Can provide answer for this question
1332 bool mIsUnique : 1; // Is unique record (vs a shared record).
1333 bool mIsForService : 1; // Is for a `ServiceEntry` (vs a `HostEntry`).
1334 bool mIsServiceType : 1; // Is for service type or sub-type of a `ServiceEntry`.
1335 bool mIsForAllServicesDnssd : 1; // Is for "_services._dns-sd._udp" (all service types).
1336 };
1337
1338 void ProcessQuestion(Question &aQuestion);
1339 void AnswerQuestion(const Question &aQuestion, uint16_t aDelay);
1340 void AnswerServiceTypeQuestion(const Question &aQuestion, const AnswerInfo &aInfo, ServiceEntry &aFirstEntry);
1341 bool ShouldSuppressKnownAnswer(const Name &aServiceType,
1342 const char *aSubLabel,
1343 const ServiceEntry &aServiceEntry) const;
1344 bool ParseQuestionNameAsSubType(const Question &aQuestion,
1345 Name::LabelBuffer &aSubLabel,
1346 Name &aServiceType) const;
1347 void AnswerAllServicesQuestion(const Question &aQuestion, const AnswerInfo &aInfo);
1348 bool ShouldSuppressKnownAnswer(const Question &aQuestion, const ServiceType &aServiceType) const;
1349 void SendUnicastResponse(void);
1350 void IterateOnAllRecordsInResponse(RecordProcessor aRecordProcessor);
1351 void ProcessRecordForConflict(const Name &aName, const ResourceRecord &aRecord, uint16_t aRecordOffset);
1352 void ProcessPtrRecord(const Name &aName, const ResourceRecord &aRecord, uint16_t aRecordOffset);
1353 void ProcessSrvRecord(const Name &aName, const ResourceRecord &aRecord, uint16_t aRecordOffset);
1354 void ProcessTxtRecord(const Name &aName, const ResourceRecord &aRecord, uint16_t aRecordOffset);
1355 void ProcessAaaaRecord(const Name &aName, const ResourceRecord &aRecord, uint16_t aRecordOffset);
1356 void ProcessARecord(const Name &aName, const ResourceRecord &aRecord, uint16_t aRecordOffset);
1357
1358 RxMessage *mNext;
1359 TimeMilli mRxTime;
1360 OwnedPtr<Message> mMessagePtr;
1361 Heap::Array<Question> mQuestions;
1362 AddressInfo mSenderAddress;
1363 RecordCounts mRecordCounts;
1364 uint16_t mStartOffset[kNumSections];
1365 uint16_t mQueryId;
1366 bool mIsQuery : 1;
1367 bool mIsUnicast : 1;
1368 bool mIsLegacyUnicast : 1;
1369 bool mTruncated : 1;
1370 bool mIsSelfOriginating : 1;
1371 };
1372
1373 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1374
HandleMultiPacketTimer(void)1375 void HandleMultiPacketTimer(void) { mMultiPacketRxMessages.HandleTimer(); }
1376
1377 class MultiPacketRxMessages : public InstanceLocator
1378 {
1379 public:
1380 explicit MultiPacketRxMessages(Instance &aInstance);
1381
1382 void AddToExisting(OwnedPtr<RxMessage> &aRxMessagePtr);
1383 void AddNew(OwnedPtr<RxMessage> &aRxMessagePtr);
1384 void HandleTimer(void);
1385 void Clear(void);
1386
1387 private:
1388 static constexpr uint32_t kMinProcessDelay = 400; // msec
1389 static constexpr uint32_t kMaxProcessDelay = 500; // msec
1390 static constexpr uint16_t kMaxNumMessages = 10;
1391
1392 struct RxMsgEntry : public InstanceLocator,
1393 public LinkedListEntry<RxMsgEntry>,
1394 public Heap::Allocatable<RxMsgEntry>,
1395 private NonCopyable
1396 {
1397 explicit RxMsgEntry(Instance &aInstance);
1398
1399 bool Matches(const AddressInfo &aAddress) const;
1400 bool Matches(const ExpireChecker &aExpireChecker) const;
1401 void Add(OwnedPtr<RxMessage> &aRxMessagePtr);
1402
1403 OwningList<RxMessage> mRxMessages;
1404 TimeMilli mProcessTime;
1405 RxMsgEntry *mNext;
1406 };
1407
1408 using MultiPacketTimer = TimerMilliIn<Core, &Core::HandleMultiPacketTimer>;
1409
1410 OwningList<RxMsgEntry> mRxMsgEntries;
1411 MultiPacketTimer mTimer;
1412 };
1413
1414 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1415
HandleTxMessageHistoryTimer(void)1416 void HandleTxMessageHistoryTimer(void) { mTxMessageHistory.HandleTimer(); }
1417
1418 class TxMessageHistory : public InstanceLocator
1419 {
1420 // Keep track of messages sent by mDNS module to tell if
1421 // a received message is self originating.
1422
1423 public:
1424 explicit TxMessageHistory(Instance &aInstance);
1425 void Clear(void);
1426 void Add(const Message &aMessage);
1427 bool Contains(const Message &aMessage) const;
1428 void HandleTimer(void);
1429
1430 private:
1431 static constexpr uint32_t kExpireInterval = TimeMilli::SecToMsec(10); // in msec
1432
1433 struct MsgInfo : public Clearable<MsgInfo>, public Equatable<MsgInfo>
1434 {
1435 void InitFrom(const Message &aMessage);
1436
1437 uint16_t mMsgLength;
1438 uint16_t mCrc16;
1439 uint32_t mCrc32;
1440 };
1441
1442 struct MsgEntry : public LinkedListEntry<MsgEntry>, public Heap::Allocatable<MsgEntry>
1443 {
Matchesot::Dns::Multicast::Core::TxMessageHistory::MsgEntry1444 bool Matches(const MsgInfo &aInfo) const { return mInfo == aInfo; }
Matchesot::Dns::Multicast::Core::TxMessageHistory::MsgEntry1445 bool Matches(const ExpireChecker &aExpireChecker) const { return mExpireTime <= aExpireChecker.mNow; }
1446
1447 MsgEntry *mNext;
1448 MsgInfo mInfo;
1449 TimeMilli mExpireTime;
1450 };
1451
1452 using TxMsgHistoryTimer = TimerMilliIn<Core, &Core::HandleTxMessageHistoryTimer>;
1453
1454 OwningList<MsgEntry> mMsgEntries;
1455 TxMsgHistoryTimer mTimer;
1456 };
1457
1458 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1459
1460 class CacheEntry;
1461 class TxtCache;
1462
1463 class ResultCallback : public LinkedListEntry<ResultCallback>, public Heap::Allocatable<ResultCallback>
1464 {
1465 friend class Heap::Allocatable<ResultCallback>;
1466 friend class LinkedListEntry<ResultCallback>;
1467 friend class CacheEntry;
1468
1469 public:
1470 ResultCallback(const ResultCallback &aResultCallback) = default;
1471
1472 template <typename CallbackType>
ResultCallback(CallbackType aCallback)1473 explicit ResultCallback(CallbackType aCallback)
1474 : mNext(nullptr)
1475 , mSharedCallback(aCallback)
1476 {
1477 }
1478
Matches(BrowseCallback aCallback) const1479 bool Matches(BrowseCallback aCallback) const { return mSharedCallback.mBrowse == aCallback; }
Matches(SrvCallback aCallback) const1480 bool Matches(SrvCallback aCallback) const { return mSharedCallback.mSrv == aCallback; }
Matches(TxtCallback aCallback) const1481 bool Matches(TxtCallback aCallback) const { return mSharedCallback.mTxt == aCallback; }
Matches(AddressCallback aCallback) const1482 bool Matches(AddressCallback aCallback) const { return mSharedCallback.mAddress == aCallback; }
Matches(EmptyChecker) const1483 bool Matches(EmptyChecker) const { return (mSharedCallback.mSrv == nullptr); }
1484
1485 void Invoke(Instance &aInstance, const BrowseResult &aResult) const;
1486 void Invoke(Instance &aInstance, const SrvResult &aResult) const;
1487 void Invoke(Instance &aInstance, const TxtResult &aResult) const;
1488 void Invoke(Instance &aInstance, const AddressResult &aResult) const;
1489
ClearCallback(void)1490 void ClearCallback(void) { mSharedCallback.Clear(); }
1491
1492 private:
1493 union SharedCallback
1494 {
SharedCallback(BrowseCallback aCallback)1495 explicit SharedCallback(BrowseCallback aCallback) { mBrowse = aCallback; }
SharedCallback(SrvCallback aCallback)1496 explicit SharedCallback(SrvCallback aCallback) { mSrv = aCallback; }
SharedCallback(TxtCallback aCallback)1497 explicit SharedCallback(TxtCallback aCallback) { mTxt = aCallback; }
SharedCallback(AddressCallback aCallback)1498 explicit SharedCallback(AddressCallback aCallback) { mAddress = aCallback; }
1499
Clear(void)1500 void Clear(void) { mBrowse = nullptr; }
1501
1502 BrowseCallback mBrowse;
1503 SrvCallback mSrv;
1504 TxtCallback mTxt;
1505 AddressCallback mAddress;
1506 };
1507
1508 ResultCallback *mNext;
1509 SharedCallback mSharedCallback;
1510 };
1511
1512 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1513
1514 struct CacheContext : private NonCopyable
1515 {
1516 CacheContext(Instance &aInstance);
GetNowot::Dns::Multicast::Core::CacheContext1517 TimeMilli GetNow(void) const { return mNextFireTime.GetNow(); }
1518
1519 NextFireTime mNextFireTime;
1520 TxMessage mQueryMessage;
1521 };
1522
1523 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1524
1525 class CacheRecordInfo
1526 {
1527 public:
1528 CacheRecordInfo(void);
1529
IsPresent(void) const1530 bool IsPresent(void) const { return (mTtl > 0); }
GetTtl(void) const1531 uint32_t GetTtl(void) const { return mTtl; }
1532 bool RefreshTtl(uint32_t aTtl);
1533 bool ShouldExpire(TimeMilli aNow) const;
1534 void UpdateStateAfterQuery(TimeMilli aNow);
1535 void UpdateQueryAndFireTimeOn(CacheEntry &aCacheEntry);
1536 bool LessThanHalfTtlRemains(TimeMilli aNow) const;
1537 uint32_t GetRemainingTtl(TimeMilli aNow) const;
1538
1539 private:
1540 static constexpr uint32_t kMaxTtl = (24 * 3600); // One day
1541 static constexpr uint8_t kNumberOfQueries = 4;
1542 static constexpr uint32_t kQueryTtlVariation = 1000 * 2 / 100; // 2%
1543
1544 uint32_t GetClampedTtl(void) const;
1545 TimeMilli GetExpireTime(void) const;
1546 TimeMilli GetQueryTime(uint8_t aAttemptIndex) const;
1547
1548 uint32_t mTtl;
1549 TimeMilli mLastRxTime;
1550 uint8_t mQueryCount;
1551 };
1552
1553 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1554
1555 class CacheEntry : public FireTime, public InstanceLocatorInit, private NonCopyable
1556 {
1557 // Base class for cache entries: `BrowseCache`, `mSrvCache`,
1558 // `mTxtCache`, etc. Implements common behaviors: initial
1559 // queries, query/timer scheduling, callback tracking, entry
1560 // aging, and timer handling. Tracks entry type in `mType` and
1561 // invokes sub-class method for type-specific behaviors
1562 // (e.g., query message construction).
1563
1564 public:
1565 void HandleTimer(CacheContext &aContext);
1566 void ClearEmptyCallbacks(void);
1567 void ScheduleQuery(TimeMilli aQueryTime);
1568
1569 protected:
1570 enum Type : uint8_t
1571 {
1572 kBrowseCache,
1573 kSrvCache,
1574 kTxtCache,
1575 kIp6AddrCache,
1576 kIp4AddrCache,
1577 };
1578
1579 void Init(Instance &aInstance, Type aType);
IsActive(void) const1580 bool IsActive(void) const { return mIsActive; }
1581 bool ShouldDelete(TimeMilli aNow) const;
1582 void StartInitialQueries(void);
StopInitialQueries(void)1583 void StopInitialQueries(void) { mInitalQueries = kNumberOfInitalQueries; }
1584 Error Add(const ResultCallback &aCallback);
1585 void Remove(const ResultCallback &aCallback);
1586 void DetermineNextFireTime(void);
1587 void ScheduleTimer(void);
1588
1589 template <typename ResultType> void InvokeCallbacks(const ResultType &aResult);
1590
1591 private:
1592 static constexpr uint32_t kMinIntervalBetweenQueries = 1000; // In msec
1593 static constexpr uint32_t kNonActiveDeleteTimeout = 7 * Time::kOneMinuteInMsec;
1594
1595 typedef OwningList<ResultCallback> CallbackList;
1596
1597 void SetIsActive(bool aIsActive);
1598 bool ShouldQuery(TimeMilli aNow);
1599 void PrepareQuery(CacheContext &aContext);
1600 void ProcessExpiredRecords(TimeMilli aNow);
1601 void DetermineNextInitialQueryTime(void);
1602
1603 ResultCallback *FindCallbackMatching(const ResultCallback &aCallback);
1604
As(void)1605 template <typename CacheType> CacheType &As(void) { return *static_cast<CacheType *>(this); }
As(void) const1606 template <typename CacheType> const CacheType &As(void) const { return *static_cast<const CacheType *>(this); }
1607
1608 Type mType; // Cache entry type.
1609 uint8_t mInitalQueries; // Number initial queries sent already.
1610 bool mQueryPending : 1; // Whether a query tx request is pending.
1611 bool mLastQueryTimeValid : 1; // Whether `mLastQueryTime` is valid.
1612 bool mIsActive : 1; // Whether there is any active resolver/browser for this entry.
1613 TimeMilli mNextQueryTime; // The next query tx time when `mQueryPending`.
1614 TimeMilli mLastQueryTime; // The last query tx time or the upcoming tx time of first initial query.
1615 TimeMilli mDeleteTime; // The time to delete the entry when not `mIsActive`.
1616 CallbackList mCallbacks; // Resolver/Browser callbacks.
1617 };
1618
1619 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1620
1621 class BrowseCache : public CacheEntry, public LinkedListEntry<BrowseCache>, public Heap::Allocatable<BrowseCache>
1622 {
1623 friend class LinkedListEntry<BrowseCache>;
1624 friend class Heap::Allocatable<BrowseCache>;
1625 friend class CacheEntry;
1626
1627 public:
1628 void ClearCompressOffsets(void);
1629 bool Matches(const Name &aFullName) const;
1630 bool Matches(const char *aServiceType, const char *aSubTypeLabel) const;
1631 bool Matches(const Browser &aBrowser) const;
1632 bool Matches(const ExpireChecker &aExpireChecker) const;
1633 Error Add(const Browser &aBrowser);
1634 void Remove(const Browser &aBrowser);
1635 void ProcessResponseRecord(const Message &aMessage, uint16_t aRecordOffset);
1636 #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
1637 void CopyInfoTo(Browser &aBrowser, CacheInfo &aInfo) const;
1638 #endif
1639
1640 private:
1641 struct PtrEntry : public LinkedListEntry<PtrEntry>, public Heap::Allocatable<PtrEntry>
1642 {
1643 Error Init(const char *aServiceInstance);
Matchesot::Dns::Multicast::Core::BrowseCache::PtrEntry1644 bool Matches(const char *aServiceInstance) const { return NameMatch(mServiceInstance, aServiceInstance); }
1645 bool Matches(const ExpireChecker &aExpireChecker) const;
1646 void ConvertTo(BrowseResult &aResult, const BrowseCache &aBrowseCache) const;
1647
1648 PtrEntry *mNext;
1649 Heap::String mServiceInstance;
1650 CacheRecordInfo mRecord;
1651 };
1652
1653 // Called by base class `CacheEntry`
1654 void PreparePtrQuestion(TxMessage &aQuery, TimeMilli aNow);
1655 void UpdateRecordStateAfterQuery(TimeMilli aNow);
1656 void DetermineRecordFireTime(void);
1657 void ProcessExpiredRecords(TimeMilli aNow);
1658 void ReportResultsTo(ResultCallback &aCallback) const;
1659
1660 Error Init(Instance &aInstance, const char *aServiceType, const char *aSubTypeLabel);
1661 Error Init(Instance &aInstance, const Browser &aBrowser);
1662 void AppendServiceTypeOrSubTypeTo(TxMessage &aTxMessage, Section aSection);
1663 void AppendKnownAnswer(TxMessage &aTxMessage, const PtrEntry &aPtrEntry, TimeMilli aNow);
1664 void DiscoverCompressOffsets(void);
1665
1666 BrowseCache *mNext;
1667 Heap::String mServiceType;
1668 Heap::String mSubTypeLabel;
1669 OwningList<PtrEntry> mPtrEntries;
1670 uint16_t mServiceTypeOffset;
1671 uint16_t mSubServiceTypeOffset;
1672 uint16_t mSubServiceNameOffset;
1673 };
1674
1675 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1676
1677 struct ServiceName
1678 {
ServiceNameot::Dns::Multicast::Core::ServiceName1679 ServiceName(const char *aServiceInstance, const char *aServiceType)
1680 : mServiceInstance(aServiceInstance)
1681 , mServiceType(aServiceType)
1682 {
1683 }
1684
1685 const char *mServiceInstance;
1686 const char *mServiceType;
1687 };
1688
1689 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1690
1691 class ServiceCache : public CacheEntry
1692 {
1693 // Base class for `SrvCache` and `TxtCache`, tracking common info
1694 // shared between the two, e.g. service instance/type strings,
1695 // record info, and append state and compression offsets.
1696
1697 friend class CacheEntry;
1698
1699 public:
1700 void ClearCompressOffsets(void);
1701
1702 protected:
1703 ServiceCache(void) = default;
1704
1705 Error Init(Instance &aInstance, Type aType, const char *aServiceInstance, const char *aServiceType);
1706 bool Matches(const Name &aFullName) const;
1707 bool Matches(const char *aServiceInstance, const char *aServiceType) const;
1708 void PrepareQueryQuestion(TxMessage &aQuery, uint16_t aRrType);
1709 void AppendServiceNameTo(TxMessage &aTxMessage, Section aSection);
1710 void UpdateRecordStateAfterQuery(TimeMilli aNow);
1711 void DetermineRecordFireTime(void);
1712 bool ShouldStartInitialQueries(void) const;
1713
1714 CacheRecordInfo mRecord;
1715 Heap::String mServiceInstance;
1716 Heap::String mServiceType;
1717 uint16_t mServiceNameOffset;
1718 uint16_t mServiceTypeOffset;
1719 };
1720
1721 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1722
1723 class SrvCache : public ServiceCache, public LinkedListEntry<SrvCache>, public Heap::Allocatable<SrvCache>
1724 {
1725 friend class LinkedListEntry<SrvCache>;
1726 friend class Heap::Allocatable<SrvCache>;
1727 friend class CacheEntry;
1728 friend class TxtCache;
1729 friend class BrowseCache;
1730
1731 public:
1732 bool Matches(const Name &aFullName) const;
1733 bool Matches(const SrvResolver &aResolver) const;
1734 bool Matches(const ServiceName &aServiceName) const;
1735 bool Matches(const ExpireChecker &aExpireChecker) const;
1736 Error Add(const SrvResolver &aResolver);
1737 void Remove(const SrvResolver &aResolver);
1738 void ProcessResponseRecord(const Message &aMessage, uint16_t aRecordOffset);
1739 #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
1740 void CopyInfoTo(SrvResolver &aResolver, CacheInfo &aInfo) const;
1741 #endif
1742
1743 private:
1744 Error Init(Instance &aInstance, const char *aServiceInstance, const char *aServiceType);
1745 Error Init(Instance &aInstance, const ServiceName &aServiceName);
1746 Error Init(Instance &aInstance, const SrvResolver &aResolver);
1747 void PrepareSrvQuestion(TxMessage &aQuery);
1748 void DiscoverCompressOffsets(void);
1749 void ProcessExpiredRecords(TimeMilli aNow);
1750 void ReportResultTo(ResultCallback &aCallback) const;
1751 void ConvertTo(SrvResult &aResult) const;
1752
1753 SrvCache *mNext;
1754 Heap::String mHostName;
1755 uint16_t mPort;
1756 uint16_t mPriority;
1757 uint16_t mWeight;
1758 };
1759
1760 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1761
1762 class TxtCache : public ServiceCache, public LinkedListEntry<TxtCache>, public Heap::Allocatable<TxtCache>
1763 {
1764 friend class LinkedListEntry<TxtCache>;
1765 friend class Heap::Allocatable<TxtCache>;
1766 friend class CacheEntry;
1767 friend class BrowseCache;
1768
1769 public:
1770 bool Matches(const Name &aFullName) const;
1771 bool Matches(const TxtResolver &aResolver) const;
1772 bool Matches(const ServiceName &aServiceName) const;
1773 bool Matches(const ExpireChecker &aExpireChecker) const;
1774 Error Add(const TxtResolver &aResolver);
1775 void Remove(const TxtResolver &aResolver);
1776 void ProcessResponseRecord(const Message &aMessage, uint16_t aRecordOffset);
1777 #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
1778 void CopyInfoTo(TxtResolver &aResolver, CacheInfo &aInfo) const;
1779 #endif
1780
1781 private:
1782 Error Init(Instance &aInstance, const char *aServiceInstance, const char *aServiceType);
1783 Error Init(Instance &aInstance, const ServiceName &aServiceName);
1784 Error Init(Instance &aInstance, const TxtResolver &aResolver);
1785 void PrepareTxtQuestion(TxMessage &aQuery);
1786 void DiscoverCompressOffsets(void);
1787 void ProcessExpiredRecords(TimeMilli aNow);
1788 void ReportResultTo(ResultCallback &aCallback) const;
1789 void ConvertTo(TxtResult &aResult) const;
1790
1791 TxtCache *mNext;
1792 Heap::Data mTxtData;
1793 };
1794
1795 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1796
1797 class AddrCache : public CacheEntry
1798 {
1799 // Base class for `Ip6AddrCache` and `Ip4AddrCache`, tracking common info
1800 // shared between the two.
1801
1802 friend class CacheEntry;
1803
1804 public:
1805 bool Matches(const Name &aFullName) const;
1806 bool Matches(const char *aName) const;
1807 bool Matches(const AddressResolver &aResolver) const;
1808 bool Matches(const ExpireChecker &aExpireChecker) const;
1809 Error Add(const AddressResolver &aResolver);
1810 void Remove(const AddressResolver &aResolver);
1811 void CommitNewResponseEntries(void);
1812 #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
1813 void CopyInfoTo(AddressResolver &aResolver, CacheInfo &aInfo) const;
1814 #endif
1815
1816 protected:
1817 struct AddrEntry : public LinkedListEntry<AddrEntry>, public Heap::Allocatable<AddrEntry>
1818 {
1819 explicit AddrEntry(const Ip6::Address &aAddress);
Matchesot::Dns::Multicast::Core::AddrCache::AddrEntry1820 bool Matches(const Ip6::Address &aAddress) const { return (mAddress == aAddress); }
1821 bool Matches(const ExpireChecker &aExpireChecker) const;
1822 bool Matches(EmptyChecker aChecker) const;
GetTtlot::Dns::Multicast::Core::AddrCache::AddrEntry1823 uint32_t GetTtl(void) const { return mRecord.GetTtl(); }
1824
1825 AddrEntry *mNext;
1826 Ip6::Address mAddress;
1827 CacheRecordInfo mRecord;
1828 };
1829
1830 // Called by base class `CacheEntry`
1831 void PrepareQueryQuestion(TxMessage &aQuery, uint16_t aRrType);
1832 void UpdateRecordStateAfterQuery(TimeMilli aNow);
1833 void DetermineRecordFireTime(void);
1834 void ProcessExpiredRecords(TimeMilli aNow);
1835 void ReportResultsTo(ResultCallback &aCallback) const;
1836 bool ShouldStartInitialQueries(void) const;
1837
1838 Error Init(Instance &aInstance, Type aType, const char *aHostName);
1839 Error Init(Instance &aInstance, Type aType, const AddressResolver &aResolver);
1840 void AppendNameTo(TxMessage &aTxMessage, Section aSection);
1841 void ConstructResult(AddressResult &aResult, Heap::Array<AddressAndTtl> &aAddrArray) const;
1842 void AddNewResponseAddress(const Ip6::Address &aAddress, uint32_t aTtl, bool aCacheFlush);
1843
1844 AddrCache *mNext;
1845 Heap::String mName;
1846 OwningList<AddrEntry> mCommittedEntries;
1847 OwningList<AddrEntry> mNewEntries;
1848 bool mShouldFlush;
1849 };
1850
1851 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1852
1853 class Ip6AddrCache : public AddrCache, public LinkedListEntry<Ip6AddrCache>, public Heap::Allocatable<Ip6AddrCache>
1854 {
1855 friend class CacheEntry;
1856 friend class LinkedListEntry<Ip6AddrCache>;
1857 friend class Heap::Allocatable<Ip6AddrCache>;
1858
1859 public:
1860 void ProcessResponseRecord(const Message &aMessage, uint16_t aRecordOffset);
1861
1862 private:
1863 Error Init(Instance &aInstance, const char *aHostName);
1864 Error Init(Instance &aInstance, const AddressResolver &aResolver);
1865 void PrepareAaaaQuestion(TxMessage &aQuery);
1866 };
1867
1868 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1869
1870 class Ip4AddrCache : public AddrCache, public LinkedListEntry<Ip4AddrCache>, public Heap::Allocatable<Ip4AddrCache>
1871 {
1872 friend class CacheEntry;
1873 friend class LinkedListEntry<Ip4AddrCache>;
1874 friend class Heap::Allocatable<Ip4AddrCache>;
1875
1876 public:
1877 void ProcessResponseRecord(const Message &aMessage, uint16_t aRecordOffset);
1878
1879 private:
1880 Error Init(Instance &aInstance, const char *aHostName);
1881 Error Init(Instance &aInstance, const AddressResolver &aResolver);
1882 void PrepareAQuestion(TxMessage &aQuery);
1883 };
1884
1885 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1886
1887 #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
1888
1889 class EntryIterator : public Iterator, public InstanceLocator, public Heap::Allocatable<EntryIterator>
1890 {
1891 friend class Heap::Allocatable<EntryIterator>;
1892 friend class ServiceEntry;
1893
1894 public:
1895 Error GetNextHost(Host &aHost, EntryState &aState);
1896 Error GetNextService(Service &aService, EntryState &aState);
1897 Error GetNextKey(Key &aKey, EntryState &aState);
1898 Error GetNextBrowser(Browser &aBrowser, CacheInfo &aInfo);
1899 Error GetNextSrvResolver(SrvResolver &aResolver, CacheInfo &aInfo);
1900 Error GetNextTxtResolver(TxtResolver &aResolver, CacheInfo &aInfo);
1901 Error GetNextIp6AddressResolver(AddressResolver &aResolver, CacheInfo &aInfo);
1902 Error GetNextIp4AddressResolver(AddressResolver &aResolver, CacheInfo &aInfo);
1903
1904 private:
1905 static constexpr uint16_t kArrayCapacityIncrement = 32;
1906
1907 enum Type : uint8_t
1908 {
1909 kUnspecified,
1910 kHost,
1911 kService,
1912 kHostKey,
1913 kServiceKey,
1914 kBrowser,
1915 kSrvResolver,
1916 kTxtResolver,
1917 kIp6AddrResolver,
1918 kIp4AddrResolver,
1919 };
1920
1921 explicit EntryIterator(Instance &aInstance);
1922
1923 Type mType;
1924
1925 union
1926 {
1927 const HostEntry *mHostEntry;
1928 const ServiceEntry *mServiceEntry;
1929 const BrowseCache *mBrowseCache;
1930 const SrvCache *mSrvCache;
1931 const TxtCache *mTxtCache;
1932 const Ip6AddrCache *mIp6AddrCache;
1933 const Ip4AddrCache *mIp4AddrCache;
1934 };
1935
1936 Heap::Array<const char *, kArrayCapacityIncrement> mSubTypeArray;
1937 };
1938
1939 #endif // OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
1940
1941 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1942
1943 template <typename EntryType> OwningList<EntryType> &GetEntryList(void);
1944 template <typename EntryType, typename ItemInfo>
1945 Error Register(const ItemInfo &aItemInfo, RequestId aRequestId, RegisterCallback aCallback);
1946 template <typename EntryType, typename ItemInfo> Error Unregister(const ItemInfo &aItemInfo);
1947
1948 template <typename CacheType> OwningList<CacheType> &GetCacheList(void);
1949 template <typename CacheType, typename BrowserResolverType>
1950 Error Start(const BrowserResolverType &aBrowserOrResolver);
1951 template <typename CacheType, typename BrowserResolverType>
1952 Error Stop(const BrowserResolverType &aBrowserOrResolver);
1953
1954 void InvokeConflictCallback(const char *aName, const char *aServiceType);
1955 void HandleMessage(Message &aMessage, bool aIsUnicast, const AddressInfo &aSenderAddress);
1956 void AddPassiveSrvTxtCache(const char *aServiceInstance, const char *aServiceType);
1957 void AddPassiveIp6AddrCache(const char *aHostName);
1958 TimeMilli RandomizeFirstProbeTxTime(void);
1959 TimeMilli RandomizeInitialQueryTxTime(void);
1960 void RemoveEmptyEntries(void);
1961 void HandleEntryTimer(void);
1962 void HandleEntryTask(void);
1963 void HandleCacheTimer(void);
1964 void HandleCacheTask(void);
1965
IsKeyForService(const Key & aKey)1966 static bool IsKeyForService(const Key &aKey) { return aKey.mServiceType != nullptr; }
1967 static uint32_t DetermineTtl(uint32_t aTtl, uint32_t aDefaultTtl);
1968 static bool NameMatch(const Heap::String &aHeapString, const char *aName);
1969 static bool NameMatch(const Heap::String &aFirst, const Heap::String &aSecond);
1970 static void UpdateCacheFlushFlagIn(ResourceRecord &aResourceRecord,
1971 Section aSection,
1972 bool aIsLegacyUnicast = false);
1973 static void UpdateRecordLengthInMessage(ResourceRecord &aRecord, Message &aMessage, uint16_t aOffset);
1974 static void UpdateCompressOffset(uint16_t &aOffset, uint16_t aNewOffse);
1975 static bool QuestionMatches(uint16_t aQuestionRrType, uint16_t aRrType);
1976 static bool RrClassIsInternetOrAny(uint16_t aRrClass);
1977
1978 using EntryTimer = TimerMilliIn<Core, &Core::HandleEntryTimer>;
1979 using CacheTimer = TimerMilliIn<Core, &Core::HandleCacheTimer>;
1980 using EntryTask = TaskletIn<Core, &Core::HandleEntryTask>;
1981 using CacheTask = TaskletIn<Core, &Core::HandleCacheTask>;
1982
1983 static const char kLocalDomain[]; // "local."
1984 static const char kUdpServiceLabel[]; // "_udp"
1985 static const char kTcpServiceLabel[]; // "_tcp"
1986 static const char kSubServiceLabel[]; // "_sub"
1987 static const char kServicesDnssdLabels[]; // "_services._dns-sd._udp"
1988
1989 bool mIsEnabled;
1990 bool mIsQuestionUnicastAllowed;
1991 uint16_t mMaxMessageSize;
1992 uint32_t mInfraIfIndex;
1993 OwningList<HostEntry> mHostEntries;
1994 OwningList<ServiceEntry> mServiceEntries;
1995 OwningList<ServiceType> mServiceTypes;
1996 MultiPacketRxMessages mMultiPacketRxMessages;
1997 TimeMilli mNextProbeTxTime;
1998 EntryTimer mEntryTimer;
1999 EntryTask mEntryTask;
2000 TxMessageHistory mTxMessageHistory;
2001 ConflictCallback mConflictCallback;
2002
2003 OwningList<BrowseCache> mBrowseCacheList;
2004 OwningList<SrvCache> mSrvCacheList;
2005 OwningList<TxtCache> mTxtCacheList;
2006 OwningList<Ip6AddrCache> mIp6AddrCacheList;
2007 OwningList<Ip4AddrCache> mIp4AddrCacheList;
2008 TimeMilli mNextQueryTxTime;
2009 CacheTimer mCacheTimer;
2010 CacheTask mCacheTask;
2011 };
2012
2013 // Specializations of `Core::GetEntryList()` for `HostEntry` and `ServiceEntry`:
2014
GetEntryList(void)2015 template <> inline OwningList<Core::HostEntry> &Core::GetEntryList<Core::HostEntry>(void) { return mHostEntries; }
2016
GetEntryList(void)2017 template <> inline OwningList<Core::ServiceEntry> &Core::GetEntryList<Core::ServiceEntry>(void)
2018 {
2019 return mServiceEntries;
2020 }
2021
2022 // Specializations of `Core::GetCacheList()`:
2023
GetCacheList(void)2024 template <> inline OwningList<Core::BrowseCache> &Core::GetCacheList<Core::BrowseCache>(void)
2025 {
2026 return mBrowseCacheList;
2027 }
2028
GetCacheList(void)2029 template <> inline OwningList<Core::SrvCache> &Core::GetCacheList<Core::SrvCache>(void) { return mSrvCacheList; }
2030
GetCacheList(void)2031 template <> inline OwningList<Core::TxtCache> &Core::GetCacheList<Core::TxtCache>(void) { return mTxtCacheList; }
2032
GetCacheList(void)2033 template <> inline OwningList<Core::Ip6AddrCache> &Core::GetCacheList<Core::Ip6AddrCache>(void)
2034 {
2035 return mIp6AddrCacheList;
2036 }
2037
GetCacheList(void)2038 template <> inline OwningList<Core::Ip4AddrCache> &Core::GetCacheList<Core::Ip4AddrCache>(void)
2039 {
2040 return mIp4AddrCacheList;
2041 }
2042
2043 } // namespace Multicast
2044 } // namespace Dns
2045
2046 DefineCoreType(otPlatMdnsAddressInfo, Dns::Multicast::Core::AddressInfo);
2047
2048 } // namespace ot
2049
2050 #endif // OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
2051
2052 #endif // MULTICAST_DNS_HPP_
2053