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