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