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