• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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         FD_SET(fd, &aMainloop.mReadFdSet);
316 
317         aMainloop.mMaxFd = std::max(aMainloop.mMaxFd, fd);
318     }
319 
320     for (const auto &service : mSubscribedServices)
321     {
322         service->UpdateAll(aMainloop);
323     }
324 
325     for (const auto &host : mSubscribedHosts)
326     {
327         host->Update(aMainloop);
328     }
329 }
330 
Process(const MainloopContext & aMainloop)331 void PublisherMDnsSd::Process(const MainloopContext &aMainloop)
332 {
333     mServiceRefsToProcess.clear();
334 
335     for (auto &kv : mServiceRegistrations)
336     {
337         auto &serviceReg = static_cast<DnssdServiceRegistration &>(*kv.second);
338 
339         serviceReg.Process(aMainloop, mServiceRefsToProcess);
340     }
341 
342     if (mHostsRef != nullptr)
343     {
344         int fd = DNSServiceRefSockFD(mHostsRef);
345 
346         if (FD_ISSET(fd, &aMainloop.mReadFdSet))
347         {
348             mServiceRefsToProcess.push_back(mHostsRef);
349         }
350     }
351 
352     for (const auto &service : mSubscribedServices)
353     {
354         service->ProcessAll(aMainloop, mServiceRefsToProcess);
355     }
356 
357     for (const auto &host : mSubscribedHosts)
358     {
359         host->Process(aMainloop, mServiceRefsToProcess);
360     }
361 
362     for (DNSServiceRef serviceRef : mServiceRefsToProcess)
363     {
364         DNSServiceErrorType error;
365 
366         // As we go through the list of `mServiceRefsToProcess` the call
367         // to `DNSServiceProcessResult()` can itself invoke callbacks
368         // into `PublisherMDnsSd` and OT, which in turn, may change the
369         // state of `Publisher` and potentially trigger a previously
370         // valid `ServiceRef` in the list to be deallocated. We use
371         // `HandleServiceRefDeallocating()` which is called whenever a
372         // `ServiceRef` is being deallocated and from this we update
373         // the entry in `mServiceRefsToProcess` list to `nullptr` so to
374         // avoid calling `DNSServiceProcessResult()` on an already
375         // freed `ServiceRef`.
376 
377         if (serviceRef == nullptr)
378         {
379             continue;
380         }
381 
382         error = DNSServiceProcessResult(serviceRef);
383 
384         if (error != kDNSServiceErr_NoError)
385         {
386             otbrLogLevel logLevel = (error == kDNSServiceErr_BadReference) ? OTBR_LOG_INFO : OTBR_LOG_WARNING;
387             otbrLog(logLevel, OTBR_LOG_TAG, "DNSServiceProcessResult failed: %s (serviceRef = %p)",
388                     DNSErrorToString(error), serviceRef);
389         }
390         if (error == kDNSServiceErr_ServiceNotRunning)
391         {
392             otbrLogWarning("Need to reconnect to mdnsd");
393             Stop(kStopOnServiceNotRunningError);
394             Start();
395             ExitNow();
396         }
397     }
398 exit:
399     return;
400 }
401 
HandleServiceRefDeallocating(const DNSServiceRef & aServiceRef)402 void PublisherMDnsSd::HandleServiceRefDeallocating(const DNSServiceRef &aServiceRef)
403 {
404     for (DNSServiceRef &entry : mServiceRefsToProcess)
405     {
406         if (entry == aServiceRef)
407         {
408             entry = nullptr;
409         }
410     }
411 }
412 
Update(MainloopContext & aMainloop) const413 void PublisherMDnsSd::DnssdServiceRegistration::Update(MainloopContext &aMainloop) const
414 {
415     int fd;
416 
417     VerifyOrExit(mServiceRef != nullptr);
418 
419     fd = DNSServiceRefSockFD(mServiceRef);
420     VerifyOrExit(fd != -1);
421 
422     FD_SET(fd, &aMainloop.mReadFdSet);
423     aMainloop.mMaxFd = std::max(aMainloop.mMaxFd, fd);
424 
425 exit:
426     return;
427 }
428 
Process(const MainloopContext & aMainloop,std::vector<DNSServiceRef> & aReadyServices) const429 void PublisherMDnsSd::DnssdServiceRegistration::Process(const MainloopContext      &aMainloop,
430                                                         std::vector<DNSServiceRef> &aReadyServices) const
431 {
432     int fd;
433 
434     VerifyOrExit(mServiceRef != nullptr);
435 
436     fd = DNSServiceRefSockFD(mServiceRef);
437     VerifyOrExit(fd != -1);
438 
439     VerifyOrExit(FD_ISSET(fd, &aMainloop.mReadFdSet));
440     aReadyServices.push_back(mServiceRef);
441 
442 exit:
443     return;
444 }
445 
Register(void)446 otbrError PublisherMDnsSd::DnssdServiceRegistration::Register(void)
447 {
448     std::string           fullHostName;
449     std::string           regType            = MakeRegType(mType, mSubTypeList);
450     const char           *hostNameCString    = nullptr;
451     const char           *serviceNameCString = nullptr;
452     DnssdKeyRegistration *keyReg;
453     DNSServiceErrorType   dnsError;
454 
455     if (!mHostName.empty())
456     {
457         fullHostName    = MakeFullHostName(mHostName);
458         hostNameCString = fullHostName.c_str();
459     }
460 
461     if (!mName.empty())
462     {
463         serviceNameCString = mName.c_str();
464     }
465 
466     keyReg = static_cast<DnssdKeyRegistration *>(GetPublisher().FindKeyRegistration(mName, mType));
467 
468     if (keyReg != nullptr)
469     {
470         keyReg->Unregister();
471     }
472 
473     otbrLogInfo("Registering service %s.%s", mName.c_str(), regType.c_str());
474 
475     dnsError = DNSServiceRegister(&mServiceRef, kDNSServiceFlagsNoAutoRename, kDNSServiceInterfaceIndexAny,
476                                   serviceNameCString, regType.c_str(),
477                                   /* domain */ nullptr, hostNameCString, htons(mPort), mTxtData.size(), mTxtData.data(),
478                                   HandleRegisterResult, this);
479 
480     if (dnsError != kDNSServiceErr_NoError)
481     {
482         HandleRegisterResult(/* aFlags */ 0, dnsError);
483     }
484 
485     if (keyReg != nullptr)
486     {
487         keyReg->Register();
488     }
489 
490     return GetPublisher().DnsErrorToOtbrError(dnsError);
491 }
492 
Unregister(void)493 void PublisherMDnsSd::DnssdServiceRegistration::Unregister(void)
494 {
495     DnssdKeyRegistration *keyReg = mRelatedKeyReg;
496 
497     VerifyOrExit(mServiceRef != nullptr);
498 
499     // If we have a related key registration associated with this
500     // service registration, we first unregister it and after we
501     // deallocated the `mServiceRef` try to register it again
502     // (which will add it as an individual record not tied to a
503     // service registration). Note that the `keyReg->Unregister()`
504     // will clear the `mRelatedKeyReg` field, so we need to keep
505     // a local copy to it in `keyReg`.
506 
507     if (keyReg != nullptr)
508     {
509         keyReg->Unregister();
510     }
511 
512     GetPublisher().HandleServiceRefDeallocating(mServiceRef);
513     DNSServiceRefDeallocate(mServiceRef);
514     mServiceRef = nullptr;
515 
516     if (keyReg != nullptr)
517     {
518         keyReg->Register();
519     }
520 
521 exit:
522     return;
523 }
524 
HandleRegisterResult(DNSServiceRef aServiceRef,DNSServiceFlags aFlags,DNSServiceErrorType aError,const char * aName,const char * aType,const char * aDomain,void * aContext)525 void PublisherMDnsSd::DnssdServiceRegistration::HandleRegisterResult(DNSServiceRef       aServiceRef,
526                                                                      DNSServiceFlags     aFlags,
527                                                                      DNSServiceErrorType aError,
528                                                                      const char         *aName,
529                                                                      const char         *aType,
530                                                                      const char         *aDomain,
531                                                                      void               *aContext)
532 {
533     OTBR_UNUSED_VARIABLE(aServiceRef);
534     OTBR_UNUSED_VARIABLE(aName);
535     OTBR_UNUSED_VARIABLE(aType);
536     OTBR_UNUSED_VARIABLE(aDomain);
537 
538     static_cast<DnssdServiceRegistration *>(aContext)->HandleRegisterResult(aFlags, aError);
539 }
540 
HandleRegisterResult(DNSServiceFlags aFlags,DNSServiceErrorType aError)541 void PublisherMDnsSd::DnssdServiceRegistration::HandleRegisterResult(DNSServiceFlags aFlags, DNSServiceErrorType aError)
542 {
543     if (mRelatedKeyReg != nullptr)
544     {
545         mRelatedKeyReg->HandleRegisterResult(aError);
546     }
547 
548     if ((aError == kDNSServiceErr_NoError) && (aFlags & kDNSServiceFlagsAdd))
549     {
550         otbrLogInfo("Successfully registered service %s.%s", mName.c_str(), mType.c_str());
551         Complete(OTBR_ERROR_NONE);
552     }
553     else
554     {
555         otbrLogErr("Failed to register service %s.%s: %s", mName.c_str(), mType.c_str(), DNSErrorToString(aError));
556         GetPublisher().RemoveServiceRegistration(mName, mType, DNSErrorToOtbrError(aError));
557     }
558 }
559 
Register(void)560 otbrError PublisherMDnsSd::DnssdHostRegistration::Register(void)
561 {
562     DNSServiceErrorType dnsError = kDNSServiceErr_NoError;
563 
564     otbrLogInfo("Registering new host %s", mName.c_str());
565 
566     for (const Ip6Address &address : mAddresses)
567     {
568         DNSRecordRef recordRef = nullptr;
569 
570         dnsError = GetPublisher().CreateSharedHostsRef();
571         VerifyOrExit(dnsError == kDNSServiceErr_NoError);
572 
573         dnsError = DNSServiceRegisterRecord(GetPublisher().mHostsRef, &recordRef, kDNSServiceFlagsShared,
574                                             kDNSServiceInterfaceIndexAny, MakeFullHostName(mName).c_str(),
575                                             kDNSServiceType_AAAA, kDNSServiceClass_IN, sizeof(address.m8), address.m8,
576                                             /* ttl */ 0, HandleRegisterResult, this);
577         VerifyOrExit(dnsError == kDNSServiceErr_NoError);
578 
579         mAddrRecordRefs.push_back(recordRef);
580         mAddrRegistered.push_back(false);
581     }
582 
583 exit:
584     if ((dnsError != kDNSServiceErr_NoError) || mAddresses.empty())
585     {
586         HandleRegisterResult(/* aRecordRef */ nullptr, dnsError);
587     }
588 
589     return GetPublisher().DnsErrorToOtbrError(dnsError);
590 }
591 
Unregister(void)592 void PublisherMDnsSd::DnssdHostRegistration::Unregister(void)
593 {
594     DNSServiceErrorType dnsError;
595 
596     VerifyOrExit(GetPublisher().mHostsRef != nullptr);
597 
598     for (size_t index = 0; index < mAddrRecordRefs.size(); index++)
599     {
600         const Ip6Address &address = mAddresses[index];
601 
602         if (mAddrRegistered[index])
603         {
604             // The Bonjour mDNSResponder somehow doesn't send goodbye message for the AAAA record when it is
605             // removed by `DNSServiceRemoveRecord`. Per RFC 6762, a goodbye message of a record sets its TTL
606             // to zero but the receiver should record the TTL of 1 and flushes the cache 1 second later. Here
607             // we remove the AAAA record after updating its TTL to 1 second. This has the same effect as
608             // sending a goodbye message.
609             // TODO: resolve the goodbye issue with Bonjour mDNSResponder.
610             dnsError = DNSServiceUpdateRecord(GetPublisher().mHostsRef, mAddrRecordRefs[index], kDNSServiceFlagsUnique,
611                                               sizeof(address.m8), address.m8, /* ttl */ 1);
612             otbrLogResult(DNSErrorToOtbrError(dnsError), "Send goodbye message for host %s address %s: %s",
613                           MakeFullHostName(mName).c_str(), address.ToString().c_str(), DNSErrorToString(dnsError));
614         }
615 
616         dnsError = DNSServiceRemoveRecord(GetPublisher().mHostsRef, mAddrRecordRefs[index], /* flags */ 0);
617 
618         otbrLogResult(DNSErrorToOtbrError(dnsError), "Remove record for host %s address %s: %s",
619                       MakeFullHostName(mName).c_str(), address.ToString().c_str(), DNSErrorToString(dnsError));
620     }
621 
622 exit:
623     mAddrRegistered.clear();
624     mAddrRecordRefs.clear();
625 }
626 
HandleRegisterResult(DNSServiceRef aServiceRef,DNSRecordRef aRecordRef,DNSServiceFlags aFlags,DNSServiceErrorType aError,void * aContext)627 void PublisherMDnsSd::DnssdHostRegistration::HandleRegisterResult(DNSServiceRef       aServiceRef,
628                                                                   DNSRecordRef        aRecordRef,
629                                                                   DNSServiceFlags     aFlags,
630                                                                   DNSServiceErrorType aError,
631                                                                   void               *aContext)
632 {
633     OTBR_UNUSED_VARIABLE(aServiceRef);
634     OTBR_UNUSED_VARIABLE(aFlags);
635 
636     static_cast<DnssdHostRegistration *>(aContext)->HandleRegisterResult(aRecordRef, aError);
637 }
638 
HandleRegisterResult(DNSRecordRef aRecordRef,DNSServiceErrorType aError)639 void PublisherMDnsSd::DnssdHostRegistration::HandleRegisterResult(DNSRecordRef aRecordRef, DNSServiceErrorType aError)
640 {
641     if (aError != kDNSServiceErr_NoError)
642     {
643         otbrLogErr("Failed to register host %s: %s", mName.c_str(), DNSErrorToString(aError));
644         GetPublisher().RemoveHostRegistration(mName, DNSErrorToOtbrError(aError));
645     }
646     else
647     {
648         bool shouldComplete = !IsCompleted();
649 
650         for (size_t index = 0; index < mAddrRecordRefs.size(); index++)
651         {
652             if ((mAddrRecordRefs[index] == aRecordRef) && !mAddrRegistered[index])
653             {
654                 mAddrRegistered[index] = true;
655                 otbrLogInfo("Successfully registered host %s address %s", mName.c_str(),
656                             mAddresses[index].ToString().c_str());
657             }
658 
659             if (!mAddrRegistered[index])
660             {
661                 shouldComplete = false;
662             }
663         }
664 
665         if (shouldComplete)
666         {
667             otbrLogInfo("Successfully registered all host %s addresses", mName.c_str());
668             Complete(OTBR_ERROR_NONE);
669         }
670     }
671 }
672 
Register(void)673 otbrError PublisherMDnsSd::DnssdKeyRegistration::Register(void)
674 {
675     DNSServiceErrorType       dnsError = kDNSServiceErr_NoError;
676     DnssdServiceRegistration *serviceReg;
677 
678     otbrLogInfo("Registering new key %s", mName.c_str());
679 
680     serviceReg = static_cast<DnssdServiceRegistration *>(GetPublisher().FindServiceRegistration(mName));
681 
682     if ((serviceReg != nullptr) && (serviceReg->mServiceRef != nullptr))
683     {
684         otbrLogInfo("Key %s is being registered as a record of an existing service registration", mName.c_str());
685 
686         dnsError = DNSServiceAddRecord(serviceReg->mServiceRef, &mRecordRef, kDNSServiceFlagsUnique,
687                                        kDNSServiceType_KEY, mKeyData.size(), mKeyData.data(), /* ttl */ 0);
688 
689         VerifyOrExit(dnsError == kDNSServiceErr_NoError);
690 
691         mRelatedServiceReg         = serviceReg;
692         serviceReg->mRelatedKeyReg = this;
693 
694         if (mRelatedServiceReg->IsCompleted())
695         {
696             HandleRegisterResult(kDNSServiceErr_NoError);
697         }
698 
699         // If related service registration is not yet finished,
700         // we wait for service registration completion to signal
701         // key record registration as well.
702     }
703     else
704     {
705         otbrLogInfo("Key %s is being registered individually", mName.c_str());
706 
707         dnsError = GetPublisher().CreateSharedHostsRef();
708         VerifyOrExit(dnsError == kDNSServiceErr_NoError);
709 
710         dnsError = DNSServiceRegisterRecord(GetPublisher().mHostsRef, &mRecordRef, kDNSServiceFlagsUnique,
711                                             kDNSServiceInterfaceIndexAny, MakeFullKeyName(mName).c_str(),
712                                             kDNSServiceType_KEY, kDNSServiceClass_IN, mKeyData.size(), mKeyData.data(),
713                                             /* ttl */ 0, HandleRegisterResult, this);
714         VerifyOrExit(dnsError == kDNSServiceErr_NoError);
715     }
716 
717 exit:
718     if (dnsError != kDNSServiceErr_NoError)
719     {
720         HandleRegisterResult(dnsError);
721     }
722 
723     return GetPublisher().DnsErrorToOtbrError(dnsError);
724 }
725 
Unregister(void)726 void PublisherMDnsSd::DnssdKeyRegistration::Unregister(void)
727 {
728     DNSServiceErrorType dnsError;
729     DNSServiceRef       serviceRef;
730 
731     VerifyOrExit(mRecordRef != nullptr);
732 
733     if (mRelatedServiceReg != nullptr)
734     {
735         serviceRef = mRelatedServiceReg->mServiceRef;
736 
737         mRelatedServiceReg->mRelatedKeyReg = nullptr;
738         mRelatedServiceReg                 = nullptr;
739 
740         otbrLogInfo("Unregistering key %s (was registered as a record of a service)", mName.c_str());
741     }
742     else
743     {
744         serviceRef = GetPublisher().mHostsRef;
745 
746         otbrLogInfo("Unregistering key %s (was registered individually)", mName.c_str());
747     }
748 
749     VerifyOrExit(serviceRef != nullptr);
750 
751     dnsError = DNSServiceRemoveRecord(serviceRef, mRecordRef, /* flags */ 0);
752 
753     otbrLogInfo("Unregistered key %s: error:%s", mName.c_str(), DNSErrorToString(dnsError));
754 
755 exit:
756     return;
757 }
758 
HandleRegisterResult(DNSServiceRef aServiceRef,DNSRecordRef aRecordRef,DNSServiceFlags aFlags,DNSServiceErrorType aError,void * aContext)759 void PublisherMDnsSd::DnssdKeyRegistration::HandleRegisterResult(DNSServiceRef       aServiceRef,
760                                                                  DNSRecordRef        aRecordRef,
761                                                                  DNSServiceFlags     aFlags,
762                                                                  DNSServiceErrorType aError,
763                                                                  void               *aContext)
764 {
765     OTBR_UNUSED_VARIABLE(aServiceRef);
766     OTBR_UNUSED_VARIABLE(aRecordRef);
767     OTBR_UNUSED_VARIABLE(aFlags);
768 
769     static_cast<DnssdKeyRegistration *>(aContext)->HandleRegisterResult(aError);
770 }
771 
HandleRegisterResult(DNSServiceErrorType aError)772 void PublisherMDnsSd::DnssdKeyRegistration::HandleRegisterResult(DNSServiceErrorType aError)
773 {
774     if (aError != kDNSServiceErr_NoError)
775     {
776         otbrLogErr("Failed to register key %s: %s", mName.c_str(), DNSErrorToString(aError));
777         GetPublisher().RemoveKeyRegistration(mName, DNSErrorToOtbrError(aError));
778     }
779     else
780     {
781         otbrLogInfo("Successfully registered key %s", mName.c_str());
782         Complete(OTBR_ERROR_NONE);
783     }
784 }
785 
PublishServiceImpl(const std::string & aHostName,const std::string & aName,const std::string & aType,const SubTypeList & aSubTypeList,uint16_t aPort,const TxtData & aTxtData,ResultCallback && aCallback)786 otbrError PublisherMDnsSd::PublishServiceImpl(const std::string &aHostName,
787                                               const std::string &aName,
788                                               const std::string &aType,
789                                               const SubTypeList &aSubTypeList,
790                                               uint16_t           aPort,
791                                               const TxtData     &aTxtData,
792                                               ResultCallback   &&aCallback)
793 {
794     otbrError                 error             = OTBR_ERROR_NONE;
795     SubTypeList               sortedSubTypeList = SortSubTypeList(aSubTypeList);
796     std::string               regType           = MakeRegType(aType, sortedSubTypeList);
797     DnssdServiceRegistration *serviceReg;
798 
799     if (mState != State::kReady)
800     {
801         error = OTBR_ERROR_INVALID_STATE;
802         std::move(aCallback)(error);
803         ExitNow();
804     }
805 
806     aCallback = HandleDuplicateServiceRegistration(aHostName, aName, aType, sortedSubTypeList, aPort, aTxtData,
807                                                    std::move(aCallback));
808     VerifyOrExit(!aCallback.IsNull());
809 
810     serviceReg = new DnssdServiceRegistration(aHostName, aName, aType, sortedSubTypeList, aPort, aTxtData,
811                                               std::move(aCallback), this);
812     AddServiceRegistration(std::unique_ptr<DnssdServiceRegistration>(serviceReg));
813 
814     error = serviceReg->Register();
815 
816 exit:
817     return error;
818 }
819 
UnpublishService(const std::string & aName,const std::string & aType,ResultCallback && aCallback)820 void PublisherMDnsSd::UnpublishService(const std::string &aName, const std::string &aType, ResultCallback &&aCallback)
821 {
822     otbrError error = OTBR_ERROR_NONE;
823 
824     VerifyOrExit(mState == Publisher::State::kReady, error = OTBR_ERROR_INVALID_STATE);
825     RemoveServiceRegistration(aName, aType, OTBR_ERROR_ABORTED);
826 
827 exit:
828     std::move(aCallback)(error);
829 }
830 
PublishHostImpl(const std::string & aName,const AddressList & aAddresses,ResultCallback && aCallback)831 otbrError PublisherMDnsSd::PublishHostImpl(const std::string &aName,
832                                            const AddressList &aAddresses,
833                                            ResultCallback   &&aCallback)
834 {
835     otbrError              error = OTBR_ERROR_NONE;
836     DnssdHostRegistration *hostReg;
837 
838     if (mState != State::kReady)
839     {
840         error = OTBR_ERROR_INVALID_STATE;
841         std::move(aCallback)(error);
842         ExitNow();
843     }
844 
845     aCallback = HandleDuplicateHostRegistration(aName, aAddresses, std::move(aCallback));
846     VerifyOrExit(!aCallback.IsNull());
847 
848     hostReg = new DnssdHostRegistration(aName, aAddresses, std::move(aCallback), this);
849     AddHostRegistration(std::unique_ptr<DnssdHostRegistration>(hostReg));
850 
851     error = hostReg->Register();
852 
853 exit:
854     return error;
855 }
856 
UnpublishHost(const std::string & aName,ResultCallback && aCallback)857 void PublisherMDnsSd::UnpublishHost(const std::string &aName, ResultCallback &&aCallback)
858 {
859     otbrError error = OTBR_ERROR_NONE;
860 
861     VerifyOrExit(mState == Publisher::State::kReady, error = OTBR_ERROR_INVALID_STATE);
862     RemoveHostRegistration(aName, OTBR_ERROR_ABORTED);
863 
864 exit:
865     // We may failed to unregister the host from underlying mDNS publishers, but
866     // it usually means that the mDNS publisher is already not functioning. So it's
867     // okay to return success directly since the service is not advertised anyway.
868     std::move(aCallback)(error);
869 }
870 
PublishKeyImpl(const std::string & aName,const KeyData & aKeyData,ResultCallback && aCallback)871 otbrError PublisherMDnsSd::PublishKeyImpl(const std::string &aName, const KeyData &aKeyData, ResultCallback &&aCallback)
872 {
873     otbrError             error = OTBR_ERROR_NONE;
874     DnssdKeyRegistration *keyReg;
875 
876     if (mState != State::kReady)
877     {
878         error = OTBR_ERROR_INVALID_STATE;
879         std::move(aCallback)(error);
880         ExitNow();
881     }
882 
883     aCallback = HandleDuplicateKeyRegistration(aName, aKeyData, std::move(aCallback));
884     VerifyOrExit(!aCallback.IsNull());
885 
886     keyReg = new DnssdKeyRegistration(aName, aKeyData, std::move(aCallback), this);
887     AddKeyRegistration(std::unique_ptr<DnssdKeyRegistration>(keyReg));
888 
889     error = keyReg->Register();
890 
891 exit:
892     return error;
893 }
894 
UnpublishKey(const std::string & aName,ResultCallback && aCallback)895 void PublisherMDnsSd::UnpublishKey(const std::string &aName, ResultCallback &&aCallback)
896 {
897     otbrError error = OTBR_ERROR_NONE;
898 
899     VerifyOrExit(mState == Publisher::State::kReady, error = OTBR_ERROR_INVALID_STATE);
900     RemoveKeyRegistration(aName, OTBR_ERROR_ABORTED);
901 
902 exit:
903     std::move(aCallback)(error);
904 }
905 
906 // See `regtype` parameter of the DNSServiceRegister() function for more information.
MakeRegType(const std::string & aType,SubTypeList aSubTypeList)907 std::string PublisherMDnsSd::MakeRegType(const std::string &aType, SubTypeList aSubTypeList)
908 {
909     std::string regType = aType;
910 
911     std::sort(aSubTypeList.begin(), aSubTypeList.end());
912 
913     for (const auto &subType : aSubTypeList)
914     {
915         regType += "," + subType;
916     }
917 
918     return regType;
919 }
920 
SubscribeService(const std::string & aType,const std::string & aInstanceName)921 void PublisherMDnsSd::SubscribeService(const std::string &aType, const std::string &aInstanceName)
922 {
923     VerifyOrExit(mState == Publisher::State::kReady);
924     mSubscribedServices.push_back(MakeUnique<ServiceSubscription>(*this, aType, aInstanceName));
925 
926     otbrLogInfo("Subscribe service %s.%s (total %zu)", aInstanceName.c_str(), aType.c_str(),
927                 mSubscribedServices.size());
928 
929     if (aInstanceName.empty())
930     {
931         mSubscribedServices.back()->Browse();
932     }
933     else
934     {
935         mSubscribedServices.back()->Resolve(kDNSServiceInterfaceIndexAny, aInstanceName, aType, kDomain);
936     }
937 
938 exit:
939     return;
940 }
941 
UnsubscribeService(const std::string & aType,const std::string & aInstanceName)942 void PublisherMDnsSd::UnsubscribeService(const std::string &aType, const std::string &aInstanceName)
943 {
944     ServiceSubscriptionList::iterator it;
945 
946     VerifyOrExit(mState == Publisher::State::kReady);
947     it = std::find_if(mSubscribedServices.begin(), mSubscribedServices.end(),
948                       [&aType, &aInstanceName](const std::unique_ptr<ServiceSubscription> &aService) {
949                           return aService->mType == aType && aService->mInstanceName == aInstanceName;
950                       });
951     VerifyOrExit(it != mSubscribedServices.end());
952 
953     mSubscribedServices.erase(it);
954 
955     otbrLogInfo("Unsubscribe service %s.%s (left %zu)", aInstanceName.c_str(), aType.c_str(),
956                 mSubscribedServices.size());
957 
958 exit:
959     return;
960 }
961 
OnServiceResolveFailedImpl(const std::string & aType,const std::string & aInstanceName,int32_t aErrorCode)962 void PublisherMDnsSd::OnServiceResolveFailedImpl(const std::string &aType,
963                                                  const std::string &aInstanceName,
964                                                  int32_t            aErrorCode)
965 {
966     otbrLogWarning("Resolve service %s.%s failed: code=%" PRId32, aInstanceName.c_str(), aType.c_str(), aErrorCode);
967 }
968 
OnHostResolveFailedImpl(const std::string & aHostName,int32_t aErrorCode)969 void PublisherMDnsSd::OnHostResolveFailedImpl(const std::string &aHostName, int32_t aErrorCode)
970 {
971     otbrLogWarning("Resolve host %s failed: code=%" PRId32, aHostName.c_str(), aErrorCode);
972 }
973 
DnsErrorToOtbrError(int32_t aErrorCode)974 otbrError PublisherMDnsSd::DnsErrorToOtbrError(int32_t aErrorCode)
975 {
976     return otbr::Mdns::DNSErrorToOtbrError(aErrorCode);
977 }
978 
SubscribeHost(const std::string & aHostName)979 void PublisherMDnsSd::SubscribeHost(const std::string &aHostName)
980 {
981     VerifyOrExit(mState == State::kReady);
982     mSubscribedHosts.push_back(MakeUnique<HostSubscription>(*this, aHostName));
983 
984     otbrLogInfo("Subscribe host %s (total %zu)", aHostName.c_str(), mSubscribedHosts.size());
985 
986     mSubscribedHosts.back()->Resolve();
987 
988 exit:
989     return;
990 }
991 
UnsubscribeHost(const std::string & aHostName)992 void PublisherMDnsSd::UnsubscribeHost(const std::string &aHostName)
993 {
994     HostSubscriptionList ::iterator it;
995 
996     VerifyOrExit(mState == Publisher::State::kReady);
997     it = std::find_if(
998         mSubscribedHosts.begin(), mSubscribedHosts.end(),
999         [&aHostName](const std::unique_ptr<HostSubscription> &aHost) { return aHost->mHostName == aHostName; });
1000 
1001     VerifyOrExit(it != mSubscribedHosts.end());
1002 
1003     mSubscribedHosts.erase(it);
1004 
1005     otbrLogInfo("Unsubscribe host %s (remaining %d)", aHostName.c_str(), mSubscribedHosts.size());
1006 
1007 exit:
1008     return;
1009 }
1010 
Create(StateCallback aCallback)1011 Publisher *Publisher::Create(StateCallback aCallback)
1012 {
1013     return new PublisherMDnsSd(aCallback);
1014 }
1015 
Destroy(Publisher * aPublisher)1016 void Publisher::Destroy(Publisher *aPublisher)
1017 {
1018     delete static_cast<PublisherMDnsSd *>(aPublisher);
1019 }
1020 
Release(void)1021 void PublisherMDnsSd::ServiceRef::Release(void)
1022 {
1023     DeallocateServiceRef();
1024 }
1025 
DeallocateServiceRef(void)1026 void PublisherMDnsSd::ServiceRef::DeallocateServiceRef(void)
1027 {
1028     if (mServiceRef != nullptr)
1029     {
1030         mPublisher.HandleServiceRefDeallocating(mServiceRef);
1031         DNSServiceRefDeallocate(mServiceRef);
1032         mServiceRef = nullptr;
1033     }
1034 }
1035 
Update(MainloopContext & aMainloop) const1036 void PublisherMDnsSd::ServiceRef::Update(MainloopContext &aMainloop) const
1037 {
1038     int fd;
1039 
1040     VerifyOrExit(mServiceRef != nullptr);
1041 
1042     fd = DNSServiceRefSockFD(mServiceRef);
1043     assert(fd != -1);
1044     FD_SET(fd, &aMainloop.mReadFdSet);
1045     aMainloop.mMaxFd = std::max(aMainloop.mMaxFd, fd);
1046 exit:
1047     return;
1048 }
1049 
Process(const MainloopContext & aMainloop,std::vector<DNSServiceRef> & aReadyServices) const1050 void PublisherMDnsSd::ServiceRef::Process(const MainloopContext      &aMainloop,
1051                                           std::vector<DNSServiceRef> &aReadyServices) const
1052 {
1053     int fd;
1054 
1055     VerifyOrExit(mServiceRef != nullptr);
1056 
1057     fd = DNSServiceRefSockFD(mServiceRef);
1058     assert(fd != -1);
1059     if (FD_ISSET(fd, &aMainloop.mReadFdSet))
1060     {
1061         aReadyServices.push_back(mServiceRef);
1062     }
1063 exit:
1064     return;
1065 }
1066 
Browse(void)1067 void PublisherMDnsSd::ServiceSubscription::Browse(void)
1068 {
1069     assert(mServiceRef == nullptr);
1070 
1071     otbrLogInfo("DNSServiceBrowse %s", mType.c_str());
1072     DNSServiceBrowse(&mServiceRef, /* flags */ 0, kDNSServiceInterfaceIndexAny, mType.c_str(),
1073                      /* domain */ nullptr, HandleBrowseResult, this);
1074 }
1075 
HandleBrowseResult(DNSServiceRef aServiceRef,DNSServiceFlags aFlags,uint32_t aInterfaceIndex,DNSServiceErrorType aErrorCode,const char * aInstanceName,const char * aType,const char * aDomain,void * aContext)1076 void PublisherMDnsSd::ServiceSubscription::HandleBrowseResult(DNSServiceRef       aServiceRef,
1077                                                               DNSServiceFlags     aFlags,
1078                                                               uint32_t            aInterfaceIndex,
1079                                                               DNSServiceErrorType aErrorCode,
1080                                                               const char         *aInstanceName,
1081                                                               const char         *aType,
1082                                                               const char         *aDomain,
1083                                                               void               *aContext)
1084 {
1085     static_cast<ServiceSubscription *>(aContext)->HandleBrowseResult(aServiceRef, aFlags, aInterfaceIndex, aErrorCode,
1086                                                                      aInstanceName, aType, aDomain);
1087 }
1088 
HandleBrowseResult(DNSServiceRef aServiceRef,DNSServiceFlags aFlags,uint32_t aInterfaceIndex,DNSServiceErrorType aErrorCode,const char * aInstanceName,const char * aType,const char * aDomain)1089 void PublisherMDnsSd::ServiceSubscription::HandleBrowseResult(DNSServiceRef       aServiceRef,
1090                                                               DNSServiceFlags     aFlags,
1091                                                               uint32_t            aInterfaceIndex,
1092                                                               DNSServiceErrorType aErrorCode,
1093                                                               const char         *aInstanceName,
1094                                                               const char         *aType,
1095                                                               const char         *aDomain)
1096 {
1097     OTBR_UNUSED_VARIABLE(aServiceRef);
1098     OTBR_UNUSED_VARIABLE(aDomain);
1099 
1100     otbrLogInfo("DNSServiceBrowse reply: %s %s.%s inf %" PRIu32 ", flags=%" PRIu32 ", error=%" PRId32,
1101                 aFlags & kDNSServiceFlagsAdd ? "add" : "remove", aInstanceName, aType, aInterfaceIndex, aFlags,
1102                 aErrorCode);
1103 
1104     VerifyOrExit(aErrorCode == kDNSServiceErr_NoError);
1105 
1106     if (aFlags & kDNSServiceFlagsAdd)
1107     {
1108         Resolve(aInterfaceIndex, aInstanceName, aType, aDomain);
1109     }
1110     else
1111     {
1112         mPublisher.OnServiceRemoved(aInterfaceIndex, mType, aInstanceName);
1113     }
1114 
1115 exit:
1116     if (aErrorCode != kDNSServiceErr_NoError)
1117     {
1118         mPublisher.OnServiceResolveFailed(mType, mInstanceName, aErrorCode);
1119         Release();
1120     }
1121 }
1122 
Resolve(uint32_t aInterfaceIndex,const std::string & aInstanceName,const std::string & aType,const std::string & aDomain)1123 void PublisherMDnsSd::ServiceSubscription::Resolve(uint32_t           aInterfaceIndex,
1124                                                    const std::string &aInstanceName,
1125                                                    const std::string &aType,
1126                                                    const std::string &aDomain)
1127 {
1128     mResolvingInstances.push_back(
1129         MakeUnique<ServiceInstanceResolution>(*this, aInstanceName, aType, aDomain, aInterfaceIndex));
1130     mResolvingInstances.back()->Resolve();
1131 }
1132 
UpdateAll(MainloopContext & aMainloop) const1133 void PublisherMDnsSd::ServiceSubscription::UpdateAll(MainloopContext &aMainloop) const
1134 {
1135     Update(aMainloop);
1136 
1137     for (const auto &instance : mResolvingInstances)
1138     {
1139         instance->Update(aMainloop);
1140     }
1141 }
1142 
ProcessAll(const MainloopContext & aMainloop,std::vector<DNSServiceRef> & aReadyServices) const1143 void PublisherMDnsSd::ServiceSubscription::ProcessAll(const MainloopContext      &aMainloop,
1144                                                       std::vector<DNSServiceRef> &aReadyServices) const
1145 {
1146     Process(aMainloop, aReadyServices);
1147 
1148     for (const auto &instance : mResolvingInstances)
1149     {
1150         instance->Process(aMainloop, aReadyServices);
1151     }
1152 }
1153 
Resolve(void)1154 void PublisherMDnsSd::ServiceInstanceResolution::Resolve(void)
1155 {
1156     assert(mServiceRef == nullptr);
1157 
1158     mSubscription->mPublisher.mServiceInstanceResolutionBeginTime[std::make_pair(mInstanceName, mType)] = Clock::now();
1159 
1160     otbrLogInfo("DNSServiceResolve %s %s inf %u", mInstanceName.c_str(), mType.c_str(), mNetifIndex);
1161     DNSServiceResolve(&mServiceRef, /* flags */ kDNSServiceFlagsTimeout, mNetifIndex, mInstanceName.c_str(),
1162                       mType.c_str(), mDomain.c_str(), HandleResolveResult, this);
1163 }
1164 
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)1165 void PublisherMDnsSd::ServiceInstanceResolution::HandleResolveResult(DNSServiceRef        aServiceRef,
1166                                                                      DNSServiceFlags      aFlags,
1167                                                                      uint32_t             aInterfaceIndex,
1168                                                                      DNSServiceErrorType  aErrorCode,
1169                                                                      const char          *aFullName,
1170                                                                      const char          *aHostTarget,
1171                                                                      uint16_t             aPort,
1172                                                                      uint16_t             aTxtLen,
1173                                                                      const unsigned char *aTxtRecord,
1174                                                                      void                *aContext)
1175 {
1176     static_cast<ServiceInstanceResolution *>(aContext)->HandleResolveResult(
1177         aServiceRef, aFlags, aInterfaceIndex, aErrorCode, aFullName, aHostTarget, aPort, aTxtLen, aTxtRecord);
1178 }
1179 
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)1180 void PublisherMDnsSd::ServiceInstanceResolution::HandleResolveResult(DNSServiceRef        aServiceRef,
1181                                                                      DNSServiceFlags      aFlags,
1182                                                                      uint32_t             aInterfaceIndex,
1183                                                                      DNSServiceErrorType  aErrorCode,
1184                                                                      const char          *aFullName,
1185                                                                      const char          *aHostTarget,
1186                                                                      uint16_t             aPort,
1187                                                                      uint16_t             aTxtLen,
1188                                                                      const unsigned char *aTxtRecord)
1189 {
1190     OTBR_UNUSED_VARIABLE(aServiceRef);
1191 
1192     std::string instanceName, type, domain;
1193     otbrError   error = OTBR_ERROR_NONE;
1194 
1195     otbrLogInfo("DNSServiceResolve reply: %s host %s:%d, TXT=%dB inf %u, flags=%u", aFullName, aHostTarget, aPort,
1196                 aTxtLen, aInterfaceIndex, aFlags);
1197 
1198     VerifyOrExit(aErrorCode == kDNSServiceErr_NoError);
1199 
1200     SuccessOrExit(error = SplitFullServiceInstanceName(aFullName, instanceName, type, domain));
1201 
1202     mInstanceInfo.mNetifIndex = aInterfaceIndex;
1203     mInstanceInfo.mName       = instanceName;
1204     mInstanceInfo.mHostName   = aHostTarget;
1205     mInstanceInfo.mPort       = ntohs(aPort);
1206     mInstanceInfo.mTxtData.assign(aTxtRecord, aTxtRecord + aTxtLen);
1207     // priority and weight are not given in the reply
1208     mInstanceInfo.mPriority = 0;
1209     mInstanceInfo.mWeight   = 0;
1210 
1211     DeallocateServiceRef();
1212     error = GetAddrInfo(aInterfaceIndex);
1213 
1214 exit:
1215     if (error != OTBR_ERROR_NONE)
1216     {
1217         otbrLogWarning("Failed to resolve service instance %s", aFullName);
1218     }
1219 
1220     if (aErrorCode != kDNSServiceErr_NoError || error != OTBR_ERROR_NONE)
1221     {
1222         mSubscription->mPublisher.OnServiceResolveFailed(mSubscription->mType, mInstanceName, aErrorCode);
1223         FinishResolution();
1224     }
1225 }
1226 
GetAddrInfo(uint32_t aInterfaceIndex)1227 otbrError PublisherMDnsSd::ServiceInstanceResolution::GetAddrInfo(uint32_t aInterfaceIndex)
1228 {
1229     DNSServiceErrorType dnsError;
1230 
1231     assert(mServiceRef == nullptr);
1232 
1233     otbrLogInfo("DNSServiceGetAddrInfo %s inf %d", mInstanceInfo.mHostName.c_str(), aInterfaceIndex);
1234 
1235     dnsError = DNSServiceGetAddrInfo(&mServiceRef, /* flags */ 0, aInterfaceIndex,
1236                                      kDNSServiceProtocol_IPv6 | kDNSServiceProtocol_IPv4,
1237                                      mInstanceInfo.mHostName.c_str(), HandleGetAddrInfoResult, this);
1238 
1239     if (dnsError != kDNSServiceErr_NoError)
1240     {
1241         otbrLogWarning("DNSServiceGetAddrInfo failed: %s", DNSErrorToString(dnsError));
1242     }
1243 
1244     return dnsError == kDNSServiceErr_NoError ? OTBR_ERROR_NONE : OTBR_ERROR_MDNS;
1245 }
1246 
HandleGetAddrInfoResult(DNSServiceRef aServiceRef,DNSServiceFlags aFlags,uint32_t aInterfaceIndex,DNSServiceErrorType aErrorCode,const char * aHostName,const struct sockaddr * aAddress,uint32_t aTtl,void * aContext)1247 void PublisherMDnsSd::ServiceInstanceResolution::HandleGetAddrInfoResult(DNSServiceRef          aServiceRef,
1248                                                                          DNSServiceFlags        aFlags,
1249                                                                          uint32_t               aInterfaceIndex,
1250                                                                          DNSServiceErrorType    aErrorCode,
1251                                                                          const char            *aHostName,
1252                                                                          const struct sockaddr *aAddress,
1253                                                                          uint32_t               aTtl,
1254                                                                          void                  *aContext)
1255 {
1256     static_cast<ServiceInstanceResolution *>(aContext)->HandleGetAddrInfoResult(aServiceRef, aFlags, aInterfaceIndex,
1257                                                                                 aErrorCode, aHostName, aAddress, aTtl);
1258 }
1259 
HandleGetAddrInfoResult(DNSServiceRef aServiceRef,DNSServiceFlags aFlags,uint32_t aInterfaceIndex,DNSServiceErrorType aErrorCode,const char * aHostName,const struct sockaddr * aAddress,uint32_t aTtl)1260 void PublisherMDnsSd::ServiceInstanceResolution::HandleGetAddrInfoResult(DNSServiceRef          aServiceRef,
1261                                                                          DNSServiceFlags        aFlags,
1262                                                                          uint32_t               aInterfaceIndex,
1263                                                                          DNSServiceErrorType    aErrorCode,
1264                                                                          const char            *aHostName,
1265                                                                          const struct sockaddr *aAddress,
1266                                                                          uint32_t               aTtl)
1267 {
1268     OTBR_UNUSED_VARIABLE(aServiceRef);
1269     OTBR_UNUSED_VARIABLE(aInterfaceIndex);
1270 
1271     Ip6Address address;
1272     bool       isAdd = (aFlags & kDNSServiceFlagsAdd) != 0;
1273 
1274     otbrLog(aErrorCode == kDNSServiceErr_NoError ? OTBR_LOG_INFO : OTBR_LOG_WARNING, OTBR_LOG_TAG,
1275             "DNSServiceGetAddrInfo reply: flags=%" PRIu32 ", host=%s, sa_family=%u, error=%" PRId32, aFlags, aHostName,
1276             static_cast<unsigned int>(aAddress->sa_family), aErrorCode);
1277 
1278     VerifyOrExit(aErrorCode == kDNSServiceErr_NoError);
1279     VerifyOrExit(aAddress->sa_family == AF_INET6);
1280 
1281     address.CopyFrom(*reinterpret_cast<const struct sockaddr_in6 *>(aAddress));
1282     VerifyOrExit(!address.IsUnspecified() && !address.IsLinkLocal() && !address.IsMulticast() && !address.IsLoopback(),
1283                  otbrLogDebug("DNSServiceGetAddrInfo ignores address %s", address.ToString().c_str()));
1284 
1285     otbrLogInfo("DNSServiceGetAddrInfo reply: %s address=%s, ttl=%" PRIu32, isAdd ? "add" : "remove",
1286                 address.ToString().c_str(), aTtl);
1287 
1288     if (isAdd)
1289     {
1290         mInstanceInfo.AddAddress(address);
1291     }
1292     else
1293     {
1294         mInstanceInfo.RemoveAddress(address);
1295     }
1296     mInstanceInfo.mTtl = aTtl;
1297 
1298 exit:
1299     if (!mInstanceInfo.mAddresses.empty() || aErrorCode != kDNSServiceErr_NoError)
1300     {
1301         FinishResolution();
1302     }
1303 }
1304 
FinishResolution(void)1305 void PublisherMDnsSd::ServiceInstanceResolution::FinishResolution(void)
1306 {
1307     ServiceSubscription   *subscription = mSubscription;
1308     std::string            serviceName  = mSubscription->mType;
1309     DiscoveredInstanceInfo instanceInfo = mInstanceInfo;
1310 
1311     // NOTE: The `ServiceSubscription` object may be freed in `OnServiceResolved`.
1312     subscription->mPublisher.OnServiceResolved(serviceName, instanceInfo);
1313 }
1314 
Resolve(void)1315 void PublisherMDnsSd::HostSubscription::Resolve(void)
1316 {
1317     std::string fullHostName = MakeFullHostName(mHostName);
1318 
1319     assert(mServiceRef == nullptr);
1320 
1321     mPublisher.mHostResolutionBeginTime[mHostName] = Clock::now();
1322 
1323     otbrLogInfo("DNSServiceGetAddrInfo %s inf %d", fullHostName.c_str(), kDNSServiceInterfaceIndexAny);
1324 
1325     DNSServiceGetAddrInfo(&mServiceRef, /* flags */ 0, kDNSServiceInterfaceIndexAny,
1326                           kDNSServiceProtocol_IPv6 | kDNSServiceProtocol_IPv4, fullHostName.c_str(),
1327                           HandleResolveResult, this);
1328 }
1329 
HandleResolveResult(DNSServiceRef aServiceRef,DNSServiceFlags aFlags,uint32_t aInterfaceIndex,DNSServiceErrorType aErrorCode,const char * aHostName,const struct sockaddr * aAddress,uint32_t aTtl,void * aContext)1330 void PublisherMDnsSd::HostSubscription::HandleResolveResult(DNSServiceRef          aServiceRef,
1331                                                             DNSServiceFlags        aFlags,
1332                                                             uint32_t               aInterfaceIndex,
1333                                                             DNSServiceErrorType    aErrorCode,
1334                                                             const char            *aHostName,
1335                                                             const struct sockaddr *aAddress,
1336                                                             uint32_t               aTtl,
1337                                                             void                  *aContext)
1338 {
1339     static_cast<HostSubscription *>(aContext)->HandleResolveResult(aServiceRef, aFlags, aInterfaceIndex, aErrorCode,
1340                                                                    aHostName, aAddress, aTtl);
1341 }
1342 
HandleResolveResult(DNSServiceRef aServiceRef,DNSServiceFlags aFlags,uint32_t aInterfaceIndex,DNSServiceErrorType aErrorCode,const char * aHostName,const struct sockaddr * aAddress,uint32_t aTtl)1343 void PublisherMDnsSd::HostSubscription::HandleResolveResult(DNSServiceRef          aServiceRef,
1344                                                             DNSServiceFlags        aFlags,
1345                                                             uint32_t               aInterfaceIndex,
1346                                                             DNSServiceErrorType    aErrorCode,
1347                                                             const char            *aHostName,
1348                                                             const struct sockaddr *aAddress,
1349                                                             uint32_t               aTtl)
1350 {
1351     OTBR_UNUSED_VARIABLE(aServiceRef);
1352 
1353     Ip6Address address;
1354     bool       isAdd = (aFlags & kDNSServiceFlagsAdd) != 0;
1355 
1356     otbrLog(aErrorCode == kDNSServiceErr_NoError ? OTBR_LOG_INFO : OTBR_LOG_WARNING, OTBR_LOG_TAG,
1357             "DNSServiceGetAddrInfo reply: flags=%" PRIu32 ", host=%s, sa_family=%u, error=%" PRId32, aFlags, aHostName,
1358             static_cast<unsigned int>(aAddress->sa_family), aErrorCode);
1359 
1360     VerifyOrExit(aErrorCode == kDNSServiceErr_NoError);
1361     VerifyOrExit(aAddress->sa_family == AF_INET6);
1362 
1363     address.CopyFrom(*reinterpret_cast<const struct sockaddr_in6 *>(aAddress));
1364     VerifyOrExit(!address.IsLinkLocal(),
1365                  otbrLogDebug("DNSServiceGetAddrInfo ignore link-local address %s", address.ToString().c_str()));
1366 
1367     otbrLogInfo("DNSServiceGetAddrInfo reply: %s address=%s, ttl=%" PRIu32, isAdd ? "add" : "remove",
1368                 address.ToString().c_str(), aTtl);
1369 
1370     if (isAdd)
1371     {
1372         mHostInfo.AddAddress(address);
1373     }
1374     else
1375     {
1376         mHostInfo.RemoveAddress(address);
1377     }
1378     mHostInfo.mHostName   = aHostName;
1379     mHostInfo.mNetifIndex = aInterfaceIndex;
1380     mHostInfo.mTtl        = aTtl;
1381 
1382     // NOTE: This `HostSubscription` object may be freed in `OnHostResolved`.
1383     mPublisher.OnHostResolved(mHostName, mHostInfo);
1384 
1385 exit:
1386     if (aErrorCode != kDNSServiceErr_NoError)
1387     {
1388         mPublisher.OnHostResolveFailed(aHostName, aErrorCode);
1389     }
1390 }
1391 
1392 } // namespace Mdns
1393 
1394 } // namespace otbr
1395