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