xref: /aosp_15_r20/external/ot-br-posix/src/mdns/mdns_mdnssd.cpp (revision 4a64e381480ef79f0532b2421e44e6ee336b8e0d)
1 /*
2  *    Copyright (c) 2018, 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 /**
30  * @file
31  *   This file implements mDNS publisher based on mDNSResponder.
32  */
33 
34 #define OTBR_LOG_TAG "MDNS"
35 
36 #include "mdns/mdns_mdnssd.hpp"
37 
38 #include <algorithm>
39 
40 #include <arpa/inet.h>
41 #include <assert.h>
42 #include <errno.h>
43 #include <inttypes.h>
44 #include <netinet/in.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 
49 #include "common/code_utils.hpp"
50 #include "common/dns_utils.hpp"
51 #include "common/logging.hpp"
52 #include "common/time.hpp"
53 
54 namespace otbr {
55 
56 namespace Mdns {
57 
58 static const char kDomain[] = "local.";
59 
DNSErrorToOtbrError(DNSServiceErrorType aError)60 static otbrError DNSErrorToOtbrError(DNSServiceErrorType aError)
61 {
62     otbrError error;
63 
64     switch (aError)
65     {
66     case kDNSServiceErr_NoError:
67         error = OTBR_ERROR_NONE;
68         break;
69 
70     case kDNSServiceErr_NoSuchKey:
71     case kDNSServiceErr_NoSuchName:
72     case kDNSServiceErr_NoSuchRecord:
73         error = OTBR_ERROR_NOT_FOUND;
74         break;
75 
76     case kDNSServiceErr_Invalid:
77     case kDNSServiceErr_BadParam:
78     case kDNSServiceErr_BadFlags:
79     case kDNSServiceErr_BadInterfaceIndex:
80         error = OTBR_ERROR_INVALID_ARGS;
81         break;
82 
83     case kDNSServiceErr_NameConflict:
84         error = OTBR_ERROR_DUPLICATED;
85         break;
86 
87     case kDNSServiceErr_Unsupported:
88         error = OTBR_ERROR_NOT_IMPLEMENTED;
89         break;
90 
91     case kDNSServiceErr_ServiceNotRunning:
92         error = OTBR_ERROR_INVALID_STATE;
93         break;
94 
95     default:
96         error = OTBR_ERROR_MDNS;
97         break;
98     }
99 
100     return error;
101 }
102 
DNSErrorToString(DNSServiceErrorType aError)103 static const char *DNSErrorToString(DNSServiceErrorType aError)
104 {
105     switch (aError)
106     {
107     case kDNSServiceErr_NoError:
108         return "OK";
109 
110     case kDNSServiceErr_Unknown:
111         // 0xFFFE FFFF
112         return "Unknown";
113 
114     case kDNSServiceErr_NoSuchName:
115         return "No Such Name";
116 
117     case kDNSServiceErr_NoMemory:
118         return "No Memory";
119 
120     case kDNSServiceErr_BadParam:
121         return "Bad Param";
122 
123     case kDNSServiceErr_BadReference:
124         return "Bad Reference";
125 
126     case kDNSServiceErr_BadState:
127         return "Bad State";
128 
129     case kDNSServiceErr_BadFlags:
130         return "Bad Flags";
131 
132     case kDNSServiceErr_Unsupported:
133         return "Unsupported";
134 
135     case kDNSServiceErr_NotInitialized:
136         return "Not Initialized";
137 
138     case kDNSServiceErr_AlreadyRegistered:
139         return "Already Registered";
140 
141     case kDNSServiceErr_NameConflict:
142         return "Name Conflict";
143 
144     case kDNSServiceErr_Invalid:
145         return "Invalid";
146 
147     case kDNSServiceErr_Firewall:
148         return "Firewall";
149 
150     case kDNSServiceErr_Incompatible:
151         // client library incompatible with daemon
152         return "Incompatible";
153 
154     case kDNSServiceErr_BadInterfaceIndex:
155         return "Bad Interface Index";
156 
157     case kDNSServiceErr_Refused:
158         return "Refused";
159 
160     case kDNSServiceErr_NoSuchRecord:
161         return "No Such Record";
162 
163     case kDNSServiceErr_NoAuth:
164         return "No Auth";
165 
166     case kDNSServiceErr_NoSuchKey:
167         return "No Such Key";
168 
169     case kDNSServiceErr_NATTraversal:
170         return "NAT Traversal";
171 
172     case kDNSServiceErr_DoubleNAT:
173         return "Double NAT";
174 
175     case kDNSServiceErr_BadTime:
176         // Codes up to here existed in Tiger
177         return "Bad Time";
178 
179     case kDNSServiceErr_BadSig:
180         return "Bad Sig";
181 
182     case kDNSServiceErr_BadKey:
183         return "Bad Key";
184 
185     case kDNSServiceErr_Transient:
186         return "Transient";
187 
188     case kDNSServiceErr_ServiceNotRunning:
189         // Background daemon not running
190         return "Service Not Running";
191 
192     case kDNSServiceErr_NATPortMappingUnsupported:
193         // NAT doesn't support NAT-PMP or UPnP
194         return "NAT Port Mapping Unsupported";
195 
196     case kDNSServiceErr_NATPortMappingDisabled:
197         // NAT supports NAT-PMP or UPnP but it's disabled by the administrator
198         return "NAT Port Mapping Disabled";
199 
200     case kDNSServiceErr_NoRouter:
201         // No router currently configured (probably no network connectivity)
202         return "No Router";
203 
204     case kDNSServiceErr_PollingMode:
205         return "Polling Mode";
206 
207     case kDNSServiceErr_Timeout:
208         return "Timeout";
209 
210     default:
211         assert(false);
212         return nullptr;
213     }
214 }
215 
PublisherMDnsSd(StateCallback aCallback)216 PublisherMDnsSd::PublisherMDnsSd(StateCallback aCallback)
217     : mHostsRef(nullptr)
218     , mState(State::kIdle)
219     , mStateCallback(std::move(aCallback))
220 {
221 }
222 
~PublisherMDnsSd(void)223 PublisherMDnsSd::~PublisherMDnsSd(void)
224 {
225     Stop(kNormalStop);
226 }
227 
Start(void)228 otbrError PublisherMDnsSd::Start(void)
229 {
230     mState = State::kReady;
231     mStateCallback(State::kReady);
232     return OTBR_ERROR_NONE;
233 }
234 
IsStarted(void) const235 bool PublisherMDnsSd::IsStarted(void) const
236 {
237     return mState == State::kReady;
238 }
239 
Stop(StopMode aStopMode)240 void PublisherMDnsSd::Stop(StopMode aStopMode)
241 {
242     VerifyOrExit(mState == State::kReady);
243 
244     // If we get a `kDNSServiceErr_ServiceNotRunning` and need to
245     // restart the `Publisher`, we should immediately de-allocate
246     // all `ServiceRef`. Otherwise, we first clear the `Registrations`
247     // list so that `DnssdHostRegisteration` destructor gets the chance
248     // to update registered records if needed.
249 
250     switch (aStopMode)
251     {
252     case kNormalStop:
253         break;
254 
255     case kStopOnServiceNotRunningError:
256         DeallocateHostsRef();
257         break;
258     }
259 
260     mServiceRegistrations.clear();
261     mHostRegistrations.clear();
262     mKeyRegistrations.clear();
263     DeallocateHostsRef();
264 
265     mSubscribedServices.clear();
266     mSubscribedHosts.clear();
267 
268     mState = State::kIdle;
269 
270 exit:
271     return;
272 }
273 
CreateSharedHostsRef(void)274 DNSServiceErrorType PublisherMDnsSd::CreateSharedHostsRef(void)
275 {
276     DNSServiceErrorType dnsError = kDNSServiceErr_NoError;
277 
278     VerifyOrExit(mHostsRef == nullptr);
279 
280     dnsError = DNSServiceCreateConnection(&mHostsRef);
281     otbrLogDebug("Created new shared DNSServiceRef: %p", mHostsRef);
282 
283 exit:
284     return dnsError;
285 }
286 
DeallocateHostsRef(void)287 void PublisherMDnsSd::DeallocateHostsRef(void)
288 {
289     VerifyOrExit(mHostsRef != nullptr);
290 
291     HandleServiceRefDeallocating(mHostsRef);
292     DNSServiceRefDeallocate(mHostsRef);
293     otbrLogDebug("Deallocated DNSServiceRef for hosts: %p", mHostsRef);
294     mHostsRef = nullptr;
295 
296 exit:
297     return;
298 }
299 
Update(MainloopContext & aMainloop)300 void PublisherMDnsSd::Update(MainloopContext &aMainloop)
301 {
302     for (auto &kv : mServiceRegistrations)
303     {
304         auto &serviceReg = static_cast<DnssdServiceRegistration &>(*kv.second);
305 
306         serviceReg.Update(aMainloop);
307     }
308 
309     if (mHostsRef != nullptr)
310     {
311         int fd = DNSServiceRefSockFD(mHostsRef);
312 
313         assert(fd != -1);
314 
315         aMainloop.AddFdToReadSet(fd);
316     }
317 
318     for (const auto &service : mSubscribedServices)
319     {
320         service->UpdateAll(aMainloop);
321     }
322 
323     for (const auto &host : mSubscribedHosts)
324     {
325         host->Update(aMainloop);
326     }
327 }
328 
Process(const MainloopContext & aMainloop)329 void PublisherMDnsSd::Process(const MainloopContext &aMainloop)
330 {
331     mServiceRefsToProcess.clear();
332 
333     for (auto &kv : mServiceRegistrations)
334     {
335         auto &serviceReg = static_cast<DnssdServiceRegistration &>(*kv.second);
336 
337         serviceReg.Process(aMainloop, mServiceRefsToProcess);
338     }
339 
340     if (mHostsRef != nullptr)
341     {
342         int fd = DNSServiceRefSockFD(mHostsRef);
343 
344         if (FD_ISSET(fd, &aMainloop.mReadFdSet))
345         {
346             mServiceRefsToProcess.push_back(mHostsRef);
347         }
348     }
349 
350     for (const auto &service : mSubscribedServices)
351     {
352         service->ProcessAll(aMainloop, mServiceRefsToProcess);
353     }
354 
355     for (const auto &host : mSubscribedHosts)
356     {
357         host->Process(aMainloop, mServiceRefsToProcess);
358     }
359 
360     for (DNSServiceRef serviceRef : mServiceRefsToProcess)
361     {
362         DNSServiceErrorType error;
363 
364         // As we go through the list of `mServiceRefsToProcess` the call
365         // to `DNSServiceProcessResult()` can itself invoke callbacks
366         // into `PublisherMDnsSd` and OT, which in turn, may change the
367         // state of `Publisher` and potentially trigger a previously
368         // valid `ServiceRef` in the list to be deallocated. We use
369         // `HandleServiceRefDeallocating()` which is called whenever a
370         // `ServiceRef` is being deallocated and from this we update
371         // the entry in `mServiceRefsToProcess` list to `nullptr` so to
372         // avoid calling `DNSServiceProcessResult()` on an already
373         // freed `ServiceRef`.
374 
375         if (serviceRef == nullptr)
376         {
377             continue;
378         }
379 
380         error = DNSServiceProcessResult(serviceRef);
381 
382         if (error != kDNSServiceErr_NoError)
383         {
384             otbrLogLevel logLevel = (error == kDNSServiceErr_BadReference) ? OTBR_LOG_INFO : OTBR_LOG_WARNING;
385             otbrLog(logLevel, OTBR_LOG_TAG, "DNSServiceProcessResult failed: %s (serviceRef = %p)",
386                     DNSErrorToString(error), serviceRef);
387         }
388         if (error == kDNSServiceErr_ServiceNotRunning)
389         {
390             otbrLogWarning("Need to reconnect to mdnsd");
391             Stop(kStopOnServiceNotRunningError);
392             Start();
393             ExitNow();
394         }
395     }
396 exit:
397     return;
398 }
399 
HandleServiceRefDeallocating(const DNSServiceRef & aServiceRef)400 void PublisherMDnsSd::HandleServiceRefDeallocating(const DNSServiceRef &aServiceRef)
401 {
402     for (DNSServiceRef &entry : mServiceRefsToProcess)
403     {
404         if (entry == aServiceRef)
405         {
406             entry = nullptr;
407         }
408     }
409 }
410 
Update(MainloopContext & aMainloop) const411 void PublisherMDnsSd::DnssdServiceRegistration::Update(MainloopContext &aMainloop) const
412 {
413     int fd;
414 
415     VerifyOrExit(mServiceRef != nullptr);
416 
417     fd = DNSServiceRefSockFD(mServiceRef);
418     VerifyOrExit(fd != -1);
419 
420     aMainloop.AddFdToReadSet(fd);
421 
422 exit:
423     return;
424 }
425 
Process(const MainloopContext & aMainloop,std::vector<DNSServiceRef> & aReadyServices) const426 void PublisherMDnsSd::DnssdServiceRegistration::Process(const MainloopContext      &aMainloop,
427                                                         std::vector<DNSServiceRef> &aReadyServices) const
428 {
429     int fd;
430 
431     VerifyOrExit(mServiceRef != nullptr);
432 
433     fd = DNSServiceRefSockFD(mServiceRef);
434     VerifyOrExit(fd != -1);
435 
436     VerifyOrExit(FD_ISSET(fd, &aMainloop.mReadFdSet));
437     aReadyServices.push_back(mServiceRef);
438 
439 exit:
440     return;
441 }
442 
Register(void)443 otbrError PublisherMDnsSd::DnssdServiceRegistration::Register(void)
444 {
445     std::string           fullHostName;
446     std::string           regType            = MakeRegType(mType, mSubTypeList);
447     const char           *hostNameCString    = nullptr;
448     const char           *serviceNameCString = nullptr;
449     DnssdKeyRegistration *keyReg;
450     DNSServiceErrorType   dnsError;
451 
452     if (!mHostName.empty())
453     {
454         fullHostName    = MakeFullHostName(mHostName);
455         hostNameCString = fullHostName.c_str();
456     }
457 
458     if (!mName.empty())
459     {
460         serviceNameCString = mName.c_str();
461     }
462 
463     keyReg = static_cast<DnssdKeyRegistration *>(GetPublisher().FindKeyRegistration(mName, mType));
464 
465     if (keyReg != nullptr)
466     {
467         keyReg->Unregister();
468     }
469 
470     otbrLogInfo("Registering service %s.%s", mName.c_str(), regType.c_str());
471 
472     dnsError = DNSServiceRegister(&mServiceRef, kDNSServiceFlagsNoAutoRename, kDNSServiceInterfaceIndexAny,
473                                   serviceNameCString, regType.c_str(),
474                                   /* domain */ nullptr, hostNameCString, htons(mPort), mTxtData.size(), mTxtData.data(),
475                                   HandleRegisterResult, this);
476 
477     if (dnsError != kDNSServiceErr_NoError)
478     {
479         HandleRegisterResult(/* aFlags */ 0, dnsError);
480     }
481 
482     if (keyReg != nullptr)
483     {
484         keyReg->Register();
485     }
486 
487     return GetPublisher().DnsErrorToOtbrError(dnsError);
488 }
489 
Unregister(void)490 void PublisherMDnsSd::DnssdServiceRegistration::Unregister(void)
491 {
492     DnssdKeyRegistration *keyReg = mRelatedKeyReg;
493 
494     VerifyOrExit(mServiceRef != nullptr);
495 
496     // If we have a related key registration associated with this
497     // service registration, we first unregister it and after we
498     // deallocated the `mServiceRef` try to register it again
499     // (which will add it as an individual record not tied to a
500     // service registration). Note that the `keyReg->Unregister()`
501     // will clear the `mRelatedKeyReg` field, so we need to keep
502     // a local copy to it in `keyReg`.
503 
504     if (keyReg != nullptr)
505     {
506         keyReg->Unregister();
507     }
508 
509     GetPublisher().HandleServiceRefDeallocating(mServiceRef);
510     DNSServiceRefDeallocate(mServiceRef);
511     mServiceRef = nullptr;
512 
513     if (keyReg != nullptr)
514     {
515         keyReg->Register();
516     }
517 
518 exit:
519     return;
520 }
521 
HandleRegisterResult(DNSServiceRef aServiceRef,DNSServiceFlags aFlags,DNSServiceErrorType aError,const char * aName,const char * aType,const char * aDomain,void * aContext)522 void PublisherMDnsSd::DnssdServiceRegistration::HandleRegisterResult(DNSServiceRef       aServiceRef,
523                                                                      DNSServiceFlags     aFlags,
524                                                                      DNSServiceErrorType aError,
525                                                                      const char         *aName,
526                                                                      const char         *aType,
527                                                                      const char         *aDomain,
528                                                                      void               *aContext)
529 {
530     OTBR_UNUSED_VARIABLE(aServiceRef);
531     OTBR_UNUSED_VARIABLE(aName);
532     OTBR_UNUSED_VARIABLE(aType);
533     OTBR_UNUSED_VARIABLE(aDomain);
534 
535     static_cast<DnssdServiceRegistration *>(aContext)->HandleRegisterResult(aFlags, aError);
536 }
537 
HandleRegisterResult(DNSServiceFlags aFlags,DNSServiceErrorType aError)538 void PublisherMDnsSd::DnssdServiceRegistration::HandleRegisterResult(DNSServiceFlags aFlags, DNSServiceErrorType aError)
539 {
540     if (mRelatedKeyReg != nullptr)
541     {
542         mRelatedKeyReg->HandleRegisterResult(aError);
543     }
544 
545     if ((aError == kDNSServiceErr_NoError) && (aFlags & kDNSServiceFlagsAdd))
546     {
547         otbrLogInfo("Successfully registered service %s.%s", mName.c_str(), mType.c_str());
548         Complete(OTBR_ERROR_NONE);
549     }
550     else
551     {
552         otbrLogErr("Failed to register service %s.%s: %s", mName.c_str(), mType.c_str(), DNSErrorToString(aError));
553         GetPublisher().RemoveServiceRegistration(mName, mType, DNSErrorToOtbrError(aError));
554     }
555 }
556 
Register(void)557 otbrError PublisherMDnsSd::DnssdHostRegistration::Register(void)
558 {
559     DNSServiceErrorType dnsError = kDNSServiceErr_NoError;
560 
561     otbrLogInfo("Registering new host %s", mName.c_str());
562 
563     for (const Ip6Address &address : mAddresses)
564     {
565         DNSRecordRef recordRef = nullptr;
566 
567         dnsError = GetPublisher().CreateSharedHostsRef();
568         VerifyOrExit(dnsError == kDNSServiceErr_NoError);
569 
570         dnsError = DNSServiceRegisterRecord(GetPublisher().mHostsRef, &recordRef, kDNSServiceFlagsShared,
571                                             kDNSServiceInterfaceIndexAny, MakeFullHostName(mName).c_str(),
572                                             kDNSServiceType_AAAA, kDNSServiceClass_IN, sizeof(address.m8), address.m8,
573                                             /* ttl */ 0, HandleRegisterResult, this);
574         VerifyOrExit(dnsError == kDNSServiceErr_NoError);
575 
576         mAddrRecordRefs.push_back(recordRef);
577         mAddrRegistered.push_back(false);
578     }
579 
580 exit:
581     if ((dnsError != kDNSServiceErr_NoError) || mAddresses.empty())
582     {
583         HandleRegisterResult(/* aRecordRef */ nullptr, dnsError);
584     }
585 
586     return GetPublisher().DnsErrorToOtbrError(dnsError);
587 }
588 
Unregister(void)589 void PublisherMDnsSd::DnssdHostRegistration::Unregister(void)
590 {
591     DNSServiceErrorType dnsError;
592 
593     VerifyOrExit(GetPublisher().mHostsRef != nullptr);
594 
595     for (size_t index = 0; index < mAddrRecordRefs.size(); index++)
596     {
597         const Ip6Address &address = mAddresses[index];
598 
599         if (mAddrRegistered[index])
600         {
601             // The Bonjour mDNSResponder somehow doesn't send goodbye message for the AAAA record when it is
602             // removed by `DNSServiceRemoveRecord`. Per RFC 6762, a goodbye message of a record sets its TTL
603             // to zero but the receiver should record the TTL of 1 and flushes the cache 1 second later. Here
604             // we remove the AAAA record after updating its TTL to 1 second. This has the same effect as
605             // sending a goodbye message.
606             // TODO: resolve the goodbye issue with Bonjour mDNSResponder.
607             dnsError = DNSServiceUpdateRecord(GetPublisher().mHostsRef, mAddrRecordRefs[index], kDNSServiceFlagsUnique,
608                                               sizeof(address.m8), address.m8, /* ttl */ 1);
609             otbrLogResult(DNSErrorToOtbrError(dnsError), "Send goodbye message for host %s address %s: %s",
610                           MakeFullHostName(mName).c_str(), address.ToString().c_str(), DNSErrorToString(dnsError));
611         }
612 
613         dnsError = DNSServiceRemoveRecord(GetPublisher().mHostsRef, mAddrRecordRefs[index], /* flags */ 0);
614 
615         otbrLogResult(DNSErrorToOtbrError(dnsError), "Remove record for host %s address %s: %s",
616                       MakeFullHostName(mName).c_str(), address.ToString().c_str(), DNSErrorToString(dnsError));
617     }
618 
619 exit:
620     mAddrRegistered.clear();
621     mAddrRecordRefs.clear();
622 }
623 
HandleRegisterResult(DNSServiceRef aServiceRef,DNSRecordRef aRecordRef,DNSServiceFlags aFlags,DNSServiceErrorType aError,void * aContext)624 void PublisherMDnsSd::DnssdHostRegistration::HandleRegisterResult(DNSServiceRef       aServiceRef,
625                                                                   DNSRecordRef        aRecordRef,
626                                                                   DNSServiceFlags     aFlags,
627                                                                   DNSServiceErrorType aError,
628                                                                   void               *aContext)
629 {
630     OTBR_UNUSED_VARIABLE(aServiceRef);
631     OTBR_UNUSED_VARIABLE(aFlags);
632 
633     static_cast<DnssdHostRegistration *>(aContext)->HandleRegisterResult(aRecordRef, aError);
634 }
635 
HandleRegisterResult(DNSRecordRef aRecordRef,DNSServiceErrorType aError)636 void PublisherMDnsSd::DnssdHostRegistration::HandleRegisterResult(DNSRecordRef aRecordRef, DNSServiceErrorType aError)
637 {
638     if (aError != kDNSServiceErr_NoError)
639     {
640         otbrLogErr("Failed to register host %s: %s", mName.c_str(), DNSErrorToString(aError));
641         GetPublisher().RemoveHostRegistration(mName, DNSErrorToOtbrError(aError));
642     }
643     else
644     {
645         bool shouldComplete = !IsCompleted();
646 
647         for (size_t index = 0; index < mAddrRecordRefs.size(); index++)
648         {
649             if ((mAddrRecordRefs[index] == aRecordRef) && !mAddrRegistered[index])
650             {
651                 mAddrRegistered[index] = true;
652                 otbrLogInfo("Successfully registered host %s address %s", mName.c_str(),
653                             mAddresses[index].ToString().c_str());
654             }
655 
656             if (!mAddrRegistered[index])
657             {
658                 shouldComplete = false;
659             }
660         }
661 
662         if (shouldComplete)
663         {
664             otbrLogInfo("Successfully registered all host %s addresses", mName.c_str());
665             Complete(OTBR_ERROR_NONE);
666         }
667     }
668 }
669 
Register(void)670 otbrError PublisherMDnsSd::DnssdKeyRegistration::Register(void)
671 {
672     DNSServiceErrorType       dnsError = kDNSServiceErr_NoError;
673     DnssdServiceRegistration *serviceReg;
674 
675     otbrLogInfo("Registering new key %s", mName.c_str());
676 
677     serviceReg = static_cast<DnssdServiceRegistration *>(GetPublisher().FindServiceRegistration(mName));
678 
679     if ((serviceReg != nullptr) && (serviceReg->mServiceRef != nullptr))
680     {
681         otbrLogInfo("Key %s is being registered as a record of an existing service registration", mName.c_str());
682 
683         dnsError = DNSServiceAddRecord(serviceReg->mServiceRef, &mRecordRef, kDNSServiceFlagsUnique,
684                                        kDNSServiceType_KEY, mKeyData.size(), mKeyData.data(), /* ttl */ 0);
685 
686         VerifyOrExit(dnsError == kDNSServiceErr_NoError);
687 
688         mRelatedServiceReg         = serviceReg;
689         serviceReg->mRelatedKeyReg = this;
690 
691         if (mRelatedServiceReg->IsCompleted())
692         {
693             HandleRegisterResult(kDNSServiceErr_NoError);
694         }
695 
696         // If related service registration is not yet finished,
697         // we wait for service registration completion to signal
698         // key record registration as well.
699     }
700     else
701     {
702         otbrLogInfo("Key %s is being registered individually", mName.c_str());
703 
704         dnsError = GetPublisher().CreateSharedHostsRef();
705         VerifyOrExit(dnsError == kDNSServiceErr_NoError);
706 
707         dnsError = DNSServiceRegisterRecord(GetPublisher().mHostsRef, &mRecordRef, kDNSServiceFlagsUnique,
708                                             kDNSServiceInterfaceIndexAny, MakeFullKeyName(mName).c_str(),
709                                             kDNSServiceType_KEY, kDNSServiceClass_IN, mKeyData.size(), mKeyData.data(),
710                                             /* ttl */ 0, HandleRegisterResult, this);
711         VerifyOrExit(dnsError == kDNSServiceErr_NoError);
712     }
713 
714 exit:
715     if (dnsError != kDNSServiceErr_NoError)
716     {
717         HandleRegisterResult(dnsError);
718     }
719 
720     return GetPublisher().DnsErrorToOtbrError(dnsError);
721 }
722 
Unregister(void)723 void PublisherMDnsSd::DnssdKeyRegistration::Unregister(void)
724 {
725     DNSServiceErrorType dnsError;
726     DNSServiceRef       serviceRef;
727 
728     VerifyOrExit(mRecordRef != nullptr);
729 
730     if (mRelatedServiceReg != nullptr)
731     {
732         serviceRef = mRelatedServiceReg->mServiceRef;
733 
734         mRelatedServiceReg->mRelatedKeyReg = nullptr;
735         mRelatedServiceReg                 = nullptr;
736 
737         otbrLogInfo("Unregistering key %s (was registered as a record of a service)", mName.c_str());
738     }
739     else
740     {
741         serviceRef = GetPublisher().mHostsRef;
742 
743         otbrLogInfo("Unregistering key %s (was registered individually)", mName.c_str());
744     }
745 
746     VerifyOrExit(serviceRef != nullptr);
747 
748     dnsError = DNSServiceRemoveRecord(serviceRef, mRecordRef, /* flags */ 0);
749 
750     otbrLogInfo("Unregistered key %s: error:%s", mName.c_str(), DNSErrorToString(dnsError));
751 
752 exit:
753     return;
754 }
755 
HandleRegisterResult(DNSServiceRef aServiceRef,DNSRecordRef aRecordRef,DNSServiceFlags aFlags,DNSServiceErrorType aError,void * aContext)756 void PublisherMDnsSd::DnssdKeyRegistration::HandleRegisterResult(DNSServiceRef       aServiceRef,
757                                                                  DNSRecordRef        aRecordRef,
758                                                                  DNSServiceFlags     aFlags,
759                                                                  DNSServiceErrorType aError,
760                                                                  void               *aContext)
761 {
762     OTBR_UNUSED_VARIABLE(aServiceRef);
763     OTBR_UNUSED_VARIABLE(aRecordRef);
764     OTBR_UNUSED_VARIABLE(aFlags);
765 
766     static_cast<DnssdKeyRegistration *>(aContext)->HandleRegisterResult(aError);
767 }
768 
HandleRegisterResult(DNSServiceErrorType aError)769 void PublisherMDnsSd::DnssdKeyRegistration::HandleRegisterResult(DNSServiceErrorType aError)
770 {
771     if (aError != kDNSServiceErr_NoError)
772     {
773         otbrLogErr("Failed to register key %s: %s", mName.c_str(), DNSErrorToString(aError));
774         GetPublisher().RemoveKeyRegistration(mName, DNSErrorToOtbrError(aError));
775     }
776     else
777     {
778         otbrLogInfo("Successfully registered key %s", mName.c_str());
779         Complete(OTBR_ERROR_NONE);
780     }
781 }
782 
PublishServiceImpl(const std::string & aHostName,const std::string & aName,const std::string & aType,const SubTypeList & aSubTypeList,uint16_t aPort,const TxtData & aTxtData,ResultCallback && aCallback)783 otbrError PublisherMDnsSd::PublishServiceImpl(const std::string &aHostName,
784                                               const std::string &aName,
785                                               const std::string &aType,
786                                               const SubTypeList &aSubTypeList,
787                                               uint16_t           aPort,
788                                               const TxtData     &aTxtData,
789                                               ResultCallback   &&aCallback)
790 {
791     otbrError                 error             = OTBR_ERROR_NONE;
792     SubTypeList               sortedSubTypeList = SortSubTypeList(aSubTypeList);
793     std::string               regType           = MakeRegType(aType, sortedSubTypeList);
794     DnssdServiceRegistration *serviceReg;
795 
796     if (mState != State::kReady)
797     {
798         error = OTBR_ERROR_INVALID_STATE;
799         std::move(aCallback)(error);
800         ExitNow();
801     }
802 
803     aCallback = HandleDuplicateServiceRegistration(aHostName, aName, aType, sortedSubTypeList, aPort, aTxtData,
804                                                    std::move(aCallback));
805     VerifyOrExit(!aCallback.IsNull());
806 
807     serviceReg = new DnssdServiceRegistration(aHostName, aName, aType, sortedSubTypeList, aPort, aTxtData,
808                                               std::move(aCallback), this);
809     AddServiceRegistration(std::unique_ptr<DnssdServiceRegistration>(serviceReg));
810 
811     error = serviceReg->Register();
812 
813 exit:
814     return error;
815 }
816 
UnpublishService(const std::string & aName,const std::string & aType,ResultCallback && aCallback)817 void PublisherMDnsSd::UnpublishService(const std::string &aName, const std::string &aType, ResultCallback &&aCallback)
818 {
819     otbrError error = OTBR_ERROR_NONE;
820 
821     VerifyOrExit(mState == Publisher::State::kReady, error = OTBR_ERROR_INVALID_STATE);
822     RemoveServiceRegistration(aName, aType, OTBR_ERROR_ABORTED);
823 
824 exit:
825     std::move(aCallback)(error);
826 }
827 
PublishHostImpl(const std::string & aName,const AddressList & aAddresses,ResultCallback && aCallback)828 otbrError PublisherMDnsSd::PublishHostImpl(const std::string &aName,
829                                            const AddressList &aAddresses,
830                                            ResultCallback   &&aCallback)
831 {
832     otbrError              error = OTBR_ERROR_NONE;
833     DnssdHostRegistration *hostReg;
834 
835     if (mState != State::kReady)
836     {
837         error = OTBR_ERROR_INVALID_STATE;
838         std::move(aCallback)(error);
839         ExitNow();
840     }
841 
842     aCallback = HandleDuplicateHostRegistration(aName, aAddresses, std::move(aCallback));
843     VerifyOrExit(!aCallback.IsNull());
844 
845     hostReg = new DnssdHostRegistration(aName, aAddresses, std::move(aCallback), this);
846     AddHostRegistration(std::unique_ptr<DnssdHostRegistration>(hostReg));
847 
848     error = hostReg->Register();
849 
850 exit:
851     return error;
852 }
853 
UnpublishHost(const std::string & aName,ResultCallback && aCallback)854 void PublisherMDnsSd::UnpublishHost(const std::string &aName, ResultCallback &&aCallback)
855 {
856     otbrError error = OTBR_ERROR_NONE;
857 
858     VerifyOrExit(mState == Publisher::State::kReady, error = OTBR_ERROR_INVALID_STATE);
859     RemoveHostRegistration(aName, OTBR_ERROR_ABORTED);
860 
861 exit:
862     // We may failed to unregister the host from underlying mDNS publishers, but
863     // it usually means that the mDNS publisher is already not functioning. So it's
864     // okay to return success directly since the service is not advertised anyway.
865     std::move(aCallback)(error);
866 }
867 
PublishKeyImpl(const std::string & aName,const KeyData & aKeyData,ResultCallback && aCallback)868 otbrError PublisherMDnsSd::PublishKeyImpl(const std::string &aName, const KeyData &aKeyData, ResultCallback &&aCallback)
869 {
870     otbrError             error = OTBR_ERROR_NONE;
871     DnssdKeyRegistration *keyReg;
872 
873     if (mState != State::kReady)
874     {
875         error = OTBR_ERROR_INVALID_STATE;
876         std::move(aCallback)(error);
877         ExitNow();
878     }
879 
880     aCallback = HandleDuplicateKeyRegistration(aName, aKeyData, std::move(aCallback));
881     VerifyOrExit(!aCallback.IsNull());
882 
883     keyReg = new DnssdKeyRegistration(aName, aKeyData, std::move(aCallback), this);
884     AddKeyRegistration(std::unique_ptr<DnssdKeyRegistration>(keyReg));
885 
886     error = keyReg->Register();
887 
888 exit:
889     return error;
890 }
891 
UnpublishKey(const std::string & aName,ResultCallback && aCallback)892 void PublisherMDnsSd::UnpublishKey(const std::string &aName, ResultCallback &&aCallback)
893 {
894     otbrError error = OTBR_ERROR_NONE;
895 
896     VerifyOrExit(mState == Publisher::State::kReady, error = OTBR_ERROR_INVALID_STATE);
897     RemoveKeyRegistration(aName, OTBR_ERROR_ABORTED);
898 
899 exit:
900     std::move(aCallback)(error);
901 }
902 
903 // See `regtype` parameter of the DNSServiceRegister() function for more information.
MakeRegType(const std::string & aType,SubTypeList aSubTypeList)904 std::string PublisherMDnsSd::MakeRegType(const std::string &aType, SubTypeList aSubTypeList)
905 {
906     std::string regType = aType;
907 
908     std::sort(aSubTypeList.begin(), aSubTypeList.end());
909 
910     for (const auto &subType : aSubTypeList)
911     {
912         regType += "," + subType;
913     }
914 
915     return regType;
916 }
917 
SubscribeService(const std::string & aType,const std::string & aInstanceName)918 void PublisherMDnsSd::SubscribeService(const std::string &aType, const std::string &aInstanceName)
919 {
920     VerifyOrExit(mState == Publisher::State::kReady);
921     mSubscribedServices.push_back(MakeUnique<ServiceSubscription>(*this, aType, aInstanceName));
922 
923     otbrLogInfo("Subscribe service %s.%s (total %zu)", aInstanceName.c_str(), aType.c_str(),
924                 mSubscribedServices.size());
925 
926     if (aInstanceName.empty())
927     {
928         mSubscribedServices.back()->Browse();
929     }
930     else
931     {
932         mSubscribedServices.back()->Resolve(kDNSServiceInterfaceIndexAny, aInstanceName, aType, kDomain);
933     }
934 
935 exit:
936     return;
937 }
938 
UnsubscribeService(const std::string & aType,const std::string & aInstanceName)939 void PublisherMDnsSd::UnsubscribeService(const std::string &aType, const std::string &aInstanceName)
940 {
941     ServiceSubscriptionList::iterator it;
942 
943     VerifyOrExit(mState == Publisher::State::kReady);
944     it = std::find_if(mSubscribedServices.begin(), mSubscribedServices.end(),
945                       [&aType, &aInstanceName](const std::unique_ptr<ServiceSubscription> &aService) {
946                           return aService->mType == aType && aService->mInstanceName == aInstanceName;
947                       });
948     VerifyOrExit(it != mSubscribedServices.end());
949 
950     mSubscribedServices.erase(it);
951 
952     otbrLogInfo("Unsubscribe service %s.%s (left %zu)", aInstanceName.c_str(), aType.c_str(),
953                 mSubscribedServices.size());
954 
955 exit:
956     return;
957 }
958 
OnServiceResolveFailedImpl(const std::string & aType,const std::string & aInstanceName,int32_t aErrorCode)959 void PublisherMDnsSd::OnServiceResolveFailedImpl(const std::string &aType,
960                                                  const std::string &aInstanceName,
961                                                  int32_t            aErrorCode)
962 {
963     otbrLogWarning("Resolve service %s.%s failed: code=%" PRId32, aInstanceName.c_str(), aType.c_str(), aErrorCode);
964 }
965 
OnHostResolveFailedImpl(const std::string & aHostName,int32_t aErrorCode)966 void PublisherMDnsSd::OnHostResolveFailedImpl(const std::string &aHostName, int32_t aErrorCode)
967 {
968     otbrLogWarning("Resolve host %s failed: code=%" PRId32, aHostName.c_str(), aErrorCode);
969 }
970 
DnsErrorToOtbrError(int32_t aErrorCode)971 otbrError PublisherMDnsSd::DnsErrorToOtbrError(int32_t aErrorCode)
972 {
973     return otbr::Mdns::DNSErrorToOtbrError(aErrorCode);
974 }
975 
SubscribeHost(const std::string & aHostName)976 void PublisherMDnsSd::SubscribeHost(const std::string &aHostName)
977 {
978     VerifyOrExit(mState == State::kReady);
979     mSubscribedHosts.push_back(MakeUnique<HostSubscription>(*this, aHostName));
980 
981     otbrLogInfo("Subscribe host %s (total %zu)", aHostName.c_str(), mSubscribedHosts.size());
982 
983     mSubscribedHosts.back()->Resolve();
984 
985 exit:
986     return;
987 }
988 
UnsubscribeHost(const std::string & aHostName)989 void PublisherMDnsSd::UnsubscribeHost(const std::string &aHostName)
990 {
991     HostSubscriptionList ::iterator it;
992 
993     VerifyOrExit(mState == Publisher::State::kReady);
994     it = std::find_if(
995         mSubscribedHosts.begin(), mSubscribedHosts.end(),
996         [&aHostName](const std::unique_ptr<HostSubscription> &aHost) { return aHost->mHostName == aHostName; });
997 
998     VerifyOrExit(it != mSubscribedHosts.end());
999 
1000     mSubscribedHosts.erase(it);
1001 
1002     otbrLogInfo("Unsubscribe host %s (remaining %d)", aHostName.c_str(), mSubscribedHosts.size());
1003 
1004 exit:
1005     return;
1006 }
1007 
Create(StateCallback aCallback)1008 Publisher *Publisher::Create(StateCallback aCallback)
1009 {
1010     return new PublisherMDnsSd(aCallback);
1011 }
1012 
Destroy(Publisher * aPublisher)1013 void Publisher::Destroy(Publisher *aPublisher)
1014 {
1015     delete static_cast<PublisherMDnsSd *>(aPublisher);
1016 }
1017 
Release(void)1018 void PublisherMDnsSd::ServiceRef::Release(void)
1019 {
1020     DeallocateServiceRef();
1021 }
1022 
DeallocateServiceRef(void)1023 void PublisherMDnsSd::ServiceRef::DeallocateServiceRef(void)
1024 {
1025     if (mServiceRef != nullptr)
1026     {
1027         mPublisher.HandleServiceRefDeallocating(mServiceRef);
1028         DNSServiceRefDeallocate(mServiceRef);
1029         mServiceRef = nullptr;
1030     }
1031 }
1032 
Update(MainloopContext & aMainloop) const1033 void PublisherMDnsSd::ServiceRef::Update(MainloopContext &aMainloop) const
1034 {
1035     int fd;
1036 
1037     VerifyOrExit(mServiceRef != nullptr);
1038 
1039     fd = DNSServiceRefSockFD(mServiceRef);
1040     assert(fd != -1);
1041     aMainloop.AddFdToReadSet(fd);
1042 exit:
1043     return;
1044 }
1045 
Process(const MainloopContext & aMainloop,std::vector<DNSServiceRef> & aReadyServices) const1046 void PublisherMDnsSd::ServiceRef::Process(const MainloopContext      &aMainloop,
1047                                           std::vector<DNSServiceRef> &aReadyServices) const
1048 {
1049     int fd;
1050 
1051     VerifyOrExit(mServiceRef != nullptr);
1052 
1053     fd = DNSServiceRefSockFD(mServiceRef);
1054     assert(fd != -1);
1055     if (FD_ISSET(fd, &aMainloop.mReadFdSet))
1056     {
1057         aReadyServices.push_back(mServiceRef);
1058     }
1059 exit:
1060     return;
1061 }
1062 
Browse(void)1063 void PublisherMDnsSd::ServiceSubscription::Browse(void)
1064 {
1065     assert(mServiceRef == nullptr);
1066 
1067     otbrLogInfo("DNSServiceBrowse %s", mType.c_str());
1068     DNSServiceBrowse(&mServiceRef, /* flags */ 0, kDNSServiceInterfaceIndexAny, mType.c_str(),
1069                      /* domain */ nullptr, HandleBrowseResult, this);
1070 }
1071 
HandleBrowseResult(DNSServiceRef aServiceRef,DNSServiceFlags aFlags,uint32_t aInterfaceIndex,DNSServiceErrorType aErrorCode,const char * aInstanceName,const char * aType,const char * aDomain,void * aContext)1072 void PublisherMDnsSd::ServiceSubscription::HandleBrowseResult(DNSServiceRef       aServiceRef,
1073                                                               DNSServiceFlags     aFlags,
1074                                                               uint32_t            aInterfaceIndex,
1075                                                               DNSServiceErrorType aErrorCode,
1076                                                               const char         *aInstanceName,
1077                                                               const char         *aType,
1078                                                               const char         *aDomain,
1079                                                               void               *aContext)
1080 {
1081     static_cast<ServiceSubscription *>(aContext)->HandleBrowseResult(aServiceRef, aFlags, aInterfaceIndex, aErrorCode,
1082                                                                      aInstanceName, aType, aDomain);
1083 }
1084 
HandleBrowseResult(DNSServiceRef aServiceRef,DNSServiceFlags aFlags,uint32_t aInterfaceIndex,DNSServiceErrorType aErrorCode,const char * aInstanceName,const char * aType,const char * aDomain)1085 void PublisherMDnsSd::ServiceSubscription::HandleBrowseResult(DNSServiceRef       aServiceRef,
1086                                                               DNSServiceFlags     aFlags,
1087                                                               uint32_t            aInterfaceIndex,
1088                                                               DNSServiceErrorType aErrorCode,
1089                                                               const char         *aInstanceName,
1090                                                               const char         *aType,
1091                                                               const char         *aDomain)
1092 {
1093     OTBR_UNUSED_VARIABLE(aServiceRef);
1094     OTBR_UNUSED_VARIABLE(aDomain);
1095 
1096     otbrLogInfo("DNSServiceBrowse reply: %s %s.%s inf %" PRIu32 ", flags=%" PRIu32 ", error=%" PRId32,
1097                 aFlags & kDNSServiceFlagsAdd ? "add" : "remove", aInstanceName, aType, aInterfaceIndex, aFlags,
1098                 aErrorCode);
1099 
1100     VerifyOrExit(aErrorCode == kDNSServiceErr_NoError);
1101 
1102     if (aFlags & kDNSServiceFlagsAdd)
1103     {
1104         Resolve(aInterfaceIndex, aInstanceName, aType, aDomain);
1105     }
1106     else
1107     {
1108         mPublisher.OnServiceRemoved(aInterfaceIndex, mType, aInstanceName);
1109     }
1110 
1111 exit:
1112     if (aErrorCode != kDNSServiceErr_NoError)
1113     {
1114         mPublisher.OnServiceResolveFailed(mType, mInstanceName, aErrorCode);
1115         Release();
1116     }
1117 }
1118 
Resolve(uint32_t aInterfaceIndex,const std::string & aInstanceName,const std::string & aType,const std::string & aDomain)1119 void PublisherMDnsSd::ServiceSubscription::Resolve(uint32_t           aInterfaceIndex,
1120                                                    const std::string &aInstanceName,
1121                                                    const std::string &aType,
1122                                                    const std::string &aDomain)
1123 {
1124     mResolvingInstances.push_back(
1125         MakeUnique<ServiceInstanceResolution>(*this, aInstanceName, aType, aDomain, aInterfaceIndex));
1126     mResolvingInstances.back()->Resolve();
1127 }
1128 
UpdateAll(MainloopContext & aMainloop) const1129 void PublisherMDnsSd::ServiceSubscription::UpdateAll(MainloopContext &aMainloop) const
1130 {
1131     Update(aMainloop);
1132 
1133     for (const auto &instance : mResolvingInstances)
1134     {
1135         instance->Update(aMainloop);
1136     }
1137 }
1138 
ProcessAll(const MainloopContext & aMainloop,std::vector<DNSServiceRef> & aReadyServices) const1139 void PublisherMDnsSd::ServiceSubscription::ProcessAll(const MainloopContext      &aMainloop,
1140                                                       std::vector<DNSServiceRef> &aReadyServices) const
1141 {
1142     Process(aMainloop, aReadyServices);
1143 
1144     for (const auto &instance : mResolvingInstances)
1145     {
1146         instance->Process(aMainloop, aReadyServices);
1147     }
1148 }
1149 
Resolve(void)1150 void PublisherMDnsSd::ServiceInstanceResolution::Resolve(void)
1151 {
1152     assert(mServiceRef == nullptr);
1153 
1154     mSubscription->mPublisher.mServiceInstanceResolutionBeginTime[std::make_pair(mInstanceName, mType)] = Clock::now();
1155 
1156     otbrLogInfo("DNSServiceResolve %s %s inf %u", mInstanceName.c_str(), mType.c_str(), mNetifIndex);
1157     DNSServiceResolve(&mServiceRef, /* flags */ kDNSServiceFlagsTimeout, mNetifIndex, mInstanceName.c_str(),
1158                       mType.c_str(), mDomain.c_str(), HandleResolveResult, this);
1159 }
1160 
HandleResolveResult(DNSServiceRef aServiceRef,DNSServiceFlags aFlags,uint32_t aInterfaceIndex,DNSServiceErrorType aErrorCode,const char * aFullName,const char * aHostTarget,uint16_t aPort,uint16_t aTxtLen,const unsigned char * aTxtRecord,void * aContext)1161 void PublisherMDnsSd::ServiceInstanceResolution::HandleResolveResult(DNSServiceRef        aServiceRef,
1162                                                                      DNSServiceFlags      aFlags,
1163                                                                      uint32_t             aInterfaceIndex,
1164                                                                      DNSServiceErrorType  aErrorCode,
1165                                                                      const char          *aFullName,
1166                                                                      const char          *aHostTarget,
1167                                                                      uint16_t             aPort,
1168                                                                      uint16_t             aTxtLen,
1169                                                                      const unsigned char *aTxtRecord,
1170                                                                      void                *aContext)
1171 {
1172     static_cast<ServiceInstanceResolution *>(aContext)->HandleResolveResult(
1173         aServiceRef, aFlags, aInterfaceIndex, aErrorCode, aFullName, aHostTarget, aPort, aTxtLen, aTxtRecord);
1174 }
1175 
HandleResolveResult(DNSServiceRef aServiceRef,DNSServiceFlags aFlags,uint32_t aInterfaceIndex,DNSServiceErrorType aErrorCode,const char * aFullName,const char * aHostTarget,uint16_t aPort,uint16_t aTxtLen,const unsigned char * aTxtRecord)1176 void PublisherMDnsSd::ServiceInstanceResolution::HandleResolveResult(DNSServiceRef        aServiceRef,
1177                                                                      DNSServiceFlags      aFlags,
1178                                                                      uint32_t             aInterfaceIndex,
1179                                                                      DNSServiceErrorType  aErrorCode,
1180                                                                      const char          *aFullName,
1181                                                                      const char          *aHostTarget,
1182                                                                      uint16_t             aPort,
1183                                                                      uint16_t             aTxtLen,
1184                                                                      const unsigned char *aTxtRecord)
1185 {
1186     OTBR_UNUSED_VARIABLE(aServiceRef);
1187 
1188     std::string instanceName, type, domain;
1189     otbrError   error = OTBR_ERROR_NONE;
1190 
1191     otbrLogInfo("DNSServiceResolve reply: %s host %s:%d, TXT=%dB inf %u, flags=%u", aFullName, aHostTarget, aPort,
1192                 aTxtLen, aInterfaceIndex, aFlags);
1193 
1194     VerifyOrExit(aErrorCode == kDNSServiceErr_NoError);
1195 
1196     SuccessOrExit(error = SplitFullServiceInstanceName(aFullName, instanceName, type, domain));
1197 
1198     mInstanceInfo.mNetifIndex = aInterfaceIndex;
1199     mInstanceInfo.mName       = instanceName;
1200     mInstanceInfo.mHostName   = aHostTarget;
1201     mInstanceInfo.mPort       = ntohs(aPort);
1202     mInstanceInfo.mTxtData.assign(aTxtRecord, aTxtRecord + aTxtLen);
1203     // priority and weight are not given in the reply
1204     mInstanceInfo.mPriority = 0;
1205     mInstanceInfo.mWeight   = 0;
1206 
1207     DeallocateServiceRef();
1208     error = GetAddrInfo(aInterfaceIndex);
1209 
1210 exit:
1211     if (error != OTBR_ERROR_NONE)
1212     {
1213         otbrLogWarning("Failed to resolve service instance %s", aFullName);
1214     }
1215 
1216     if (aErrorCode != kDNSServiceErr_NoError || error != OTBR_ERROR_NONE)
1217     {
1218         mSubscription->mPublisher.OnServiceResolveFailed(mSubscription->mType, mInstanceName, aErrorCode);
1219         FinishResolution();
1220     }
1221 }
1222 
GetAddrInfo(uint32_t aInterfaceIndex)1223 otbrError PublisherMDnsSd::ServiceInstanceResolution::GetAddrInfo(uint32_t aInterfaceIndex)
1224 {
1225     DNSServiceErrorType dnsError;
1226 
1227     assert(mServiceRef == nullptr);
1228 
1229     otbrLogInfo("DNSServiceGetAddrInfo %s inf %d", mInstanceInfo.mHostName.c_str(), aInterfaceIndex);
1230 
1231     dnsError = DNSServiceGetAddrInfo(&mServiceRef, /* flags */ 0, aInterfaceIndex,
1232                                      kDNSServiceProtocol_IPv6 | kDNSServiceProtocol_IPv4,
1233                                      mInstanceInfo.mHostName.c_str(), HandleGetAddrInfoResult, this);
1234 
1235     if (dnsError != kDNSServiceErr_NoError)
1236     {
1237         otbrLogWarning("DNSServiceGetAddrInfo failed: %s", DNSErrorToString(dnsError));
1238     }
1239 
1240     return dnsError == kDNSServiceErr_NoError ? OTBR_ERROR_NONE : OTBR_ERROR_MDNS;
1241 }
1242 
HandleGetAddrInfoResult(DNSServiceRef aServiceRef,DNSServiceFlags aFlags,uint32_t aInterfaceIndex,DNSServiceErrorType aErrorCode,const char * aHostName,const struct sockaddr * aAddress,uint32_t aTtl,void * aContext)1243 void PublisherMDnsSd::ServiceInstanceResolution::HandleGetAddrInfoResult(DNSServiceRef          aServiceRef,
1244                                                                          DNSServiceFlags        aFlags,
1245                                                                          uint32_t               aInterfaceIndex,
1246                                                                          DNSServiceErrorType    aErrorCode,
1247                                                                          const char            *aHostName,
1248                                                                          const struct sockaddr *aAddress,
1249                                                                          uint32_t               aTtl,
1250                                                                          void                  *aContext)
1251 {
1252     static_cast<ServiceInstanceResolution *>(aContext)->HandleGetAddrInfoResult(aServiceRef, aFlags, aInterfaceIndex,
1253                                                                                 aErrorCode, aHostName, aAddress, aTtl);
1254 }
1255 
HandleGetAddrInfoResult(DNSServiceRef aServiceRef,DNSServiceFlags aFlags,uint32_t aInterfaceIndex,DNSServiceErrorType aErrorCode,const char * aHostName,const struct sockaddr * aAddress,uint32_t aTtl)1256 void PublisherMDnsSd::ServiceInstanceResolution::HandleGetAddrInfoResult(DNSServiceRef          aServiceRef,
1257                                                                          DNSServiceFlags        aFlags,
1258                                                                          uint32_t               aInterfaceIndex,
1259                                                                          DNSServiceErrorType    aErrorCode,
1260                                                                          const char            *aHostName,
1261                                                                          const struct sockaddr *aAddress,
1262                                                                          uint32_t               aTtl)
1263 {
1264     OTBR_UNUSED_VARIABLE(aServiceRef);
1265     OTBR_UNUSED_VARIABLE(aInterfaceIndex);
1266 
1267     Ip6Address address;
1268     bool       isAdd = (aFlags & kDNSServiceFlagsAdd) != 0;
1269 
1270     otbrLog(aErrorCode == kDNSServiceErr_NoError ? OTBR_LOG_INFO : OTBR_LOG_WARNING, OTBR_LOG_TAG,
1271             "DNSServiceGetAddrInfo reply: flags=%" PRIu32 ", host=%s, sa_family=%u, error=%" PRId32, aFlags, aHostName,
1272             static_cast<unsigned int>(aAddress->sa_family), aErrorCode);
1273 
1274     VerifyOrExit(aErrorCode == kDNSServiceErr_NoError);
1275     VerifyOrExit(aAddress->sa_family == AF_INET6);
1276 
1277     address.CopyFrom(*reinterpret_cast<const struct sockaddr_in6 *>(aAddress));
1278     VerifyOrExit(!address.IsUnspecified() && !address.IsLinkLocal() && !address.IsMulticast() && !address.IsLoopback(),
1279                  otbrLogDebug("DNSServiceGetAddrInfo ignores address %s", address.ToString().c_str()));
1280 
1281     otbrLogInfo("DNSServiceGetAddrInfo reply: %s address=%s, ttl=%" PRIu32, isAdd ? "add" : "remove",
1282                 address.ToString().c_str(), aTtl);
1283 
1284     if (isAdd)
1285     {
1286         mInstanceInfo.AddAddress(address);
1287     }
1288     else
1289     {
1290         mInstanceInfo.RemoveAddress(address);
1291     }
1292     mInstanceInfo.mTtl = aTtl;
1293 
1294 exit:
1295     if (!mInstanceInfo.mAddresses.empty() || aErrorCode != kDNSServiceErr_NoError)
1296     {
1297         FinishResolution();
1298     }
1299 }
1300 
FinishResolution(void)1301 void PublisherMDnsSd::ServiceInstanceResolution::FinishResolution(void)
1302 {
1303     ServiceSubscription   *subscription = mSubscription;
1304     std::string            serviceName  = mSubscription->mType;
1305     DiscoveredInstanceInfo instanceInfo = mInstanceInfo;
1306 
1307     // NOTE: The `ServiceSubscription` object may be freed in `OnServiceResolved`.
1308     subscription->mPublisher.OnServiceResolved(serviceName, instanceInfo);
1309 }
1310 
Resolve(void)1311 void PublisherMDnsSd::HostSubscription::Resolve(void)
1312 {
1313     std::string fullHostName = MakeFullHostName(mHostName);
1314 
1315     assert(mServiceRef == nullptr);
1316 
1317     mPublisher.mHostResolutionBeginTime[mHostName] = Clock::now();
1318 
1319     otbrLogInfo("DNSServiceGetAddrInfo %s inf %d", fullHostName.c_str(), kDNSServiceInterfaceIndexAny);
1320 
1321     DNSServiceGetAddrInfo(&mServiceRef, /* flags */ 0, kDNSServiceInterfaceIndexAny,
1322                           kDNSServiceProtocol_IPv6 | kDNSServiceProtocol_IPv4, fullHostName.c_str(),
1323                           HandleResolveResult, this);
1324 }
1325 
HandleResolveResult(DNSServiceRef aServiceRef,DNSServiceFlags aFlags,uint32_t aInterfaceIndex,DNSServiceErrorType aErrorCode,const char * aHostName,const struct sockaddr * aAddress,uint32_t aTtl,void * aContext)1326 void PublisherMDnsSd::HostSubscription::HandleResolveResult(DNSServiceRef          aServiceRef,
1327                                                             DNSServiceFlags        aFlags,
1328                                                             uint32_t               aInterfaceIndex,
1329                                                             DNSServiceErrorType    aErrorCode,
1330                                                             const char            *aHostName,
1331                                                             const struct sockaddr *aAddress,
1332                                                             uint32_t               aTtl,
1333                                                             void                  *aContext)
1334 {
1335     static_cast<HostSubscription *>(aContext)->HandleResolveResult(aServiceRef, aFlags, aInterfaceIndex, aErrorCode,
1336                                                                    aHostName, aAddress, aTtl);
1337 }
1338 
HandleResolveResult(DNSServiceRef aServiceRef,DNSServiceFlags aFlags,uint32_t aInterfaceIndex,DNSServiceErrorType aErrorCode,const char * aHostName,const struct sockaddr * aAddress,uint32_t aTtl)1339 void PublisherMDnsSd::HostSubscription::HandleResolveResult(DNSServiceRef          aServiceRef,
1340                                                             DNSServiceFlags        aFlags,
1341                                                             uint32_t               aInterfaceIndex,
1342                                                             DNSServiceErrorType    aErrorCode,
1343                                                             const char            *aHostName,
1344                                                             const struct sockaddr *aAddress,
1345                                                             uint32_t               aTtl)
1346 {
1347     OTBR_UNUSED_VARIABLE(aServiceRef);
1348 
1349     Ip6Address address;
1350     bool       isAdd = (aFlags & kDNSServiceFlagsAdd) != 0;
1351 
1352     otbrLog(aErrorCode == kDNSServiceErr_NoError ? OTBR_LOG_INFO : OTBR_LOG_WARNING, OTBR_LOG_TAG,
1353             "DNSServiceGetAddrInfo reply: flags=%" PRIu32 ", host=%s, sa_family=%u, error=%" PRId32, aFlags, aHostName,
1354             static_cast<unsigned int>(aAddress->sa_family), aErrorCode);
1355 
1356     VerifyOrExit(aErrorCode == kDNSServiceErr_NoError);
1357     VerifyOrExit(aAddress->sa_family == AF_INET6);
1358 
1359     address.CopyFrom(*reinterpret_cast<const struct sockaddr_in6 *>(aAddress));
1360     VerifyOrExit(!address.IsLinkLocal(),
1361                  otbrLogDebug("DNSServiceGetAddrInfo ignore link-local address %s", address.ToString().c_str()));
1362 
1363     otbrLogInfo("DNSServiceGetAddrInfo reply: %s address=%s, ttl=%" PRIu32, isAdd ? "add" : "remove",
1364                 address.ToString().c_str(), aTtl);
1365 
1366     if (isAdd)
1367     {
1368         mHostInfo.AddAddress(address);
1369     }
1370     else
1371     {
1372         mHostInfo.RemoveAddress(address);
1373     }
1374     mHostInfo.mHostName   = aHostName;
1375     mHostInfo.mNetifIndex = aInterfaceIndex;
1376     mHostInfo.mTtl        = aTtl;
1377 
1378     // NOTE: This `HostSubscription` object may be freed in `OnHostResolved`.
1379     mPublisher.OnHostResolved(mHostName, mHostInfo);
1380 
1381 exit:
1382     if (aErrorCode != kDNSServiceErr_NoError)
1383     {
1384         mPublisher.OnHostResolveFailed(aHostName, aErrorCode);
1385     }
1386 }
1387 
1388 } // namespace Mdns
1389 
1390 } // namespace otbr
1391