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