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