Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / ot-br-posix / repo / src / mdns / mdns_mdnssd.cpp
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 service based on mDNSResponder.
32  */
33
34 #include "mdns/mdns_mdnssd.hpp"
35
36 #include <algorithm>
37
38 #include <arpa/inet.h>
39 #include <assert.h>
40 #include <errno.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44
45 #include "common/code_utils.hpp"
46 #include "common/logging.hpp"
47 #include "common/time.hpp"
48 #include "utils/strcpy_utils.hpp"
49
50 namespace otbr {
51
52 namespace Mdns {
53
54 static otbrError DNSErrorToOtbrError(DNSServiceErrorType aError)
55 {
56     otbrError error;
57
58     switch (aError)
59     {
60     case kDNSServiceErr_NoError:
61         error = OTBR_ERROR_NONE;
62         break;
63
64     case kDNSServiceErr_NoSuchKey:
65     case kDNSServiceErr_NoSuchName:
66     case kDNSServiceErr_NoSuchRecord:
67         error = OTBR_ERROR_NOT_FOUND;
68         break;
69
70     case kDNSServiceErr_Invalid:
71     case kDNSServiceErr_BadParam:
72     case kDNSServiceErr_BadFlags:
73     case kDNSServiceErr_BadInterfaceIndex:
74         error = OTBR_ERROR_INVALID_ARGS;
75         break;
76
77     case kDNSServiceErr_AlreadyRegistered:
78     case kDNSServiceErr_NameConflict:
79         error = OTBR_ERROR_DUPLICATED;
80         break;
81
82     case kDNSServiceErr_Unsupported:
83         error = OTBR_ERROR_NOT_IMPLEMENTED;
84         break;
85
86     default:
87         error = OTBR_ERROR_MDNS;
88         break;
89     }
90
91     return error;
92 }
93
94 static const char *DNSErrorToString(DNSServiceErrorType aError)
95 {
96     switch (aError)
97     {
98     case kDNSServiceErr_NoError:
99         return "OK";
100
101     case kDNSServiceErr_Unknown:
102         // 0xFFFE FFFF
103         return "Unknown";
104
105     case kDNSServiceErr_NoSuchName:
106         return "No Such Name";
107
108     case kDNSServiceErr_NoMemory:
109         return "No Memory";
110
111     case kDNSServiceErr_BadParam:
112         return "Bad Param";
113
114     case kDNSServiceErr_BadReference:
115         return "Bad Reference";
116
117     case kDNSServiceErr_BadState:
118         return "Bad State";
119
120     case kDNSServiceErr_BadFlags:
121         return "Bad Flags";
122
123     case kDNSServiceErr_Unsupported:
124         return "Unsupported";
125
126     case kDNSServiceErr_NotInitialized:
127         return "Not Initialized";
128
129     case kDNSServiceErr_AlreadyRegistered:
130         return "Already Registered";
131
132     case kDNSServiceErr_NameConflict:
133         return "Name Conflict";
134
135     case kDNSServiceErr_Invalid:
136         return "Invalid";
137
138     case kDNSServiceErr_Firewall:
139         return "Firewall";
140
141     case kDNSServiceErr_Incompatible:
142         // client library incompatible with daemon
143         return "Incompatible";
144
145     case kDNSServiceErr_BadInterfaceIndex:
146         return "Bad Interface Index";
147
148     case kDNSServiceErr_Refused:
149         return "Refused";
150
151     case kDNSServiceErr_NoSuchRecord:
152         return "No Such Record";
153
154     case kDNSServiceErr_NoAuth:
155         return "No Auth";
156
157     case kDNSServiceErr_NoSuchKey:
158         return "No Such Key";
159
160     case kDNSServiceErr_NATTraversal:
161         return "NAT Traversal";
162
163     case kDNSServiceErr_DoubleNAT:
164         return "Double NAT";
165
166     case kDNSServiceErr_BadTime:
167         // Codes up to here existed in Tiger
168         return "Bad Time";
169
170     case kDNSServiceErr_BadSig:
171         return "Bad Sig";
172
173     case kDNSServiceErr_BadKey:
174         return "Bad Key";
175
176     case kDNSServiceErr_Transient:
177         return "Transient";
178
179     case kDNSServiceErr_ServiceNotRunning:
180         // Background daemon not running
181         return "Service Not Running";
182
183     case kDNSServiceErr_NATPortMappingUnsupported:
184         // NAT doesn't support NAT-PMP or UPnP
185         return "NAT Port Mapping Unsupported";
186
187     case kDNSServiceErr_NATPortMappingDisabled:
188         // NAT supports NAT-PMP or UPnP but it's disabled by the administrator
189         return "NAT Port Mapping Disabled";
190
191     case kDNSServiceErr_NoRouter:
192         // No router currently configured (probably no network connectivity)
193         return "No Router";
194
195     case kDNSServiceErr_PollingMode:
196         return "Polling Mode";
197
198     case kDNSServiceErr_Timeout:
199         return "Timeout";
200
201     default:
202         assert(false);
203         return nullptr;
204     }
205 }
206
207 PublisherMDnsSd::PublisherMDnsSd(int aProtocol, const char *aDomain, StateHandler aHandler, void *aContext)
208     : mHostsRef(nullptr)
209     , mDomain(aDomain)
210     , mState(State::kIdle)
211     , mStateHandler(aHandler)
212     , mContext(aContext)
213 {
214     OTBR_UNUSED_VARIABLE(aProtocol);
215 }
216
217 PublisherMDnsSd::~PublisherMDnsSd(void)
218 {
219     Stop();
220 }
221
222 otbrError PublisherMDnsSd::Start(void)
223 {
224     mState = State::kReady;
225     mStateHandler(mContext, State::kReady);
226     return OTBR_ERROR_NONE;
227 }
228
229 bool PublisherMDnsSd::IsStarted(void) const
230 {
231     return mState == State::kReady;
232 }
233
234 void PublisherMDnsSd::Stop(void)
235 {
236     VerifyOrExit(mState == State::kReady);
237
238     for (Service &service : mServices)
239     {
240         otbrLog(OTBR_LOG_INFO, "[mdns] remove service %s.%s", service.mName, service.mType);
241         DNSServiceRefDeallocate(service.mService);
242     }
243     mServices.clear();
244
245     otbrLog(OTBR_LOG_INFO, "[mdns] remove all hosts");
246     DNSServiceRefDeallocate(mHostsRef);
247     mHostsRef = nullptr;
248     mHosts.clear();
249
250 exit:
251     return;
252 }
253
254 void PublisherMDnsSd::UpdateFdSet(fd_set & aReadFdSet,
255                                   fd_set & aWriteFdSet,
256                                   fd_set & aErrorFdSet,
257                                   int &    aMaxFd,
258                                   timeval &aTimeout)
259 {
260     OTBR_UNUSED_VARIABLE(aWriteFdSet);
261     OTBR_UNUSED_VARIABLE(aErrorFdSet);
262     OTBR_UNUSED_VARIABLE(aTimeout);
263
264     for (Service &service : mServices)
265     {
266         assert(service.mService != nullptr);
267
268         int fd = DNSServiceRefSockFD(service.mService);
269
270         assert(fd != -1);
271
272         FD_SET(fd, &aReadFdSet);
273
274         if (fd > aMaxFd)
275         {
276             aMaxFd = fd;
277         }
278     }
279
280     if (mHostsRef != nullptr)
281     {
282         int fd = DNSServiceRefSockFD(mHostsRef);
283
284         assert(fd != -1);
285
286         FD_SET(fd, &aReadFdSet);
287
288         if (fd > aMaxFd)
289         {
290             aMaxFd = fd;
291         }
292     }
293 }
294
295 void PublisherMDnsSd::Process(const fd_set &aReadFdSet, const fd_set &aWriteFdSet, const fd_set &aErrorFdSet)
296 {
297     std::vector<DNSServiceRef> readyServices;
298
299     OTBR_UNUSED_VARIABLE(aWriteFdSet);
300     OTBR_UNUSED_VARIABLE(aErrorFdSet);
301
302     for (Service &service : mServices)
303     {
304         int fd = DNSServiceRefSockFD(service.mService);
305
306         if (FD_ISSET(fd, &aReadFdSet))
307         {
308             readyServices.push_back(service.mService);
309         }
310     }
311
312     if (mHostsRef != nullptr)
313     {
314         int fd = DNSServiceRefSockFD(mHostsRef);
315
316         if (FD_ISSET(fd, &aReadFdSet))
317         {
318             readyServices.push_back(mHostsRef);
319         }
320     }
321
322     for (DNSServiceRef serviceRef : readyServices)
323     {
324         DNSServiceErrorType error = DNSServiceProcessResult(serviceRef);
325
326         if (error != kDNSServiceErr_NoError)
327         {
328             otbrLog(OTBR_LOG_WARNING, "[mdns] DNSServiceProcessResult failed: %s", DNSErrorToString(error));
329         }
330     }
331 }
332
333 void PublisherMDnsSd::HandleServiceRegisterResult(DNSServiceRef         aService,
334                                                   const DNSServiceFlags aFlags,
335                                                   DNSServiceErrorType   aError,
336                                                   const char *          aName,
337                                                   const char *          aType,
338                                                   const char *          aDomain,
339                                                   void *                aContext)
340 {
341     static_cast<PublisherMDnsSd *>(aContext)->HandleServiceRegisterResult(aService, aFlags, aError, aName, aType,
342                                                                           aDomain);
343 }
344
345 void PublisherMDnsSd::HandleServiceRegisterResult(DNSServiceRef         aServiceRef,
346                                                   const DNSServiceFlags aFlags,
347                                                   DNSServiceErrorType   aError,
348                                                   const char *          aName,
349                                                   const char *          aType,
350                                                   const char *          aDomain)
351 {
352     OTBR_UNUSED_VARIABLE(aDomain);
353
354     otbrError       error = DNSErrorToOtbrError(aError);
355     std::string     originalInstanceName;
356     ServiceIterator service = FindPublishedService(aServiceRef);
357
358     VerifyOrExit(service != mServices.end());
359
360     // mDNSResponder could auto-rename the service instance name when name conflict
361     // is detected. In this case, `aName` may not match `service->mName` and we
362     // should use the original `service->mName` to find associated SRP service.
363     originalInstanceName = service->mName;
364
365     otbrLog(OTBR_LOG_INFO, "[mdns] received reply for service %s.%s", originalInstanceName.c_str(), aType);
366
367     if (originalInstanceName != aName)
368     {
369         otbrLog(OTBR_LOG_INFO, "[mdns] service %s.%s renamed to %s.%s", originalInstanceName.c_str(), aType, aName,
370                 aType);
371     }
372
373     if (aError == kDNSServiceErr_NoError)
374     {
375         otbrLog(OTBR_LOG_INFO, "[mdns] successfully registered service %s.%s", originalInstanceName.c_str(), aType);
376         if (aFlags & kDNSServiceFlagsAdd)
377         {
378             RecordService(originalInstanceName.c_str(), aType, aServiceRef);
379         }
380         else
381         {
382             DiscardService(originalInstanceName.c_str(), aType, aServiceRef);
383         }
384     }
385     else
386     {
387         otbrLog(OTBR_LOG_ERR, "[mdns] failed to register service %s.%s: %s", originalInstanceName.c_str(), aType,
388                 DNSErrorToString(aError));
389         DiscardService(originalInstanceName.c_str(), aType, aServiceRef);
390     }
391
392     if (mServiceHandler != nullptr)
393     {
394         // TODO: pass the renewed service instance name back to SRP server handler.
395         mServiceHandler(originalInstanceName.c_str(), aType, error, mServiceHandlerContext);
396     }
397
398 exit:
399     return;
400 }
401
402 void PublisherMDnsSd::DiscardService(const char *aName, const char *aType, DNSServiceRef aServiceRef)
403 {
404     ServiceIterator service = FindPublishedService(aName, aType);
405
406     if (service != mServices.end())
407     {
408         assert(aServiceRef == nullptr || aServiceRef == service->mService);
409
410         otbrLog(OTBR_LOG_INFO, "[mdns] remove service ref %p", service->mService);
411
412         DNSServiceRefDeallocate(service->mService);
413         mServices.erase(service);
414     }
415 }
416
417 void PublisherMDnsSd::RecordService(const char *aName, const char *aType, DNSServiceRef aServiceRef)
418 {
419     ServiceIterator service = FindPublishedService(aName, aType);
420
421     if (service == mServices.end())
422     {
423         Service newService;
424
425         otbrLog(OTBR_LOG_INFO, "[mdns] add service: %s.%s (ref: %p)", aName, aType, aServiceRef);
426
427         strcpy(newService.mName, aName);
428         strcpy(newService.mType, aType);
429         newService.mService = aServiceRef;
430         mServices.push_back(newService);
431     }
432     else
433     {
434         assert(service->mService == aServiceRef);
435     }
436 }
437
438 otbrError PublisherMDnsSd::PublishService(const char *   aHostName,
439                                           uint16_t       aPort,
440                                           const char *   aName,
441                                           const char *   aType,
442                                           const TxtList &aTxtList)
443 {
444     otbrError       ret   = OTBR_ERROR_NONE;
445     int             error = 0;
446     uint8_t         txt[kMaxSizeOfTxtRecord];
447     uint16_t        txtLength  = sizeof(txt);
448     ServiceIterator service    = FindPublishedService(aName, aType);
449     DNSServiceRef   serviceRef = nullptr;
450     char            fullHostName[kMaxSizeOfDomain];
451
452     if (aHostName != nullptr)
453     {
454         HostIterator host = FindPublishedHost(aHostName);
455
456         // Make sure that the host has been published.
457         VerifyOrExit(host != mHosts.end(), ret = OTBR_ERROR_INVALID_ARGS);
458         SuccessOrExit(error = MakeFullName(fullHostName, sizeof(fullHostName), aHostName));
459     }
460
461     SuccessOrExit(ret = EncodeTxtData(aTxtList, txt, txtLength));
462
463     if (service != mServices.end())
464     {
465         otbrLog(OTBR_LOG_INFO, "[mdns] update service %s.%s", aName, aType);
466
467         // Setting TTL to 0 to use default value.
468         SuccessOrExit(error = DNSServiceUpdateRecord(service->mService, nullptr, 0, txtLength, txt, /* ttl */ 0));
469
470         if (mServiceHandler != nullptr)
471         {
472             mServiceHandler(aName, aType, DNSErrorToOtbrError(error), mServiceHandlerContext);
473         }
474     }
475     else
476     {
477         SuccessOrExit(error = DNSServiceRegister(&serviceRef, /* flags */ 0, kDNSServiceInterfaceIndexAny, aName, aType,
478                                                  mDomain, (aHostName != nullptr) ? fullHostName : nullptr, htons(aPort),
479                                                  txtLength, txt, HandleServiceRegisterResult, this));
480         RecordService(aName, aType, serviceRef);
481     }
482
483 exit:
484     if (error != kDNSServiceErr_NoError)
485     {
486         ret = OTBR_ERROR_MDNS;
487         otbrLog(OTBR_LOG_ERR, "[mdns] failed to publish service for mdnssd error: %s!", DNSErrorToString(error));
488     }
489     return ret;
490 }
491
492 otbrError PublisherMDnsSd::UnpublishService(const char *aName, const char *aType)
493 {
494     DiscardService(aName, aType);
495     return OTBR_ERROR_NONE;
496 }
497
498 otbrError PublisherMDnsSd::DiscardHost(const char *aName, bool aSendGoodbye)
499 {
500     otbrError    ret   = OTBR_ERROR_NONE;
501     int          error = 0;
502     HostIterator host  = FindPublishedHost(aName);
503
504     VerifyOrExit(mHostsRef != nullptr && host != mHosts.end());
505
506     otbrLog(OTBR_LOG_INFO, "[mdns] remove host: %s (record ref: %p)", host->mName, host->mRecord);
507
508     if (aSendGoodbye)
509     {
510         // The Bonjour mDNSResponder somehow doesn't send goodbye message for the AAAA record when it is
511         // removed by `DNSServiceRemoveRecord`. Per RFC 6762, a goodbye message of a record sets its TTL
512         // to zero but the receiver should record the TTL of 1 and flushes the cache 1 second later. Here
513         // we remove the AAAA record after updating its TTL to 1 second. This has the same effect as
514         // sending a goodbye message.
515         // TODO: resolve the goodbye issue with Bonjour mDNSResponder.
516         error = DNSServiceUpdateRecord(mHostsRef, host->mRecord, kDNSServiceFlagsUnique, host->mAddress.size(),
517                                        &host->mAddress.front(), /* ttl */ 1);
518         // Do not SuccessOrExit so that we always erase the host entry.
519
520         DNSServiceRemoveRecord(mHostsRef, host->mRecord, /* flags */ 0);
521     }
522     mHosts.erase(host);
523
524 exit:
525     if (error != kDNSServiceErr_NoError)
526     {
527         ret = OTBR_ERROR_MDNS;
528         otbrLog(OTBR_LOG_ERR, "[mdns] failed to remove host %s for mdnssd error: %s!", aName, DNSErrorToString(error));
529     }
530     return ret;
531 }
532
533 void PublisherMDnsSd::RecordHost(const char *   aName,
534                                  const uint8_t *aAddress,
535                                  uint8_t        aAddressLength,
536                                  DNSRecordRef   aRecordRef)
537 {
538     HostIterator host = FindPublishedHost(aName);
539
540     if (host == mHosts.end())
541     {
542         Host newHost;
543
544         otbrLog(OTBR_LOG_INFO, "[mdns] add new host %s", aName);
545
546         strcpy(newHost.mName, aName);
547         std::copy(aAddress, aAddress + aAddressLength, newHost.mAddress.begin());
548         newHost.mRecord = aRecordRef;
549         mHosts.push_back(newHost);
550     }
551     else
552     {
553         otbrLog(OTBR_LOG_INFO, "[mdns] update existing host %s", host->mName);
554
555         // The address of the host may be updated.
556         std::copy(aAddress, aAddress + aAddressLength, host->mAddress.begin());
557         assert(host->mRecord == aRecordRef);
558     }
559 }
560
561 otbrError PublisherMDnsSd::PublishHost(const char *aName, const uint8_t *aAddress, uint8_t aAddressLength)
562 {
563     otbrError    ret   = OTBR_ERROR_NONE;
564     int          error = 0;
565     char         fullName[kMaxSizeOfDomain];
566     HostIterator host = FindPublishedHost(aName);
567
568     // Supports only IPv6 for now, may support IPv4 in the future.
569     VerifyOrExit(aAddressLength == OTBR_IP6_ADDRESS_SIZE, error = OTBR_ERROR_INVALID_ARGS);
570
571     SuccessOrExit(ret = MakeFullName(fullName, sizeof(fullName), aName));
572
573     if (mHostsRef == nullptr)
574     {
575         SuccessOrExit(error = DNSServiceCreateConnection(&mHostsRef));
576     }
577
578     if (host != mHosts.end())
579     {
580         otbrLog(OTBR_LOG_INFO, "[mdns] update existing host %s", aName);
581         SuccessOrExit(error = DNSServiceUpdateRecord(mHostsRef, host->mRecord, kDNSServiceFlagsUnique, aAddressLength,
582                                                      aAddress, /* ttl */ 0));
583
584         RecordHost(aName, aAddress, aAddressLength, host->mRecord);
585         if (mHostHandler != nullptr)
586         {
587             mHostHandler(aName, DNSErrorToOtbrError(error), mHostHandlerContext);
588         }
589     }
590     else
591     {
592         DNSRecordRef record;
593
594         otbrLog(OTBR_LOG_INFO, "[mdns] publish new host %s", aName);
595         SuccessOrExit(error = DNSServiceRegisterRecord(mHostsRef, &record, kDNSServiceFlagsUnique,
596                                                        kDNSServiceInterfaceIndexAny, fullName, kDNSServiceType_AAAA,
597                                                        kDNSServiceClass_IN, aAddressLength, aAddress, /* ttl */ 0,
598                                                        HandleRegisterHostResult, this));
599         RecordHost(aName, aAddress, aAddressLength, record);
600     }
601
602 exit:
603     if (error != kDNSServiceErr_NoError)
604     {
605         if (mHostsRef != nullptr)
606         {
607             DNSServiceRefDeallocate(mHostsRef);
608             mHostsRef = nullptr;
609         }
610
611         ret = OTBR_ERROR_MDNS;
612         otbrLog(OTBR_LOG_ERR, "[mdns] failed to publish/update host %s for mdnssd error: %s!", aName,
613                 DNSErrorToString(error));
614     }
615     return ret;
616 }
617
618 otbrError PublisherMDnsSd::UnpublishHost(const char *aName)
619 {
620     return DiscardHost(aName);
621 }
622
623 void PublisherMDnsSd::HandleRegisterHostResult(DNSServiceRef       aHostsConnection,
624                                                DNSRecordRef        aHostRecord,
625                                                DNSServiceFlags     aFlags,
626                                                DNSServiceErrorType aErrorCode,
627                                                void *              aContext)
628 {
629     static_cast<PublisherMDnsSd *>(aContext)->HandleRegisterHostResult(aHostsConnection, aHostRecord, aFlags,
630                                                                        aErrorCode);
631 }
632
633 void PublisherMDnsSd::HandleRegisterHostResult(DNSServiceRef       aHostsConnection,
634                                                DNSRecordRef        aHostRecord,
635                                                DNSServiceFlags     aFlags,
636                                                DNSServiceErrorType aErrorCode)
637 {
638     OTBR_UNUSED_VARIABLE(aHostsConnection);
639     OTBR_UNUSED_VARIABLE(aFlags);
640
641     HostIterator host = FindPublishedHost(aHostRecord);
642     std::string  hostName;
643
644     VerifyOrExit(host != mHosts.end());
645     hostName = host->mName;
646
647     otbrLog(OTBR_LOG_INFO, "[mdns] received reply for host %s", hostName.c_str());
648
649     if (aErrorCode == kDNSServiceErr_NoError)
650     {
651         otbrLog(OTBR_LOG_INFO, "[mdns] successfully registered host %s", hostName.c_str());
652     }
653     else
654     {
655         otbrLog(OTBR_LOG_WARNING, "[mdns] failed to register host %s for mdnssd error: %s", hostName.c_str(),
656                 DNSErrorToString(aErrorCode));
657
658         DiscardHost(hostName.c_str(), /* aSendGoodbye */ false);
659     }
660
661     if (mHostHandler != nullptr)
662     {
663         mHostHandler(hostName.c_str(), DNSErrorToOtbrError(aErrorCode), mHostHandlerContext);
664     }
665
666 exit:
667     return;
668 }
669
670 otbrError PublisherMDnsSd::MakeFullName(char *aFullName, size_t aFullNameLength, const char *aName)
671 {
672     otbrError   error      = OTBR_ERROR_NONE;
673     size_t      nameLength = strlen(aName);
674     const char *domain     = (mDomain == nullptr) ? "local." : mDomain;
675
676     VerifyOrExit(nameLength <= kMaxSizeOfHost, error = OTBR_ERROR_INVALID_ARGS);
677
678     assert(aFullNameLength >= nameLength + sizeof(".") + strlen(domain));
679
680     strcpy(aFullName, aName);
681     strcpy(aFullName + nameLength, ".");
682     strcpy(aFullName + nameLength + 1, domain);
683
684 exit:
685     return error;
686 }
687
688 PublisherMDnsSd::ServiceIterator PublisherMDnsSd::FindPublishedService(const char *aName, const char *aType)
689 {
690     return std::find_if(mServices.begin(), mServices.end(), [&aName, aType](const Service &service) {
691         return strcmp(aName, service.mName) == 0 && IsServiceTypeEqual(aType, service.mType);
692     });
693 }
694
695 PublisherMDnsSd::ServiceIterator PublisherMDnsSd::FindPublishedService(const DNSServiceRef &aServiceRef)
696 {
697     return std::find_if(mServices.begin(), mServices.end(),
698                         [&aServiceRef](const Service &service) { return service.mService == aServiceRef; });
699 }
700
701 PublisherMDnsSd::HostIterator PublisherMDnsSd::FindPublishedHost(const DNSRecordRef &aRecordRef)
702 {
703     return std::find_if(mHosts.begin(), mHosts.end(),
704                         [&aRecordRef](const Host &host) { return host.mRecord == aRecordRef; });
705 }
706
707 PublisherMDnsSd::HostIterator PublisherMDnsSd::FindPublishedHost(const char *aHostName)
708 {
709     return std::find_if(mHosts.begin(), mHosts.end(),
710                         [&aHostName](const Host &host) { return strcmp(host.mName, aHostName) == 0; });
711 }
712
713 Publisher *Publisher::Create(int aFamily, const char *aDomain, StateHandler aHandler, void *aContext)
714 {
715     return new PublisherMDnsSd(aFamily, aDomain, aHandler, aContext);
716 }
717
718 void Publisher::Destroy(Publisher *aPublisher)
719 {
720     delete static_cast<PublisherMDnsSd *>(aPublisher);
721 }
722
723 } // namespace Mdns
724
725 } // namespace otbr