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