xref: /aosp_15_r20/external/ot-br-posix/src/android/mdns_publisher.cpp (revision 4a64e381480ef79f0532b2421e44e6ee336b8e0d)
1 /*
2  *    Copyright (c) 2024, The OpenThread Authors.
3  *    All rights reserved.
4  *
5  *    Redistribution and use in source and binary forms, with or without
6  *    modification, are permitted provided that the following conditions are met:
7  *    1. Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *    2. Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *    3. Neither the name of the copyright holder nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *    POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #define OTBR_LOG_TAG "MDNS"
30 
31 #include "android/mdns_publisher.hpp"
32 
33 namespace otbr {
34 
Create(Mdns::Publisher::StateCallback aCallback)35 Mdns::Publisher *Mdns::Publisher::Create(Mdns::Publisher::StateCallback aCallback)
36 {
37     return new Android::MdnsPublisher(std::move(aCallback));
38 }
39 
40 namespace Android {
DnsErrorToOtbrErrorImpl(int32_t aError)41 otbrError DnsErrorToOtbrErrorImpl(int32_t aError)
42 {
43     return aError == 0 ? OTBR_ERROR_NONE : OTBR_ERROR_MDNS;
44 }
45 
DnsErrorToOtbrError(int32_t aError)46 otbrError MdnsPublisher::DnsErrorToOtbrError(int32_t aError)
47 {
48     return DnsErrorToOtbrErrorImpl(aError);
49 }
50 
onSuccess()51 Status MdnsPublisher::NsdStatusReceiver::onSuccess()
52 {
53     if (!mCallback.IsNull())
54     {
55         std::move(mCallback)(OTBR_ERROR_NONE);
56     }
57 
58     return Status::ok();
59 }
60 
onServiceDiscovered(const std::string & aName,const std::string & aType,bool aIsFound)61 Status MdnsPublisher::NsdDiscoverServiceCallback::onServiceDiscovered(const std::string &aName,
62                                                                       const std::string &aType,
63                                                                       bool               aIsFound)
64 {
65     std::shared_ptr<ServiceSubscription> subscription = mSubscription.lock();
66 
67     VerifyOrExit(subscription != nullptr);
68     VerifyOrExit(aIsFound, subscription->mPublisher.OnServiceRemoved(0, aType, aName));
69 
70     subscription->Resolve(aName, aType);
71 
72 exit:
73     return Status::ok();
74 }
75 
onServiceResolved(const std::string & aHostname,int aNetifIndex,const std::string & aName,const std::string & aType,int aPort,const std::vector<std::string> & aAddresses,const std::vector<DnsTxtAttribute> & aTxt,int aTtlSeconds)76 Status MdnsPublisher::NsdResolveServiceCallback::onServiceResolved(const std::string                  &aHostname,
77                                                                    int                                 aNetifIndex,
78                                                                    const std::string                  &aName,
79                                                                    const std::string                  &aType,
80                                                                    int                                 aPort,
81                                                                    const std::vector<std::string>     &aAddresses,
82                                                                    const std::vector<DnsTxtAttribute> &aTxt,
83                                                                    int                                 aTtlSeconds)
84 {
85     DiscoveredInstanceInfo               info;
86     TxtList                              txtList;
87     std::shared_ptr<ServiceSubscription> subscription = mSubscription.lock();
88 
89     VerifyOrExit(subscription != nullptr);
90 
91     info.mHostName   = aHostname + ".local.";
92     info.mName       = aName;
93     info.mPort       = aPort;
94     info.mTtl        = std::clamp(aTtlSeconds, kMinResolvedTtl, kMaxResolvedTtl);
95     info.mNetifIndex = aNetifIndex;
96     for (const auto &addressStr : aAddresses)
97     {
98         Ip6Address address;
99         // addressStr may be in the format of "fe80::1234%eth0"
100         std::string addrStr(addressStr.begin(), std::find(addressStr.begin(), addressStr.end(), '%'));
101         int         error = Ip6Address::FromString(addrStr.c_str(), address);
102 
103         if (error != OTBR_ERROR_NONE)
104         {
105             otbrLogInfo("Failed to parse resolved IPv6 address: %s", addressStr.c_str());
106             continue;
107         }
108         info.mAddresses.push_back(address);
109     }
110     for (const auto &entry : aTxt)
111     {
112         txtList.emplace_back(entry.name.c_str(), entry.value.data(), entry.value.size());
113     }
114     EncodeTxtData(txtList, info.mTxtData);
115 
116     subscription->mPublisher.OnServiceResolved(aType, info);
117 
118 exit:
119     return Status::ok();
120 }
121 
onHostResolved(const std::string & aName,const std::vector<std::string> & aAddresses)122 Status MdnsPublisher::NsdResolveHostCallback::onHostResolved(const std::string              &aName,
123                                                              const std::vector<std::string> &aAddresses)
124 {
125     DiscoveredHostInfo                info;
126     std::shared_ptr<HostSubscription> subscription = mSubscription.lock();
127 
128     VerifyOrExit(subscription != nullptr);
129 
130     info.mTtl = kDefaultResolvedTtl;
131     for (const auto &addressStr : aAddresses)
132     {
133         Ip6Address address;
134         int        error = Ip6Address::FromString(addressStr.c_str(), address);
135 
136         if (error != OTBR_ERROR_NONE)
137         {
138             otbrLogInfo("Failed to parse resolved IPv6 address: %s", addressStr.c_str());
139             continue;
140         }
141         info.mAddresses.push_back(address);
142     }
143 
144     subscription->mPublisher.OnHostResolved(aName, info);
145 
146 exit:
147     return Status::ok();
148 }
149 
SetINsdPublisher(std::shared_ptr<INsdPublisher> aINsdPublisher)150 void MdnsPublisher::SetINsdPublisher(std::shared_ptr<INsdPublisher> aINsdPublisher)
151 {
152     otbrLogInfo("Set INsdPublisher %p", aINsdPublisher.get());
153 
154     mNsdPublisher = std::move(aINsdPublisher);
155 
156     if (mNsdPublisher != nullptr)
157     {
158         mStateCallback(Mdns::Publisher::State::kReady);
159     }
160     else
161     {
162         mStateCallback(Mdns::Publisher::State::kIdle);
163     }
164 }
165 
onError(int aError)166 Status MdnsPublisher::NsdStatusReceiver::onError(int aError)
167 {
168     if (!mCallback.IsNull())
169     {
170         std::move(mCallback)(DnsErrorToOtbrErrorImpl(aError));
171     }
172 
173     return Status::ok();
174 }
175 
CreateReceiver(Mdns::Publisher::ResultCallback aCallback)176 std::shared_ptr<MdnsPublisher::NsdStatusReceiver> CreateReceiver(Mdns::Publisher::ResultCallback aCallback)
177 {
178     return ndk::SharedRefBase::make<MdnsPublisher::NsdStatusReceiver>(std::move(aCallback));
179 }
180 
CreateNsdDiscoverServiceCallback(const std::shared_ptr<MdnsPublisher::ServiceSubscription> & aServiceSubscription)181 std::shared_ptr<MdnsPublisher::NsdDiscoverServiceCallback> CreateNsdDiscoverServiceCallback(
182     const std::shared_ptr<MdnsPublisher::ServiceSubscription> &aServiceSubscription)
183 {
184     return ndk::SharedRefBase::make<MdnsPublisher::NsdDiscoverServiceCallback>(aServiceSubscription);
185 }
186 
CreateNsdResolveServiceCallback(const std::shared_ptr<MdnsPublisher::ServiceSubscription> & aServiceSubscription)187 std::shared_ptr<MdnsPublisher::NsdResolveServiceCallback> CreateNsdResolveServiceCallback(
188     const std::shared_ptr<MdnsPublisher::ServiceSubscription> &aServiceSubscription)
189 {
190     return ndk::SharedRefBase::make<MdnsPublisher::NsdResolveServiceCallback>(aServiceSubscription);
191 }
192 
CreateNsdResolveHostCallback(const std::shared_ptr<MdnsPublisher::HostSubscription> & aHostSubscription)193 std::shared_ptr<MdnsPublisher::NsdResolveHostCallback> CreateNsdResolveHostCallback(
194     const std::shared_ptr<MdnsPublisher::HostSubscription> &aHostSubscription)
195 {
196     return ndk::SharedRefBase::make<MdnsPublisher::NsdResolveHostCallback>(aHostSubscription);
197 }
198 
DieForNotImplemented(const char * aFuncName)199 void DieForNotImplemented(const char *aFuncName)
200 {
201     VerifyOrDie(false, (std::string(aFuncName) + " is not implemented").c_str());
202 }
203 
PublishServiceImpl(const std::string & aHostName,const std::string & aName,const std::string & aType,const SubTypeList & aSubTypeList,uint16_t aPort,const TxtData & aTxtData,ResultCallback && aCallback)204 otbrError MdnsPublisher::PublishServiceImpl(const std::string &aHostName,
205                                             const std::string &aName,
206                                             const std::string &aType,
207                                             const SubTypeList &aSubTypeList,
208                                             uint16_t           aPort,
209                                             const TxtData     &aTxtData,
210                                             ResultCallback   &&aCallback)
211 {
212     int32_t   listenerId = AllocateListenerId();
213     TxtList   txtList;
214     otbrError error = OTBR_ERROR_NONE;
215 
216     std::vector<DnsTxtAttribute> txtAttributes;
217 
218     VerifyOrExit(IsStarted(), error = OTBR_ERROR_MDNS);
219     if (mNsdPublisher == nullptr)
220     {
221         otbrLogWarning("No platform mDNS implementation registered!");
222         ExitNow(error = OTBR_ERROR_MDNS);
223     }
224 
225     aCallback = HandleDuplicateServiceRegistration(aHostName, aName, aType, aSubTypeList, aPort, aTxtData,
226                                                    std::move(aCallback));
227     VerifyOrExit(!aCallback.IsNull(), error = OTBR_ERROR_INVALID_STATE);
228 
229     SuccessOrExit(error = DecodeTxtData(txtList, aTxtData.data(), aTxtData.size()));
230 
231     for (const auto &txtEntry : txtList)
232     {
233         DnsTxtAttribute txtAttribute;
234 
235         txtAttribute.name  = txtEntry.mKey;
236         txtAttribute.value = txtEntry.mValue;
237         txtAttributes.push_back(std::move(txtAttribute));
238     }
239     AddServiceRegistration(MakeUnique<NsdServiceRegistration>(aHostName, aName, aType, aSubTypeList, aPort, aTxtData,
240                                                               /* aCallback= */ nullptr, this, listenerId,
241                                                               mNsdPublisher));
242 
243     otbrLogInfo("Publishing service %s.%s listener ID = %d", aName.c_str(), aType.c_str(), listenerId);
244 
245     mNsdPublisher->registerService(aHostName, aName, aType, aSubTypeList, aPort, txtAttributes,
246                                    CreateReceiver(std::move(aCallback)), listenerId);
247 
248 exit:
249     return error;
250 }
251 
UnpublishService(const std::string & aName,const std::string & aType,ResultCallback && aCallback)252 void MdnsPublisher::UnpublishService(const std::string &aName, const std::string &aType, ResultCallback &&aCallback)
253 {
254     NsdServiceRegistration *serviceRegistration =
255         static_cast<NsdServiceRegistration *>(FindServiceRegistration(aName, aType));
256 
257     VerifyOrExit(IsStarted(), std::move(aCallback)(OTBR_ERROR_MDNS));
258     if (mNsdPublisher == nullptr)
259     {
260         otbrLogWarning("No platform mDNS implementation registered!");
261         ExitNow(std::move(aCallback)(OTBR_ERROR_MDNS));
262     }
263     VerifyOrExit(serviceRegistration != nullptr, std::move(aCallback)(OTBR_ERROR_NONE));
264 
265     serviceRegistration->mUnregisterReceiver = CreateReceiver(std::move(aCallback));
266     RemoveServiceRegistration(aName, aType, OTBR_ERROR_NONE);
267 
268 exit:
269     return;
270 }
271 
PublishHostImpl(const std::string & aName,const AddressList & aAddresses,ResultCallback && aCallback)272 otbrError MdnsPublisher::PublishHostImpl(const std::string &aName,
273                                          const AddressList &aAddresses,
274                                          ResultCallback   &&aCallback)
275 {
276     int32_t   listenerId = AllocateListenerId();
277     TxtList   txtList;
278     otbrError error = OTBR_ERROR_NONE;
279 
280     std::vector<std::string> addressStrings;
281 
282     VerifyOrExit(IsStarted(), error = OTBR_ERROR_MDNS);
283     if (mNsdPublisher == nullptr)
284     {
285         otbrLogWarning("No platform mDNS implementation registered!");
286         ExitNow(error = OTBR_ERROR_MDNS);
287     }
288 
289     aCallback = HandleDuplicateHostRegistration(aName, aAddresses, std::move(aCallback));
290     VerifyOrExit(!aCallback.IsNull(), error = OTBR_ERROR_INVALID_STATE);
291 
292     AddHostRegistration(
293         MakeUnique<NsdHostRegistration>(aName, aAddresses, /* aCallback= */ nullptr, this, listenerId, mNsdPublisher));
294 
295     otbrLogInfo("Publishing host %s listener ID = %d", aName.c_str(), listenerId);
296 
297     addressStrings.reserve(aAddresses.size());
298     for (const Ip6Address &address : aAddresses)
299     {
300         addressStrings.push_back(address.ToString());
301     }
302 
303     if (aAddresses.size())
304     {
305         mNsdPublisher->registerHost(aName, addressStrings, CreateReceiver(std::move(aCallback)), listenerId);
306     }
307     else
308     {
309         // No addresses to register.
310         std::move(aCallback)(OTBR_ERROR_NONE);
311     }
312 
313 exit:
314     return error;
315 }
316 
PublishKeyImpl(const std::string & aName,const KeyData & aKeyData,ResultCallback && aCallback)317 otbrError MdnsPublisher::PublishKeyImpl(const std::string &aName, const KeyData &aKeyData, ResultCallback &&aCallback)
318 {
319     OTBR_UNUSED_VARIABLE(aName);
320     OTBR_UNUSED_VARIABLE(aKeyData);
321     OTBR_UNUSED_VARIABLE(aCallback);
322 
323     DieForNotImplemented(__func__);
324 
325     return OTBR_ERROR_MDNS;
326 }
327 
UnpublishHost(const std::string & aName,ResultCallback && aCallback)328 void MdnsPublisher::UnpublishHost(const std::string &aName, ResultCallback &&aCallback)
329 {
330     NsdHostRegistration *hostRegistration = static_cast<NsdHostRegistration *>(FindHostRegistration(aName));
331 
332     VerifyOrExit(IsStarted(), std::move(aCallback)(OTBR_ERROR_MDNS));
333     if (mNsdPublisher == nullptr)
334     {
335         otbrLogWarning("No platform mDNS implementation registered!");
336         ExitNow(std::move(aCallback)(OTBR_ERROR_MDNS));
337     }
338     VerifyOrExit(hostRegistration != nullptr, std::move(aCallback)(OTBR_ERROR_NONE));
339 
340     hostRegistration->mUnregisterReceiver = CreateReceiver(std::move(aCallback));
341     RemoveHostRegistration(aName, OTBR_ERROR_NONE);
342 
343 exit:
344     return;
345 }
346 
UnpublishKey(const std::string & aName,ResultCallback && aCallback)347 void MdnsPublisher::UnpublishKey(const std::string &aName, ResultCallback &&aCallback)
348 {
349     OTBR_UNUSED_VARIABLE(aName);
350     OTBR_UNUSED_VARIABLE(aCallback);
351 
352     DieForNotImplemented(__func__);
353 }
354 
SubscribeService(const std::string & aType,const std::string & aInstanceName)355 void MdnsPublisher::SubscribeService(const std::string &aType, const std::string &aInstanceName)
356 {
357     auto service = std::make_shared<ServiceSubscription>(aType, aInstanceName, *this, mNsdPublisher);
358 
359     VerifyOrExit(IsStarted(), otbrLogWarning("No platform mDNS implementation registered!"));
360 
361     mServiceSubscriptions.push_back(std::move(service));
362 
363     otbrLogInfo("Subscribe service %s.%s (total %zu)", aInstanceName.c_str(), aType.c_str(),
364                 mServiceSubscriptions.size());
365 
366     if (aInstanceName.empty())
367     {
368         mServiceSubscriptions.back()->Browse();
369     }
370     else
371     {
372         mServiceSubscriptions.back()->Resolve(aInstanceName, aType);
373     }
374 exit:
375     return;
376 }
377 
UnsubscribeService(const std::string & aType,const std::string & aInstanceName)378 void MdnsPublisher::UnsubscribeService(const std::string &aType, const std::string &aInstanceName)
379 {
380     ServiceSubscriptionList::iterator it;
381 
382     VerifyOrExit(IsStarted());
383 
384     it = std::find_if(mServiceSubscriptions.begin(), mServiceSubscriptions.end(),
385                       [&aType, &aInstanceName](const std::shared_ptr<ServiceSubscription> &aService) {
386                           return aService->mType == aType && aService->mName == aInstanceName;
387                       });
388 
389     VerifyOrExit(it != mServiceSubscriptions.end(),
390                  otbrLogWarning("The service %s.%s is already unsubscribed.", aInstanceName.c_str(), aType.c_str()));
391 
392     {
393         std::shared_ptr<ServiceSubscription> service = std::move(*it);
394 
395         mServiceSubscriptions.erase(it);
396     }
397 
398     otbrLogInfo("Unsubscribe service %s.%s (left %zu)", aInstanceName.c_str(), aType.c_str(),
399                 mServiceSubscriptions.size());
400 
401 exit:
402     return;
403 }
404 
SubscribeHost(const std::string & aHostName)405 void MdnsPublisher::SubscribeHost(const std::string &aHostName)
406 {
407     auto host = std::make_shared<HostSubscription>(aHostName, *this, mNsdPublisher, AllocateListenerId());
408 
409     VerifyOrExit(IsStarted(), otbrLogWarning("No platform mDNS implementation registered!"));
410 
411     mNsdPublisher->resolveHost(aHostName, CreateNsdResolveHostCallback(host), host->mListenerId);
412     mHostSubscriptions.push_back(std::move(host));
413 
414     otbrLogInfo("Subscribe host %s (total %zu)", aHostName.c_str(), mHostSubscriptions.size());
415 
416 exit:
417     return;
418 }
419 
UnsubscribeHost(const std::string & aHostName)420 void MdnsPublisher::UnsubscribeHost(const std::string &aHostName)
421 {
422     HostSubscriptionList::iterator it;
423 
424     VerifyOrExit(IsStarted());
425 
426     it = std::find_if(
427         mHostSubscriptions.begin(), mHostSubscriptions.end(),
428         [&aHostName](const std::shared_ptr<HostSubscription> &aHost) { return aHost->mName == aHostName; });
429 
430     VerifyOrExit(it != mHostSubscriptions.end(),
431                  otbrLogWarning("The host %s is already unsubscribed.", aHostName.c_str()));
432 
433     {
434         std::shared_ptr<HostSubscription> host = std::move(*it);
435 
436         mHostSubscriptions.erase(it);
437     }
438 
439     otbrLogInfo("Unsubscribe host %s (left %zu)", aHostName.c_str(), mHostSubscriptions.size());
440 
441 exit:
442     return;
443 }
444 
OnServiceResolveFailedImpl(const std::string & aType,const std::string & aInstanceName,int32_t aErrorCode)445 void MdnsPublisher::OnServiceResolveFailedImpl(const std::string &aType,
446                                                const std::string &aInstanceName,
447                                                int32_t            aErrorCode)
448 {
449     OTBR_UNUSED_VARIABLE(aType);
450     OTBR_UNUSED_VARIABLE(aInstanceName);
451     OTBR_UNUSED_VARIABLE(aErrorCode);
452 
453     DieForNotImplemented(__func__);
454 }
455 
OnHostResolveFailedImpl(const std::string & aHostName,int32_t aErrorCode)456 void MdnsPublisher::OnHostResolveFailedImpl(const std::string &aHostName, int32_t aErrorCode)
457 {
458     OTBR_UNUSED_VARIABLE(aHostName);
459     OTBR_UNUSED_VARIABLE(aErrorCode);
460 
461     DieForNotImplemented(__func__);
462 }
463 
AllocateListenerId(void)464 int32_t MdnsPublisher::AllocateListenerId(void)
465 {
466     if (mNextListenerId == std::numeric_limits<int32_t>::max())
467     {
468         mNextListenerId = 0;
469     }
470     return mNextListenerId++;
471 }
472 
~NsdServiceRegistration(void)473 MdnsPublisher::NsdServiceRegistration::~NsdServiceRegistration(void)
474 {
475     auto nsdPublisher = mNsdPublisher.lock();
476 
477     VerifyOrExit(mPublisher->IsStarted() && nsdPublisher != nullptr);
478 
479     otbrLogInfo("Unpublishing service %s.%s listener ID = %d", mName.c_str(), mType.c_str(), mListenerId);
480 
481     if (!mUnregisterReceiver)
482     {
483         mUnregisterReceiver = CreateReceiver([](int) {});
484     }
485 
486     nsdPublisher->unregister(mUnregisterReceiver, mListenerId);
487 
488 exit:
489     return;
490 }
491 
~NsdHostRegistration(void)492 MdnsPublisher::NsdHostRegistration::~NsdHostRegistration(void)
493 {
494     auto nsdPublisher = mNsdPublisher.lock();
495 
496     VerifyOrExit(mPublisher->IsStarted() && nsdPublisher != nullptr);
497 
498     otbrLogInfo("Unpublishing host %s listener ID = %d", mName.c_str(), mListenerId);
499 
500     if (!mUnregisterReceiver)
501     {
502         mUnregisterReceiver = CreateReceiver([](int) {});
503     }
504 
505     nsdPublisher->unregister(mUnregisterReceiver, mListenerId);
506 
507 exit:
508     return;
509 }
510 
Release(void)511 void MdnsPublisher::ServiceSubscription::Release(void)
512 {
513     otbrLogInfo("Browsing service type %s", mType.c_str());
514 
515     std::vector<std::string> instanceNames;
516 
517     for (const auto &nameAndResolvers : mResolvers)
518     {
519         instanceNames.push_back(nameAndResolvers.first);
520     }
521     for (const auto &name : instanceNames)
522     {
523         RemoveServiceResolver(name);
524     }
525 
526     mNsdPublisher->stopServiceDiscovery(mBrowseListenerId);
527 }
528 
Browse(void)529 void MdnsPublisher::ServiceSubscription::Browse(void)
530 {
531     VerifyOrExit(mPublisher.IsStarted());
532 
533     otbrLogInfo("Browsing service type %s", mType.c_str());
534 
535     mNsdPublisher->discoverService(mType, CreateNsdDiscoverServiceCallback(shared_from_this()), mBrowseListenerId);
536 
537 exit:
538     return;
539 }
540 
Resolve(const std::string & aName,const std::string & aType)541 void MdnsPublisher::ServiceSubscription::Resolve(const std::string &aName, const std::string &aType)
542 {
543     ServiceResolver *resolver = new ServiceResolver(mPublisher.AllocateListenerId(), mNsdPublisher);
544 
545     VerifyOrExit(mPublisher.IsStarted());
546 
547     otbrLogInfo("Resolving service %s.%s", aName.c_str(), aType.c_str());
548 
549     AddServiceResolver(aName, resolver);
550     mNsdPublisher->resolveService(aName, aType, CreateNsdResolveServiceCallback(shared_from_this()),
551                                   resolver->mListenerId);
552 
553 exit:
554     return;
555 }
556 
AddServiceResolver(const std::string & aName,ServiceResolver * aResolver)557 void MdnsPublisher::ServiceSubscription::AddServiceResolver(const std::string &aName, ServiceResolver *aResolver)
558 {
559     mResolvers[aName].insert(aResolver);
560 }
RemoveServiceResolver(const std::string & aName)561 void MdnsPublisher::ServiceSubscription::RemoveServiceResolver(const std::string &aName)
562 {
563     int numResolvers = 0;
564 
565     VerifyOrExit(mResolvers.find(aName) != mResolvers.end());
566 
567     numResolvers = mResolvers[aName].size();
568 
569     for (auto resolver : mResolvers[aName])
570     {
571         delete resolver;
572     }
573 
574     mResolvers.erase(aName);
575 
576 exit:
577     otbrLogDebug("Removed %d service resolver for instance %s", numResolvers, aName.c_str());
578     return;
579 }
580 
581 } // namespace Android
582 } // namespace otbr
583