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 kNsecTtl = 4500;
766 static constexpr uint32_t kServicesPtrTtl = 4500;
767
768 static constexpr uint16_t kClassQuestionUnicastFlag = (1U << 15);
769 static constexpr uint16_t kClassCacheFlushFlag = (1U << 15);
770 static constexpr uint16_t kClassMask = (0x7fff);
771
772 static constexpr uint16_t kUnspecifiedOffset = 0;
773
774 static constexpr uint8_t kNumSections = 4;
775
776 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
777
778 enum Section : uint8_t
779 {
780 kQuestionSection,
781 kAnswerSection,
782 kAuthoritySection,
783 kAdditionalDataSection,
784 };
785
786 enum AppendOutcome : uint8_t
787 {
788 kAppendedFullNameAsCompressed,
789 kAppendedLabels,
790 };
791
792 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
793 // Forward declarations
794
795 class EntryTimerContext;
796 class TxMessage;
797 class RxMessage;
798 class ServiceEntry;
799 class ServiceType;
800 class EntryIterator;
801
802 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
803
804 struct EmptyChecker
805 {
806 // Used in `Matches()` to find empty entries (with no record) to remove and free.
807 };
808
809 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
810
811 struct ExpireChecker
812 {
813 // Used in `Matches()` to find expired entries in a list.
814
ExpireCheckerot::Dns::Multicast::Core::ExpireChecker815 explicit ExpireChecker(TimeMilli aNow) { mNow = aNow; }
816
817 TimeMilli mNow;
818 };
819
820 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
821
822 class Callback : public Clearable<Callback>
823 {
824 public:
Callback(void)825 Callback(void) { Clear(); }
826 Callback(RequestId aRequestId, RegisterCallback aCallback);
827
IsEmpty(void) const828 bool IsEmpty(void) const { return (mCallback == nullptr); }
829 void InvokeAndClear(Instance &aInstance, Error aError);
830
831 private:
832 RequestId mRequestId;
833 RegisterCallback mCallback;
834 };
835
836 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
837
838 class RecordCounts : public Clearable<RecordCounts>
839 {
840 public:
RecordCounts(void)841 RecordCounts(void) { Clear(); }
842
GetFor(Section aSection) const843 uint16_t GetFor(Section aSection) const { return mCounts[aSection]; }
Increment(Section aSection)844 void Increment(Section aSection) { mCounts[aSection]++; }
845 void ReadFrom(const Header &aHeader);
846 void WriteTo(Header &aHeader) const;
847 bool IsEmpty(void) const;
848
849 private:
850 uint16_t mCounts[kNumSections];
851 };
852
853 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
854
855 struct AnswerInfo
856 {
857 uint16_t mQuestionRrType;
858 TimeMilli mAnswerTime;
859 bool mIsProbe;
860 bool mUnicastResponse;
861 };
862
863 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
864
865 class AddressArray : public Heap::Array<Ip6::Address>
866 {
867 public:
868 bool Matches(const Ip6::Address *aAddresses, uint16_t aNumAddresses) const;
869 void SetFrom(const Ip6::Address *aAddresses, uint16_t aNumAddresses);
870 };
871
872 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
873
874 class FireTime
875 {
876 public:
FireTime(void)877 FireTime(void) { ClearFireTime(); }
ClearFireTime(void)878 void ClearFireTime(void) { mHasFireTime = false; }
HasFireTime(void) const879 bool HasFireTime(void) const { return mHasFireTime; }
GetFireTime(void) const880 TimeMilli GetFireTime(void) const { return mFireTime; }
881 void SetFireTime(TimeMilli aFireTime);
882
883 protected:
884 void ScheduleFireTimeOn(TimerMilli &aTimer);
885 void UpdateNextFireTimeOn(NextFireTime &aNextFireTime) const;
886
887 private:
888 TimeMilli mFireTime;
889 bool mHasFireTime;
890 };
891
892 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
893
894 class RecordInfo : public Clearable<RecordInfo>, private NonCopyable
895 {
896 public:
897 // Keeps track of record state and timings.
898
RecordInfo(void)899 RecordInfo(void) { Clear(); }
900
IsPresent(void) const901 bool IsPresent(void) const { return mIsPresent; }
GetTtl(void) const902 uint32_t GetTtl(void) const { return mTtl; }
903
904 template <typename UintType> void UpdateProperty(UintType &aProperty, UintType aValue);
905 void UpdateProperty(AddressArray &aAddrProperty, const Ip6::Address *aAddrs, uint16_t aNumAddrs);
906 void UpdateProperty(Heap::String &aStringProperty, const char *aString);
907 void UpdateProperty(Heap::Data &aDataProperty, const uint8_t *aData, uint16_t aLength);
908 void UpdateTtl(uint32_t aTtl);
909
910 void StartAnnouncing(void);
911 bool ShouldAppendTo(TxMessage &aResponse, TimeMilli aNow) const;
912 bool CanAnswer(void) const;
913 void ScheduleAnswer(const AnswerInfo &aInfo);
914 void UpdateStateAfterAnswer(const TxMessage &aResponse);
915 void UpdateFireTimeOn(FireTime &aFireTime);
916 uint32_t GetDurationSinceLastMulticast(TimeMilli aTime) const;
917 Error GetLastMulticastTime(TimeMilli &aLastMulticastTime) const;
918
919 // `AppendState` methods: Used to track whether the record
920 // is appended in a message, or needs to be appended in
921 // Additional Data section.
922
MarkAsNotAppended(void)923 void MarkAsNotAppended(void) { mAppendState = kNotAppended; }
924 void MarkAsAppended(TxMessage &aTxMessage, Section aSection);
925 void MarkToAppendInAdditionalData(void);
926 bool IsAppended(void) const;
927 bool CanAppend(void) const;
ShouldAppendInAdditionalDataSection(void) const928 bool ShouldAppendInAdditionalDataSection(void) const { return (mAppendState == kToAppendInAdditionalData); }
929
930 private:
931 enum AppendState : uint8_t
932 {
933 kNotAppended,
934 kToAppendInAdditionalData,
935 kAppendedInMulticastMsg,
936 kAppendedInUnicastMsg,
937 };
938
939 static constexpr uint32_t kMinIntervalBetweenMulticast = 1000; // msec
940 static constexpr uint32_t kLastMulticastTimeAge = 10 * Time::kOneHourInMsec;
941
942 static_assert(kNotAppended == 0, "kNotAppended MUST be zero, so `Clear()` works correctly");
943
944 bool mIsPresent : 1;
945 bool mMulticastAnswerPending : 1;
946 bool mUnicastAnswerPending : 1;
947 bool mIsLastMulticastValid : 1;
948 uint8_t mAnnounceCounter;
949 AppendState mAppendState;
950 Section mAppendSection;
951 uint32_t mTtl;
952 TimeMilli mAnnounceTime;
953 TimeMilli mAnswerTime;
954 TimeMilli mLastMulticastTime;
955 };
956
957 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
958
959 class Entry : public InstanceLocatorInit, public FireTime, private NonCopyable
960 {
961 // Base class for `HostEntry` and `ServiceEntry`.
962
963 friend class ServiceType;
964
965 public:
966 enum State : uint8_t
967 {
968 kProbing = OT_MDNS_ENTRY_STATE_PROBING,
969 kRegistered = OT_MDNS_ENTRY_STATE_REGISTERED,
970 kConflict = OT_MDNS_ENTRY_STATE_CONFLICT,
971 kRemoving = OT_MDNS_ENTRY_STATE_REMOVING,
972 };
973
GetState(void) const974 State GetState(void) const { return mState; }
HasKeyRecord(void) const975 bool HasKeyRecord(void) const { return mKeyRecord.IsPresent(); }
976 void Register(const Key &aKey, const Callback &aCallback);
977 void Unregister(const Key &aKey);
978 void InvokeCallbacks(void);
979 void ClearAppendState(void);
980 Error CopyKeyInfoTo(Key &aKey, EntryState &aState) const;
981
982 protected:
983 static constexpr uint32_t kMinIntervalProbeResponse = 250; // msec
984 static constexpr uint8_t kTypeArraySize = 8; // We can have SRV, TXT and KEY today.
985
986 struct TypeArray : public Array<uint16_t, kTypeArraySize> // Array of record types for NSEC record
987 {
Addot::Dns::Multicast::Core::Entry::TypeArray988 void Add(uint16_t aType) { SuccessOrAssert(PushBack(aType)); }
989 };
990
991 struct RecordAndType
992 {
993 RecordInfo &mRecord;
994 uint16_t mType;
995 };
996
997 typedef void (*NameAppender)(Entry &aEntry, TxMessage &aTxMessage, Section aSection);
998
999 Entry(void);
1000 void Init(Instance &aInstance);
1001 void SetCallback(const Callback &aCallback);
ClearCallback(void)1002 void ClearCallback(void) { mCallback.Clear(); }
1003 void MarkToInvokeCallbackUnconditionally(void);
1004 void StartProbing(void);
1005 void SetStateToConflict(void);
1006 void SetStateToRemoving(void);
1007 void UpdateRecordsState(const TxMessage &aResponse);
1008 void AppendQuestionTo(TxMessage &aTxMessage) const;
1009 void AppendKeyRecordTo(TxMessage &aTxMessage, Section aSection, NameAppender aNameAppender);
1010 void AppendNsecRecordTo(TxMessage &aTxMessage,
1011 Section aSection,
1012 const TypeArray &aTypes,
1013 NameAppender aNameAppender);
1014 bool ShouldAnswerNsec(TimeMilli aNow) const;
1015 void DetermineNextFireTime(void);
1016 void ScheduleTimer(void);
1017 void AnswerProbe(const AnswerInfo &aInfo, RecordAndType *aRecords, uint16_t aRecordsLength);
1018 void AnswerNonProbe(const AnswerInfo &aInfo, RecordAndType *aRecords, uint16_t aRecordsLength);
1019 void ScheduleNsecAnswer(const AnswerInfo &aInfo);
1020
1021 template <typename EntryType> void HandleTimer(EntryTimerContext &aContext);
1022
1023 RecordInfo mKeyRecord;
1024
1025 private:
1026 void SetState(State aState);
1027 void ClearKey(void);
1028 void ScheduleCallbackTask(void);
1029 void CheckMessageSizeLimitToPrepareAgain(TxMessage &aTxMessage, bool &aPrepareAgain);
1030
1031 State mState;
1032 uint8_t mProbeCount;
1033 bool mMulticastNsecPending : 1;
1034 bool mUnicastNsecPending : 1;
1035 bool mAppendedNsec : 1;
1036 bool mBypassCallbackStateCheck : 1;
1037 TimeMilli mNsecAnswerTime;
1038 Heap::Data mKeyData;
1039 Callback mCallback;
1040 Callback mKeyCallback;
1041 };
1042
1043 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1044
1045 class HostEntry : public Entry, public LinkedListEntry<HostEntry>, public Heap::Allocatable<HostEntry>
1046 {
1047 friend class LinkedListEntry<HostEntry>;
1048 friend class Entry;
1049 friend class ServiceEntry;
1050
1051 public:
1052 HostEntry(void);
Init(Instance & aInstance,const Host & aHost)1053 Error Init(Instance &aInstance, const Host &aHost) { return Init(aInstance, aHost.mHostName); }
Init(Instance & aInstance,const Key & aKey)1054 Error Init(Instance &aInstance, const Key &aKey) { return Init(aInstance, aKey.mName); }
1055 bool IsEmpty(void) const;
1056 bool Matches(const Name &aName) const;
1057 bool Matches(const Host &aHost) const;
1058 bool Matches(const Key &aKey) const;
1059 bool Matches(const Heap::String &aName) const;
Matches(State aState) const1060 bool Matches(State aState) const { return GetState() == aState; }
Matches(const HostEntry & aEntry) const1061 bool Matches(const HostEntry &aEntry) const { return (this == &aEntry); }
1062 void Register(const Host &aHost, const Callback &aCallback);
1063 void Register(const Key &aKey, const Callback &aCallback);
1064 void Unregister(const Host &aHost);
1065 void Unregister(const Key &aKey);
1066 void AnswerQuestion(const AnswerInfo &aInfo);
1067 void HandleTimer(EntryTimerContext &aContext);
1068 void ClearAppendState(void);
1069 void PrepareResponse(TxMessage &aResponse, TimeMilli aNow);
1070 void HandleConflict(void);
1071 #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
1072 Error CopyInfoTo(Host &aHost, EntryState &aState) const;
1073 Error CopyInfoTo(Key &aKey, EntryState &aState) const;
1074 #endif
1075
1076 private:
1077 Error Init(Instance &aInstance, const char *aName);
1078 void ClearHost(void);
1079 void ScheduleToRemoveIfEmpty(void);
1080 void PrepareProbe(TxMessage &aProbe);
1081 void StartAnnouncing(void);
1082 void PrepareResponseRecords(TxMessage &aResponse, TimeMilli aNow);
1083 void UpdateRecordsState(const TxMessage &aResponse);
1084 void DetermineNextFireTime(void);
1085 void AppendAddressRecordsTo(TxMessage &aTxMessage, Section aSection);
1086 void AppendKeyRecordTo(TxMessage &aTxMessage, Section aSection);
1087 void AppendNsecRecordTo(TxMessage &aTxMessage, Section aSection);
1088 void AppendNameTo(TxMessage &aTxMessage, Section aSection);
1089
1090 static void AppendEntryName(Entry &aEntry, TxMessage &aTxMessage, Section aSection);
1091
1092 HostEntry *mNext;
1093 Heap::String mName;
1094 RecordInfo mAddrRecord;
1095 AddressArray mAddresses;
1096 uint16_t mNameOffset;
1097 };
1098
1099 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1100
1101 class ServiceEntry : public Entry, public LinkedListEntry<ServiceEntry>, public Heap::Allocatable<ServiceEntry>
1102 {
1103 friend class LinkedListEntry<ServiceEntry>;
1104 friend class Entry;
1105 friend class ServiceType;
1106
1107 public:
1108 ServiceEntry(void);
1109 Error Init(Instance &aInstance, const Service &aService);
1110 Error Init(Instance &aInstance, const Key &aKey);
1111 bool IsEmpty(void) const;
1112 bool Matches(const Name &aFullName) const;
1113 bool Matches(const Service &aService) const;
1114 bool Matches(const Key &aKey) const;
Matches(State aState) const1115 bool Matches(State aState) const { return GetState() == aState; }
Matches(const ServiceEntry & aEntry) const1116 bool Matches(const ServiceEntry &aEntry) const { return (this == &aEntry); }
1117 bool MatchesServiceType(const Name &aServiceType) const;
1118 bool CanAnswerSubType(const char *aSubLabel) const;
1119 void Register(const Service &aService, const Callback &aCallback);
1120 void Register(const Key &aKey, const Callback &aCallback);
1121 void Unregister(const Service &aService);
1122 void Unregister(const Key &aKey);
1123 void AnswerServiceNameQuestion(const AnswerInfo &aInfo);
1124 void AnswerServiceTypeQuestion(const AnswerInfo &aInfo, const char *aSubLabel);
1125 bool ShouldSuppressKnownAnswer(uint32_t aTtl, const char *aSubLabel) const;
1126 void HandleTimer(EntryTimerContext &aContext);
1127 void ClearAppendState(void);
1128 void PrepareResponse(TxMessage &aResponse, TimeMilli aNow);
1129 void HandleConflict(void);
1130 #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
1131 Error CopyInfoTo(Service &aService, EntryState &aState, EntryIterator &aIterator) const;
1132 Error CopyInfoTo(Key &aKey, EntryState &aState) const;
1133 #endif
1134
1135 private:
1136 class SubType : public LinkedListEntry<SubType>, public Heap::Allocatable<SubType>, private ot::NonCopyable
1137 {
1138 public:
1139 Error Init(const char *aLabel);
Matches(const char * aLabel) const1140 bool Matches(const char *aLabel) const { return NameMatch(mLabel, aLabel); }
1141 bool Matches(const EmptyChecker &aChecker) const;
1142 bool IsContainedIn(const Service &aService) const;
1143
1144 SubType *mNext;
1145 Heap::String mLabel;
1146 RecordInfo mPtrRecord;
1147 uint16_t mSubServiceNameOffset;
1148 };
1149
1150 Error Init(Instance &aInstance, const char *aServiceInstance, const char *aServiceType);
1151 void ClearService(void);
1152 void ScheduleToRemoveIfEmpty(void);
1153 void PrepareProbe(TxMessage &aProbe);
1154 void StartAnnouncing(void);
1155 void PrepareResponseRecords(TxMessage &aResponse, TimeMilli aNow);
1156 void UpdateRecordsState(const TxMessage &aResponse);
1157 void DetermineNextFireTime(void);
1158 void DiscoverOffsetsAndHost(HostEntry *&aHost);
1159 void UpdateServiceTypes(void);
1160 void AppendSrvRecordTo(TxMessage &aTxMessage, Section aSection);
1161 void AppendTxtRecordTo(TxMessage &aTxMessage, Section aSection);
1162 void AppendPtrRecordTo(TxMessage &aTxMessage, Section aSection, SubType *aSubType = nullptr);
1163 void AppendKeyRecordTo(TxMessage &aTxMessage, Section aSection);
1164 void AppendNsecRecordTo(TxMessage &aTxMessage, Section aSection);
1165 void AppendServiceNameTo(TxMessage &TxMessage, Section aSection);
1166 void AppendServiceTypeTo(TxMessage &aTxMessage, Section aSection);
1167 void AppendSubServiceTypeTo(TxMessage &aTxMessage, Section aSection);
1168 void AppendSubServiceNameTo(TxMessage &aTxMessage, Section aSection, SubType &aSubType);
1169 void AppendHostNameTo(TxMessage &aTxMessage, Section aSection);
1170
1171 static void AppendEntryName(Entry &aEntry, TxMessage &aTxMessage, Section aSection);
1172
1173 static const uint8_t kEmptyTxtData[];
1174
1175 ServiceEntry *mNext;
1176 Heap::String mServiceInstance;
1177 Heap::String mServiceType;
1178 RecordInfo mPtrRecord;
1179 RecordInfo mSrvRecord;
1180 RecordInfo mTxtRecord;
1181 OwningList<SubType> mSubTypes;
1182 Heap::String mHostName;
1183 Heap::Data mTxtData;
1184 uint16_t mPriority;
1185 uint16_t mWeight;
1186 uint16_t mPort;
1187 uint16_t mServiceNameOffset;
1188 uint16_t mServiceTypeOffset;
1189 uint16_t mSubServiceTypeOffset;
1190 uint16_t mHostNameOffset;
1191 bool mIsAddedInServiceTypes;
1192 };
1193
1194 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1195
1196 class ServiceType : public InstanceLocatorInit,
1197 public FireTime,
1198 public LinkedListEntry<ServiceType>,
1199 public Heap::Allocatable<ServiceType>,
1200 private NonCopyable
1201 {
1202 // Track a service type to answer to `_services._dns-sd._udp.local`
1203 // queries.
1204
1205 friend class LinkedListEntry<ServiceType>;
1206
1207 public:
1208 Error Init(Instance &aInstance, const char *aServiceType);
1209 bool Matches(const Name &aServiceTypeName) const;
1210 bool Matches(const Heap::String &aServiceType) const;
Matches(const ServiceType & aServiceType) const1211 bool Matches(const ServiceType &aServiceType) const { return (this == &aServiceType); }
IncrementNumEntries(void)1212 void IncrementNumEntries(void) { mNumEntries++; }
DecrementNumEntries(void)1213 void DecrementNumEntries(void) { mNumEntries--; }
GetNumEntries(void) const1214 uint16_t GetNumEntries(void) const { return mNumEntries; }
1215 void ClearAppendState(void);
1216 void AnswerQuestion(const AnswerInfo &aInfo);
1217 bool ShouldSuppressKnownAnswer(uint32_t aTtl) const;
1218 void HandleTimer(EntryTimerContext &aContext);
1219 void PrepareResponse(TxMessage &aResponse, TimeMilli aNow);
1220
1221 private:
1222 void PrepareResponseRecords(TxMessage &aResponse, TimeMilli aNow);
1223 void AppendPtrRecordTo(TxMessage &aResponse, uint16_t aServiceTypeOffset);
1224
1225 ServiceType *mNext;
1226 Heap::String mServiceType;
1227 RecordInfo mServicesPtr;
1228 uint16_t mNumEntries; // Number of service entries providing this service type.
1229 };
1230
1231 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1232
1233 class TxMessage : public InstanceLocator
1234 {
1235 public:
1236 enum Type : uint8_t
1237 {
1238 kMulticastProbe,
1239 kMulticastQuery,
1240 kMulticastResponse,
1241 kUnicastResponse,
1242 };
1243
1244 TxMessage(Instance &aInstance, Type aType);
1245 TxMessage(Instance &aInstance, Type aType, const AddressInfo &aUnicastDest);
GetType(void) const1246 Type GetType(void) const { return mType; }
1247 Message &SelectMessageFor(Section aSection);
1248 AppendOutcome AppendLabel(Section aSection, const char *aLabel, uint16_t &aCompressOffset);
1249 AppendOutcome AppendMultipleLabels(Section aSection, const char *aLabels, uint16_t &aCompressOffset);
1250 void AppendServiceType(Section aSection, const char *aServiceType, uint16_t &aCompressOffset);
1251 void AppendDomainName(Section aSection);
1252 void AppendServicesDnssdName(Section aSection);
IncrementRecordCount(Section aSection)1253 void IncrementRecordCount(Section aSection) { mRecordCounts.Increment(aSection); }
1254 void CheckSizeLimitToPrepareAgain(bool &aPrepareAgain);
1255 void SaveCurrentState(void);
1256 void RestoreToSavedState(void);
1257 void Send(void);
1258
1259 private:
1260 static constexpr bool kIsSingleLabel = true;
1261
1262 void Init(Type aType);
1263 void Reinit(void);
1264 bool IsOverSizeLimit(void) const;
1265 AppendOutcome AppendLabels(Section aSection,
1266 const char *aLabels,
1267 bool aIsSingleLabel,
1268 uint16_t &aCompressOffset);
1269 bool ShouldClearAppendStateOnReinit(const Entry &aEntry) const;
1270
1271 static void SaveOffset(uint16_t &aCompressOffset, const Message &aMessage, Section aSection);
1272
1273 RecordCounts mRecordCounts;
1274 OwnedPtr<Message> mMsgPtr;
1275 OwnedPtr<Message> mExtraMsgPtr;
1276 RecordCounts mSavedRecordCounts;
1277 uint16_t mSavedMsgLength;
1278 uint16_t mSavedExtraMsgLength;
1279 uint16_t mDomainOffset; // Offset for domain name `.local.` for name compression.
1280 uint16_t mUdpOffset; // Offset to `_udp.local.`
1281 uint16_t mTcpOffset; // Offset to `_tcp.local.`
1282 uint16_t mServicesDnssdOffset; // Offset to `_services._dns-sd`
1283 AddressInfo mUnicastDest;
1284 Type mType;
1285 };
1286
1287 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1288
1289 class EntryTimerContext : public InstanceLocator // Used by `HandleEntryTimer`.
1290 {
1291 public:
1292 EntryTimerContext(Instance &aInstance);
GetNow(void) const1293 TimeMilli GetNow(void) const { return mNextFireTime.GetNow(); }
GetNextFireTime(void)1294 NextFireTime &GetNextFireTime(void) { return mNextFireTime; }
GetProbeMessage(void)1295 TxMessage &GetProbeMessage(void) { return mProbeMessage; }
GetResponseMessage(void)1296 TxMessage &GetResponseMessage(void) { return mResponseMessage; }
1297
1298 private:
1299 NextFireTime mNextFireTime;
1300 TxMessage mProbeMessage;
1301 TxMessage mResponseMessage;
1302 };
1303
1304 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1305
1306 class RxMessage : public InstanceLocatorInit,
1307 public Heap::Allocatable<RxMessage>,
1308 public LinkedListEntry<RxMessage>,
1309 private NonCopyable
1310 {
1311 friend class LinkedListEntry<RxMessage>;
1312
1313 public:
1314 enum ProcessOutcome : uint8_t
1315 {
1316 kProcessed,
1317 kSaveAsMultiPacket,
1318 };
1319
1320 Error Init(Instance &aInstance,
1321 OwnedPtr<Message> &aMessagePtr,
1322 bool aIsUnicast,
1323 const AddressInfo &aSenderAddress);
IsQuery(void) const1324 bool IsQuery(void) const { return mIsQuery; }
IsTruncated(void) const1325 bool IsTruncated(void) const { return mTruncated; }
IsSelfOriginating(void) const1326 bool IsSelfOriginating(void) const { return mIsSelfOriginating; }
GetRecordCounts(void) const1327 const RecordCounts &GetRecordCounts(void) const { return mRecordCounts; }
GetSenderAddress(void) const1328 const AddressInfo &GetSenderAddress(void) const { return mSenderAddress; }
1329 void ClearProcessState(void);
1330 ProcessOutcome ProcessQuery(bool aShouldProcessTruncated);
1331 void ProcessResponse(void);
1332
1333 private:
1334 typedef void (RxMessage::*RecordProcessor)(const Name &aName,
1335 const ResourceRecord &aRecord,
1336 uint16_t aRecordOffset);
1337
1338 struct Question : public Clearable<Question>
1339 {
Questionot::Dns::Multicast::Core::RxMessage::Question1340 Question(void) { Clear(); }
1341 void ClearProcessState(void);
1342
1343 Entry *mEntry; // Entry which can provide answer (if any).
1344 uint16_t mNameOffset; // Offset to start of question name.
1345 uint16_t mRrType; // The question record type.
1346 bool mIsRrClassInternet : 1; // Is the record class Internet or Any.
1347 bool mIsProbe : 1; // Is a probe (contains a matching record in Authority section).
1348 bool mUnicastResponse : 1; // Is QU flag set (requesting a unicast response).
1349 bool mCanAnswer : 1; // Can provide answer for this question
1350 bool mIsUnique : 1; // Is unique record (vs a shared record).
1351 bool mIsForService : 1; // Is for a `ServiceEntry` (vs a `HostEntry`).
1352 bool mIsServiceType : 1; // Is for service type or sub-type of a `ServiceEntry`.
1353 bool mIsForAllServicesDnssd : 1; // Is for "_services._dns-sd._udp" (all service types).
1354 };
1355
1356 static constexpr uint32_t kMinResponseDelay = 20; // msec
1357 static constexpr uint32_t kMaxResponseDelay = 120; // msec
1358
1359 void ProcessQuestion(Question &aQuestion);
1360 void AnswerQuestion(const Question &aQuestion, TimeMilli aAnswerTime);
1361 void AnswerServiceTypeQuestion(const Question &aQuestion, const AnswerInfo &aInfo, ServiceEntry &aFirstEntry);
1362 bool ShouldSuppressKnownAnswer(const Name &aServiceType,
1363 const char *aSubLabel,
1364 const ServiceEntry &aServiceEntry) const;
1365 bool ParseQuestionNameAsSubType(const Question &aQuestion,
1366 Name::LabelBuffer &aSubLabel,
1367 Name &aServiceType) const;
1368 void AnswerAllServicesQuestion(const Question &aQuestion, const AnswerInfo &aInfo);
1369 bool ShouldSuppressKnownAnswer(const Question &aQuestion, const ServiceType &aServiceType) const;
1370 void SendUnicastResponse(const AddressInfo &aUnicastDest);
1371 void IterateOnAllRecordsInResponse(RecordProcessor aRecordProcessor);
1372 void ProcessRecordForConflict(const Name &aName, const ResourceRecord &aRecord, uint16_t aRecordOffset);
1373 void ProcessPtrRecord(const Name &aName, const ResourceRecord &aRecord, uint16_t aRecordOffset);
1374 void ProcessSrvRecord(const Name &aName, const ResourceRecord &aRecord, uint16_t aRecordOffset);
1375 void ProcessTxtRecord(const Name &aName, const ResourceRecord &aRecord, uint16_t aRecordOffset);
1376 void ProcessAaaaRecord(const Name &aName, const ResourceRecord &aRecord, uint16_t aRecordOffset);
1377 void ProcessARecord(const Name &aName, const ResourceRecord &aRecord, uint16_t aRecordOffset);
1378
1379 RxMessage *mNext;
1380 OwnedPtr<Message> mMessagePtr;
1381 Heap::Array<Question> mQuestions;
1382 AddressInfo mSenderAddress;
1383 RecordCounts mRecordCounts;
1384 uint16_t mStartOffset[kNumSections];
1385 bool mIsQuery : 1;
1386 bool mIsUnicast : 1;
1387 bool mTruncated : 1;
1388 bool mIsSelfOriginating : 1;
1389 };
1390
1391 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1392
HandleMultiPacketTimer(void)1393 void HandleMultiPacketTimer(void) { mMultiPacketRxMessages.HandleTimer(); }
1394
1395 class MultiPacketRxMessages : public InstanceLocator
1396 {
1397 public:
1398 explicit MultiPacketRxMessages(Instance &aInstance);
1399
1400 void AddToExisting(OwnedPtr<RxMessage> &aRxMessagePtr);
1401 void AddNew(OwnedPtr<RxMessage> &aRxMessagePtr);
1402 void HandleTimer(void);
1403 void Clear(void);
1404
1405 private:
1406 static constexpr uint32_t kMinProcessDelay = 400; // msec
1407 static constexpr uint32_t kMaxProcessDelay = 500; // msec
1408 static constexpr uint16_t kMaxNumMessages = 10;
1409
1410 struct RxMsgEntry : public InstanceLocator,
1411 public LinkedListEntry<RxMsgEntry>,
1412 public Heap::Allocatable<RxMsgEntry>,
1413 private NonCopyable
1414 {
1415 explicit RxMsgEntry(Instance &aInstance);
1416
1417 bool Matches(const AddressInfo &aAddress) const;
1418 bool Matches(const ExpireChecker &aExpireChecker) const;
1419 void Add(OwnedPtr<RxMessage> &aRxMessagePtr);
1420
1421 OwningList<RxMessage> mRxMessages;
1422 TimeMilli mProcessTime;
1423 RxMsgEntry *mNext;
1424 };
1425
1426 using MultiPacketTimer = TimerMilliIn<Core, &Core::HandleMultiPacketTimer>;
1427
1428 OwningList<RxMsgEntry> mRxMsgEntries;
1429 MultiPacketTimer mTimer;
1430 };
1431
1432 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1433
HandleTxMessageHistoryTimer(void)1434 void HandleTxMessageHistoryTimer(void) { mTxMessageHistory.HandleTimer(); }
1435
1436 class TxMessageHistory : public InstanceLocator
1437 {
1438 // Keep track of messages sent by mDNS module to tell if
1439 // a received message is self originating.
1440
1441 public:
1442 explicit TxMessageHistory(Instance &aInstance);
1443 void Clear(void);
1444 void Add(const Message &aMessage);
1445 bool Contains(const Message &aMessage) const;
1446 void HandleTimer(void);
1447
1448 private:
1449 static constexpr uint32_t kExpireInterval = TimeMilli::SecToMsec(10); // in msec
1450
1451 typedef Crypto::Sha256::Hash Hash;
1452
1453 struct HashEntry : public LinkedListEntry<HashEntry>, public Heap::Allocatable<HashEntry>
1454 {
Matchesot::Dns::Multicast::Core::TxMessageHistory::HashEntry1455 bool Matches(const Hash &aHash) const { return aHash == mHash; }
Matchesot::Dns::Multicast::Core::TxMessageHistory::HashEntry1456 bool Matches(const ExpireChecker &aExpireChecker) const { return mExpireTime <= aExpireChecker.mNow; }
1457
1458 HashEntry *mNext;
1459 Hash mHash;
1460 TimeMilli mExpireTime;
1461 };
1462
1463 static void CalculateHash(const Message &aMessage, Hash &aHash);
1464
1465 using TxMsgHistoryTimer = TimerMilliIn<Core, &Core::HandleTxMessageHistoryTimer>;
1466
1467 OwningList<HashEntry> mHashEntries;
1468 TxMsgHistoryTimer mTimer;
1469 };
1470
1471 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1472
1473 class CacheEntry;
1474 class TxtCache;
1475
1476 class ResultCallback : public LinkedListEntry<ResultCallback>, public Heap::Allocatable<ResultCallback>
1477 {
1478 friend class Heap::Allocatable<ResultCallback>;
1479 friend class LinkedListEntry<ResultCallback>;
1480 friend class CacheEntry;
1481
1482 public:
1483 ResultCallback(const ResultCallback &aResultCallback) = default;
1484
1485 template <typename CallbackType>
ResultCallback(CallbackType aCallback)1486 explicit ResultCallback(CallbackType aCallback)
1487 : mNext(nullptr)
1488 , mSharedCallback(aCallback)
1489 {
1490 }
1491
Matches(BrowseCallback aCallback) const1492 bool Matches(BrowseCallback aCallback) const { return mSharedCallback.mBrowse == aCallback; }
Matches(SrvCallback aCallback) const1493 bool Matches(SrvCallback aCallback) const { return mSharedCallback.mSrv == aCallback; }
Matches(TxtCallback aCallback) const1494 bool Matches(TxtCallback aCallback) const { return mSharedCallback.mTxt == aCallback; }
Matches(AddressCallback aCallback) const1495 bool Matches(AddressCallback aCallback) const { return mSharedCallback.mAddress == aCallback; }
Matches(EmptyChecker) const1496 bool Matches(EmptyChecker) const { return (mSharedCallback.mSrv == nullptr); }
1497
1498 void Invoke(Instance &aInstance, const BrowseResult &aResult) const;
1499 void Invoke(Instance &aInstance, const SrvResult &aResult) const;
1500 void Invoke(Instance &aInstance, const TxtResult &aResult) const;
1501 void Invoke(Instance &aInstance, const AddressResult &aResult) const;
1502
ClearCallback(void)1503 void ClearCallback(void) { mSharedCallback.Clear(); }
1504
1505 private:
1506 union SharedCallback
1507 {
SharedCallback(BrowseCallback aCallback)1508 explicit SharedCallback(BrowseCallback aCallback) { mBrowse = aCallback; }
SharedCallback(SrvCallback aCallback)1509 explicit SharedCallback(SrvCallback aCallback) { mSrv = aCallback; }
SharedCallback(TxtCallback aCallback)1510 explicit SharedCallback(TxtCallback aCallback) { mTxt = aCallback; }
SharedCallback(AddressCallback aCallback)1511 explicit SharedCallback(AddressCallback aCallback) { mAddress = aCallback; }
1512
Clear(void)1513 void Clear(void) { mBrowse = nullptr; }
1514
1515 BrowseCallback mBrowse;
1516 SrvCallback mSrv;
1517 TxtCallback mTxt;
1518 AddressCallback mAddress;
1519 };
1520
1521 ResultCallback *mNext;
1522 SharedCallback mSharedCallback;
1523 };
1524
1525 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1526
1527 class CacheTimerContext : public InstanceLocator
1528 {
1529 public:
1530 CacheTimerContext(Instance &aInstance);
GetNow(void) const1531 TimeMilli GetNow(void) const { return mNextFireTime.GetNow(); }
GetNextFireTime(void)1532 NextFireTime &GetNextFireTime(void) { return mNextFireTime; }
GetQueryMessage(void)1533 TxMessage &GetQueryMessage(void) { return mQueryMessage; }
1534
1535 private:
1536 NextFireTime mNextFireTime;
1537 TxMessage mQueryMessage;
1538 };
1539
1540 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1541
1542 class CacheRecordInfo
1543 {
1544 public:
1545 CacheRecordInfo(void);
1546
IsPresent(void) const1547 bool IsPresent(void) const { return (mTtl > 0); }
GetTtl(void) const1548 uint32_t GetTtl(void) const { return mTtl; }
1549 bool RefreshTtl(uint32_t aTtl);
1550 bool ShouldExpire(TimeMilli aNow) const;
1551 void UpdateStateAfterQuery(TimeMilli aNow);
1552 void UpdateQueryAndFireTimeOn(CacheEntry &aCacheEntry);
1553 bool LessThanHalfTtlRemains(TimeMilli aNow) const;
1554 uint32_t GetRemainingTtl(TimeMilli aNow) const;
1555
1556 private:
1557 static constexpr uint32_t kMaxTtl = (24 * 3600); // One day
1558 static constexpr uint8_t kNumberOfQueries = 4;
1559 static constexpr uint32_t kQueryTtlVariation = 1000 * 2 / 100; // 2%
1560
1561 uint32_t GetClampedTtl(void) const;
1562 TimeMilli GetExpireTime(void) const;
1563 TimeMilli GetQueryTime(uint8_t aAttemptIndex) const;
1564
1565 uint32_t mTtl;
1566 TimeMilli mLastRxTime;
1567 uint8_t mQueryCount;
1568 };
1569
1570 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1571
1572 class CacheEntry : public FireTime, public InstanceLocatorInit, private NonCopyable
1573 {
1574 // Base class for cache entries: `BrowseCache`, `mSrvCache`,
1575 // `mTxtCache`, etc. Implements common behaviors: initial
1576 // queries, query/timer scheduling, callback tracking, entry
1577 // aging, and timer handling. Tracks entry type in `mType` and
1578 // invokes sub-class method for type-specific behaviors
1579 // (e.g., query message construction).
1580
1581 public:
1582 void HandleTimer(CacheTimerContext &aContext);
1583 void ClearEmptyCallbacks(void);
1584 void ScheduleQuery(TimeMilli aQueryTime);
1585
1586 protected:
1587 enum Type : uint8_t
1588 {
1589 kBrowseCache,
1590 kSrvCache,
1591 kTxtCache,
1592 kIp6AddrCache,
1593 kIp4AddrCache,
1594 };
1595
1596 void Init(Instance &aInstance, Type aType);
IsActive(void) const1597 bool IsActive(void) const { return mIsActive; }
1598 bool ShouldDelete(TimeMilli aNow) const;
1599 void StartInitialQueries(void);
StopInitialQueries(void)1600 void StopInitialQueries(void) { mInitalQueries = kNumberOfInitalQueries; }
1601 Error Add(const ResultCallback &aCallback);
1602 void Remove(const ResultCallback &aCallback);
1603 void DetermineNextFireTime(void);
1604 void ScheduleTimer(void);
1605
1606 template <typename ResultType> void InvokeCallbacks(const ResultType &aResult);
1607
1608 private:
1609 static constexpr uint32_t kMinIntervalBetweenQueries = 1000; // In msec
1610 static constexpr uint32_t kNonActiveDeleteTimeout = 7 * Time::kOneMinuteInMsec;
1611
1612 typedef OwningList<ResultCallback> CallbackList;
1613
1614 void SetIsActive(bool aIsActive);
1615 bool ShouldQuery(TimeMilli aNow);
1616 void PrepareQuery(CacheTimerContext &aContext);
1617 void ProcessExpiredRecords(TimeMilli aNow);
1618 void DetermineNextInitialQueryTime(void);
1619
1620 ResultCallback *FindCallbackMatching(const ResultCallback &aCallback);
1621
As(void)1622 template <typename CacheType> CacheType &As(void) { return *static_cast<CacheType *>(this); }
As(void) const1623 template <typename CacheType> const CacheType &As(void) const { return *static_cast<const CacheType *>(this); }
1624
1625 Type mType; // Cache entry type.
1626 uint8_t mInitalQueries; // Number initial queries sent already.
1627 bool mQueryPending : 1; // Whether a query tx request is pending.
1628 bool mLastQueryTimeValid : 1; // Whether `mLastQueryTime` is valid.
1629 bool mIsActive : 1; // Whether there is any active resolver/browser for this entry.
1630 TimeMilli mNextQueryTime; // The next query tx time when `mQueryPending`.
1631 TimeMilli mLastQueryTime; // The last query tx time or the upcoming tx time of first initial query.
1632 TimeMilli mDeleteTime; // The time to delete the entry when not `mIsActive`.
1633 CallbackList mCallbacks; // Resolver/Browser callbacks.
1634 };
1635
1636 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1637
1638 class BrowseCache : public CacheEntry, public LinkedListEntry<BrowseCache>, public Heap::Allocatable<BrowseCache>
1639 {
1640 friend class LinkedListEntry<BrowseCache>;
1641 friend class Heap::Allocatable<BrowseCache>;
1642 friend class CacheEntry;
1643
1644 public:
1645 void ClearCompressOffsets(void);
1646 bool Matches(const Name &aFullName) const;
1647 bool Matches(const char *aServiceType, const char *aSubTypeLabel) const;
1648 bool Matches(const Browser &aBrowser) const;
1649 bool Matches(const ExpireChecker &aExpireChecker) const;
1650 Error Add(const Browser &aBrowser);
1651 void Remove(const Browser &aBrowser);
1652 void ProcessResponseRecord(const Message &aMessage, uint16_t aRecordOffset);
1653 #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
1654 void CopyInfoTo(Browser &aBrowser, CacheInfo &aInfo) const;
1655 #endif
1656
1657 private:
1658 struct PtrEntry : public LinkedListEntry<PtrEntry>, public Heap::Allocatable<PtrEntry>
1659 {
1660 Error Init(const char *aServiceInstance);
Matchesot::Dns::Multicast::Core::BrowseCache::PtrEntry1661 bool Matches(const char *aServiceInstance) const { return NameMatch(mServiceInstance, aServiceInstance); }
1662 bool Matches(const ExpireChecker &aExpireChecker) const;
1663 void ConvertTo(BrowseResult &aResult, const BrowseCache &aBrowseCache) const;
1664
1665 PtrEntry *mNext;
1666 Heap::String mServiceInstance;
1667 CacheRecordInfo mRecord;
1668 };
1669
1670 // Called by base class `CacheEntry`
1671 void PreparePtrQuestion(TxMessage &aQuery, TimeMilli aNow);
1672 void UpdateRecordStateAfterQuery(TimeMilli aNow);
1673 void DetermineRecordFireTime(void);
1674 void ProcessExpiredRecords(TimeMilli aNow);
1675 void ReportResultsTo(ResultCallback &aCallback) const;
1676
1677 Error Init(Instance &aInstance, const char *aServiceType, const char *aSubTypeLabel);
1678 Error Init(Instance &aInstance, const Browser &aBrowser);
1679 void AppendServiceTypeOrSubTypeTo(TxMessage &aTxMessage, Section aSection);
1680 void AppendKnownAnswer(TxMessage &aTxMessage, const PtrEntry &aPtrEntry, TimeMilli aNow);
1681 void DiscoverCompressOffsets(void);
1682
1683 BrowseCache *mNext;
1684 Heap::String mServiceType;
1685 Heap::String mSubTypeLabel;
1686 OwningList<PtrEntry> mPtrEntries;
1687 uint16_t mServiceTypeOffset;
1688 uint16_t mSubServiceTypeOffset;
1689 uint16_t mSubServiceNameOffset;
1690 };
1691
1692 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1693
1694 struct ServiceName
1695 {
ServiceNameot::Dns::Multicast::Core::ServiceName1696 ServiceName(const char *aServiceInstance, const char *aServiceType)
1697 : mServiceInstance(aServiceInstance)
1698 , mServiceType(aServiceType)
1699 {
1700 }
1701
1702 const char *mServiceInstance;
1703 const char *mServiceType;
1704 };
1705
1706 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1707
1708 class ServiceCache : public CacheEntry
1709 {
1710 // Base class for `SrvCache` and `TxtCache`, tracking common info
1711 // shared between the two, e.g. service instance/type strings,
1712 // record info, and append state and compression offsets.
1713
1714 friend class CacheEntry;
1715
1716 public:
1717 void ClearCompressOffsets(void);
1718
1719 protected:
1720 ServiceCache(void) = default;
1721
1722 Error Init(Instance &aInstance, Type aType, const char *aServiceInstance, const char *aServiceType);
1723 bool Matches(const Name &aFullName) const;
1724 bool Matches(const char *aServiceInstance, const char *aServiceType) const;
1725 void PrepareQueryQuestion(TxMessage &aQuery, uint16_t aRrType);
1726 void AppendServiceNameTo(TxMessage &aTxMessage, Section aSection);
1727 void UpdateRecordStateAfterQuery(TimeMilli aNow);
1728 void DetermineRecordFireTime(void);
1729 bool ShouldStartInitialQueries(void) const;
1730
1731 CacheRecordInfo mRecord;
1732 Heap::String mServiceInstance;
1733 Heap::String mServiceType;
1734 uint16_t mServiceNameOffset;
1735 uint16_t mServiceTypeOffset;
1736 };
1737
1738 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1739
1740 class SrvCache : public ServiceCache, public LinkedListEntry<SrvCache>, public Heap::Allocatable<SrvCache>
1741 {
1742 friend class LinkedListEntry<SrvCache>;
1743 friend class Heap::Allocatable<SrvCache>;
1744 friend class CacheEntry;
1745 friend class TxtCache;
1746 friend class BrowseCache;
1747
1748 public:
1749 bool Matches(const Name &aFullName) const;
1750 bool Matches(const SrvResolver &aResolver) const;
1751 bool Matches(const ServiceName &aServiceName) const;
1752 bool Matches(const ExpireChecker &aExpireChecker) const;
1753 Error Add(const SrvResolver &aResolver);
1754 void Remove(const SrvResolver &aResolver);
1755 void ProcessResponseRecord(const Message &aMessage, uint16_t aRecordOffset);
1756 #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
1757 void CopyInfoTo(SrvResolver &aResolver, CacheInfo &aInfo) const;
1758 #endif
1759
1760 private:
1761 Error Init(Instance &aInstance, const char *aServiceInstance, const char *aServiceType);
1762 Error Init(Instance &aInstance, const ServiceName &aServiceName);
1763 Error Init(Instance &aInstance, const SrvResolver &aResolver);
1764 void PrepareSrvQuestion(TxMessage &aQuery);
1765 void DiscoverCompressOffsets(void);
1766 void ProcessExpiredRecords(TimeMilli aNow);
1767 void ReportResultTo(ResultCallback &aCallback) const;
1768 void ConvertTo(SrvResult &aResult) const;
1769
1770 SrvCache *mNext;
1771 Heap::String mHostName;
1772 uint16_t mPort;
1773 uint16_t mPriority;
1774 uint16_t mWeight;
1775 };
1776
1777 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1778
1779 class TxtCache : public ServiceCache, public LinkedListEntry<TxtCache>, public Heap::Allocatable<TxtCache>
1780 {
1781 friend class LinkedListEntry<TxtCache>;
1782 friend class Heap::Allocatable<TxtCache>;
1783 friend class CacheEntry;
1784 friend class BrowseCache;
1785
1786 public:
1787 bool Matches(const Name &aFullName) const;
1788 bool Matches(const TxtResolver &aResolver) const;
1789 bool Matches(const ServiceName &aServiceName) const;
1790 bool Matches(const ExpireChecker &aExpireChecker) const;
1791 Error Add(const TxtResolver &aResolver);
1792 void Remove(const TxtResolver &aResolver);
1793 void ProcessResponseRecord(const Message &aMessage, uint16_t aRecordOffset);
1794 #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
1795 void CopyInfoTo(TxtResolver &aResolver, CacheInfo &aInfo) const;
1796 #endif
1797
1798 private:
1799 Error Init(Instance &aInstance, const char *aServiceInstance, const char *aServiceType);
1800 Error Init(Instance &aInstance, const ServiceName &aServiceName);
1801 Error Init(Instance &aInstance, const TxtResolver &aResolver);
1802 void PrepareTxtQuestion(TxMessage &aQuery);
1803 void DiscoverCompressOffsets(void);
1804 void ProcessExpiredRecords(TimeMilli aNow);
1805 void ReportResultTo(ResultCallback &aCallback) const;
1806 void ConvertTo(TxtResult &aResult) const;
1807
1808 TxtCache *mNext;
1809 Heap::Data mTxtData;
1810 };
1811
1812 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1813
1814 class AddrCache : public CacheEntry
1815 {
1816 // Base class for `Ip6AddrCache` and `Ip4AddrCache`, tracking common info
1817 // shared between the two.
1818
1819 friend class CacheEntry;
1820
1821 public:
1822 bool Matches(const Name &aFullName) const;
1823 bool Matches(const char *aName) const;
1824 bool Matches(const AddressResolver &aResolver) const;
1825 bool Matches(const ExpireChecker &aExpireChecker) const;
1826 Error Add(const AddressResolver &aResolver);
1827 void Remove(const AddressResolver &aResolver);
1828 void CommitNewResponseEntries(void);
1829 #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
1830 void CopyInfoTo(AddressResolver &aResolver, CacheInfo &aInfo) const;
1831 #endif
1832
1833 protected:
1834 struct AddrEntry : public LinkedListEntry<AddrEntry>, public Heap::Allocatable<AddrEntry>
1835 {
1836 explicit AddrEntry(const Ip6::Address &aAddress);
Matchesot::Dns::Multicast::Core::AddrCache::AddrEntry1837 bool Matches(const Ip6::Address &aAddress) const { return (mAddress == aAddress); }
1838 bool Matches(const ExpireChecker &aExpireChecker) const;
1839 bool Matches(EmptyChecker aChecker) const;
GetTtlot::Dns::Multicast::Core::AddrCache::AddrEntry1840 uint32_t GetTtl(void) const { return mRecord.GetTtl(); }
1841
1842 AddrEntry *mNext;
1843 Ip6::Address mAddress;
1844 CacheRecordInfo mRecord;
1845 };
1846
1847 // Called by base class `CacheEntry`
1848 void PrepareQueryQuestion(TxMessage &aQuery, uint16_t aRrType);
1849 void UpdateRecordStateAfterQuery(TimeMilli aNow);
1850 void DetermineRecordFireTime(void);
1851 void ProcessExpiredRecords(TimeMilli aNow);
1852 void ReportResultsTo(ResultCallback &aCallback) const;
1853 bool ShouldStartInitialQueries(void) const;
1854
1855 Error Init(Instance &aInstance, Type aType, const char *aHostName);
1856 Error Init(Instance &aInstance, Type aType, const AddressResolver &aResolver);
1857 void AppendNameTo(TxMessage &aTxMessage, Section aSection);
1858 void ConstructResult(AddressResult &aResult, Heap::Array<AddressAndTtl> &aAddrArray) const;
1859 void AddNewResponseAddress(const Ip6::Address &aAddress, uint32_t aTtl, bool aCacheFlush);
1860
1861 AddrCache *mNext;
1862 Heap::String mName;
1863 OwningList<AddrEntry> mCommittedEntries;
1864 OwningList<AddrEntry> mNewEntries;
1865 bool mShouldFlush;
1866 };
1867
1868 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1869
1870 class Ip6AddrCache : public AddrCache, public LinkedListEntry<Ip6AddrCache>, public Heap::Allocatable<Ip6AddrCache>
1871 {
1872 friend class CacheEntry;
1873 friend class LinkedListEntry<Ip6AddrCache>;
1874 friend class Heap::Allocatable<Ip6AddrCache>;
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 PrepareAaaaQuestion(TxMessage &aQuery);
1883 };
1884
1885 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1886
1887 class Ip4AddrCache : public AddrCache, public LinkedListEntry<Ip4AddrCache>, public Heap::Allocatable<Ip4AddrCache>
1888 {
1889 friend class CacheEntry;
1890 friend class LinkedListEntry<Ip4AddrCache>;
1891 friend class Heap::Allocatable<Ip4AddrCache>;
1892
1893 public:
1894 void ProcessResponseRecord(const Message &aMessage, uint16_t aRecordOffset);
1895
1896 private:
1897 Error Init(Instance &aInstance, const char *aHostName);
1898 Error Init(Instance &aInstance, const AddressResolver &aResolver);
1899 void PrepareAQuestion(TxMessage &aQuery);
1900 };
1901
1902 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1903
1904 #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
1905
1906 class EntryIterator : public Iterator, public InstanceLocator, public Heap::Allocatable<EntryIterator>
1907 {
1908 friend class Heap::Allocatable<EntryIterator>;
1909 friend class ServiceEntry;
1910
1911 public:
1912 Error GetNextHost(Host &aHost, EntryState &aState);
1913 Error GetNextService(Service &aService, EntryState &aState);
1914 Error GetNextKey(Key &aKey, EntryState &aState);
1915 Error GetNextBrowser(Browser &aBrowser, CacheInfo &aInfo);
1916 Error GetNextSrvResolver(SrvResolver &aResolver, CacheInfo &aInfo);
1917 Error GetNextTxtResolver(TxtResolver &aResolver, CacheInfo &aInfo);
1918 Error GetNextIp6AddressResolver(AddressResolver &aResolver, CacheInfo &aInfo);
1919 Error GetNextIp4AddressResolver(AddressResolver &aResolver, CacheInfo &aInfo);
1920
1921 private:
1922 static constexpr uint16_t kArrayCapacityIncrement = 32;
1923
1924 enum Type : uint8_t
1925 {
1926 kUnspecified,
1927 kHost,
1928 kService,
1929 kHostKey,
1930 kServiceKey,
1931 kBrowser,
1932 kSrvResolver,
1933 kTxtResolver,
1934 kIp6AddrResolver,
1935 kIp4AddrResolver,
1936 };
1937
1938 explicit EntryIterator(Instance &aInstance);
1939
1940 Type mType;
1941
1942 union
1943 {
1944 const HostEntry *mHostEntry;
1945 const ServiceEntry *mServiceEntry;
1946 const BrowseCache *mBrowseCache;
1947 const SrvCache *mSrvCache;
1948 const TxtCache *mTxtCache;
1949 const Ip6AddrCache *mIp6AddrCache;
1950 const Ip4AddrCache *mIp4AddrCache;
1951 };
1952
1953 Heap::Array<const char *, kArrayCapacityIncrement> mSubTypeArray;
1954 };
1955
1956 #endif // OPENTHREAD_CONFIG_MULTICAST_DNS_ENTRY_ITERATION_API_ENABLE
1957
1958 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1959
1960 template <typename EntryType> OwningList<EntryType> &GetEntryList(void);
1961 template <typename EntryType, typename ItemInfo>
1962 Error Register(const ItemInfo &aItemInfo, RequestId aRequestId, RegisterCallback aCallback);
1963 template <typename EntryType, typename ItemInfo> Error Unregister(const ItemInfo &aItemInfo);
1964
1965 template <typename CacheType> OwningList<CacheType> &GetCacheList(void);
1966 template <typename CacheType, typename BrowserResolverType>
1967 Error Start(const BrowserResolverType &aBrowserOrResolver);
1968 template <typename CacheType, typename BrowserResolverType>
1969 Error Stop(const BrowserResolverType &aBrowserOrResolver);
1970
1971 void InvokeConflictCallback(const char *aName, const char *aServiceType);
1972 void HandleMessage(Message &aMessage, bool aIsUnicast, const AddressInfo &aSenderAddress);
1973 void AddPassiveSrvTxtCache(const char *aServiceInstance, const char *aServiceType);
1974 void AddPassiveIp6AddrCache(const char *aHostName);
1975 TimeMilli RandomizeFirstProbeTxTime(void);
1976 TimeMilli RandomizeInitialQueryTxTime(void);
1977 void RemoveEmptyEntries(void);
1978 void HandleEntryTimer(void);
1979 void HandleEntryTask(void);
1980 void HandleCacheTimer(void);
1981 void HandleCacheTask(void);
1982
IsKeyForService(const Key & aKey)1983 static bool IsKeyForService(const Key &aKey) { return aKey.mServiceType != nullptr; }
1984 static uint32_t DetermineTtl(uint32_t aTtl, uint32_t aDefaultTtl);
1985 static bool NameMatch(const Heap::String &aHeapString, const char *aName);
1986 static bool NameMatch(const Heap::String &aFirst, const Heap::String &aSecond);
1987 static void UpdateCacheFlushFlagIn(ResourceRecord &aResourceRecord, Section aSection);
1988 static void UpdateRecordLengthInMessage(ResourceRecord &aRecord, Message &aMessage, uint16_t aOffset);
1989 static void UpdateCompressOffset(uint16_t &aOffset, uint16_t aNewOffse);
1990 static bool QuestionMatches(uint16_t aQuestionRrType, uint16_t aRrType);
1991 static bool RrClassIsInternetOrAny(uint16_t aRrClass);
1992
1993 using EntryTimer = TimerMilliIn<Core, &Core::HandleEntryTimer>;
1994 using CacheTimer = TimerMilliIn<Core, &Core::HandleCacheTimer>;
1995 using EntryTask = TaskletIn<Core, &Core::HandleEntryTask>;
1996 using CacheTask = TaskletIn<Core, &Core::HandleCacheTask>;
1997
1998 static const char kLocalDomain[]; // "local."
1999 static const char kUdpServiceLabel[]; // "_udp"
2000 static const char kTcpServiceLabel[]; // "_tcp"
2001 static const char kSubServiceLabel[]; // "_sub"
2002 static const char kServicesDnssdLabels[]; // "_services._dns-sd._udp"
2003
2004 bool mIsEnabled;
2005 bool mIsQuestionUnicastAllowed;
2006 uint16_t mMaxMessageSize;
2007 uint32_t mInfraIfIndex;
2008 OwningList<HostEntry> mHostEntries;
2009 OwningList<ServiceEntry> mServiceEntries;
2010 OwningList<ServiceType> mServiceTypes;
2011 MultiPacketRxMessages mMultiPacketRxMessages;
2012 TimeMilli mNextProbeTxTime;
2013 EntryTimer mEntryTimer;
2014 EntryTask mEntryTask;
2015 TxMessageHistory mTxMessageHistory;
2016 ConflictCallback mConflictCallback;
2017
2018 OwningList<BrowseCache> mBrowseCacheList;
2019 OwningList<SrvCache> mSrvCacheList;
2020 OwningList<TxtCache> mTxtCacheList;
2021 OwningList<Ip6AddrCache> mIp6AddrCacheList;
2022 OwningList<Ip4AddrCache> mIp4AddrCacheList;
2023 TimeMilli mNextQueryTxTime;
2024 CacheTimer mCacheTimer;
2025 CacheTask mCacheTask;
2026 };
2027
2028 // Specializations of `Core::GetEntryList()` for `HostEntry` and `ServiceEntry`:
2029
GetEntryList(void)2030 template <> inline OwningList<Core::HostEntry> &Core::GetEntryList<Core::HostEntry>(void) { return mHostEntries; }
2031
GetEntryList(void)2032 template <> inline OwningList<Core::ServiceEntry> &Core::GetEntryList<Core::ServiceEntry>(void)
2033 {
2034 return mServiceEntries;
2035 }
2036
2037 // Specializations of `Core::GetCacheList()`:
2038
GetCacheList(void)2039 template <> inline OwningList<Core::BrowseCache> &Core::GetCacheList<Core::BrowseCache>(void)
2040 {
2041 return mBrowseCacheList;
2042 }
2043
GetCacheList(void)2044 template <> inline OwningList<Core::SrvCache> &Core::GetCacheList<Core::SrvCache>(void) { return mSrvCacheList; }
2045
GetCacheList(void)2046 template <> inline OwningList<Core::TxtCache> &Core::GetCacheList<Core::TxtCache>(void) { return mTxtCacheList; }
2047
GetCacheList(void)2048 template <> inline OwningList<Core::Ip6AddrCache> &Core::GetCacheList<Core::Ip6AddrCache>(void)
2049 {
2050 return mIp6AddrCacheList;
2051 }
2052
GetCacheList(void)2053 template <> inline OwningList<Core::Ip4AddrCache> &Core::GetCacheList<Core::Ip4AddrCache>(void)
2054 {
2055 return mIp4AddrCacheList;
2056 }
2057
2058 } // namespace Multicast
2059 } // namespace Dns
2060
2061 DefineCoreType(otPlatMdnsAddressInfo, Dns::Multicast::Core::AddressInfo);
2062
2063 } // namespace ot
2064
2065 #endif // OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
2066
2067 #endif // MULTICAST_DNS_HPP_
2068