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