From 2116981ce43c355c4a11e34b68561818ccfe7396 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas Date: Wed, 14 Sep 2022 21:04:43 +0200 Subject: [PATCH] =?UTF-8?q?[darwin]=20Update=20DnssdHostNameRegistrar=20to?= =?UTF-8?q?=20use=20the=20network=20framework=20i=E2=80=A6=20(#22587)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tests/chiptest/lsan-mac-suppressions.txt | 23 ++ src/platform/Darwin/BUILD.gn | 1 + src/platform/Darwin/DnssdContexts.cpp | 19 +- .../Darwin/DnssdHostNameRegistrar.cpp | 381 +++++++++++++----- src/platform/Darwin/DnssdHostNameRegistrar.h | 113 ++---- src/platform/Darwin/DnssdImpl.cpp | 18 +- src/platform/Darwin/DnssdImpl.h | 14 +- 7 files changed, 356 insertions(+), 213 deletions(-) diff --git a/scripts/tests/chiptest/lsan-mac-suppressions.txt b/scripts/tests/chiptest/lsan-mac-suppressions.txt index 859d82cebf6e62..8d1bd5719713ee 100644 --- a/scripts/tests/chiptest/lsan-mac-suppressions.txt +++ b/scripts/tests/chiptest/lsan-mac-suppressions.txt @@ -21,3 +21,26 @@ leak:ERR_get_state # TODO: https://github.com/project-chip/connectedhomeip/issues/22333 leak:[MTRBaseCluster* subscribeAttribute*WithParams:subscriptionEstablished:reportHandler:] + +#TODO: Figure out why nw_path_monitor_create leaks. The leak can be reproduced using: +# -- testFile.cpp +# +##include +# +#int main(int argc, char **argv) { +# auto monitor = nw_path_monitor_create(); +# nw_release(monitor); +# return 0; +#} +# +# -- testFile.mm (with -fobj-arc) +##include +# +#int main(int argc, char **argv) { +# __auto_type monitor = nw_path_monitor_create(); +# return 0; +#} +leak:nw_path_monitor_create + +# TODO: See the previous comment about nw_path_monitor_create, since it also applies to nw_path_monitor_start +leak:nw_path_monitor_start diff --git a/src/platform/Darwin/BUILD.gn b/src/platform/Darwin/BUILD.gn index 29fddf18d99e1d..da17b8af7042a6 100644 --- a/src/platform/Darwin/BUILD.gn +++ b/src/platform/Darwin/BUILD.gn @@ -24,6 +24,7 @@ config("darwin_config") { "CoreFoundation.framework", "CoreBluetooth.framework", "Foundation.framework", + "Network.framework", ] if (current_os == "mac") { diff --git a/src/platform/Darwin/DnssdContexts.cpp b/src/platform/Darwin/DnssdContexts.cpp index b3771bb980808b..4128bfa24e431c 100644 --- a/src/platform/Darwin/DnssdContexts.cpp +++ b/src/platform/Darwin/DnssdContexts.cpp @@ -272,23 +272,10 @@ void RegisterContext::DispatchSuccess() { std::string typeWithoutSubTypes = GetFullTypeWithoutSubTypes(mType); callback(context, typeWithoutSubTypes.c_str(), mInstanceName.c_str(), CHIP_NO_ERROR); -} -RegisterRecordContext::RegisterRecordContext(RegisterContext * context) -{ - type = ContextType::RegisterRecord; - mRegisterContext = context; -} - -void RegisterRecordContext::DispatchFailure(DNSServiceErrorType err) -{ - mRegisterContext->Finalize(err); - MdnsContexts::GetInstance().Remove(this); -} - -void RegisterRecordContext::DispatchSuccess() -{ - mRegisterContext->Finalize(); + // Once a service has been properly published it is normally unreachable because the hostname has not yet been + // registered against the dns daemon. Register the records mapping the hostname to our IP. + mHostNameRegistrar.Register(); } BrowseContext::BrowseContext(void * cbContext, DnssdBrowseCallback cb, DnssdServiceProtocol cbContextProtocol) diff --git a/src/platform/Darwin/DnssdHostNameRegistrar.cpp b/src/platform/Darwin/DnssdHostNameRegistrar.cpp index d4d25fd61ab200..2e63ff26d2f73d 100644 --- a/src/platform/Darwin/DnssdHostNameRegistrar.cpp +++ b/src/platform/Darwin/DnssdHostNameRegistrar.cpp @@ -17,6 +17,7 @@ #include "DnssdHostNameRegistrar.h" #include "DnssdImpl.h" +#include "MdnsError.h" #include #include @@ -24,6 +25,10 @@ #include #include +#include + +#include + constexpr DNSServiceFlags kRegisterRecordFlags = kDNSServiceFlagsShared; namespace chip { @@ -31,172 +36,352 @@ namespace Dnssd { namespace { -static void OnRegisterRecord(DNSServiceRef sdRef, DNSRecordRef recordRef, DNSServiceFlags flags, DNSServiceErrorType err, - void * context) +#if CHIP_DETAIL_LOGGING +constexpr const char * kPathStatusInvalid = "Invalid"; +constexpr const char * kPathStatusUnsatisfied = "Unsatisfied"; +constexpr const char * kPathStatusSatisfied = "Satisfied"; +constexpr const char * kPathStatusSatisfiable = "Satisfiable"; +constexpr const char * kPathStatusUnknown = "Unknown"; + +constexpr const char * kInterfaceTypeCellular = "Cellular"; +constexpr const char * kInterfaceTypeWiFi = "WiFi"; +constexpr const char * kInterfaceTypeWired = "Wired"; +constexpr const char * kInterfaceTypeLoopback = "Loopback"; +constexpr const char * kInterfaceTypeOther = "Other"; +constexpr const char * kInterfaceTypeUnknown = "Unknown"; + +const char * GetPathStatusString(nw_path_status_t status) { - ChipLogDetail(Discovery, "Mdns: %s flags: %d", __func__, flags); - - auto sdCtx = reinterpret_cast(context); + const char * str = nullptr; - auto & registrar = sdCtx->mRegisterContext->mHostNameRegistrar; - if (!registrar.IncrementRegistrationCount(err)) + if (status == nw_path_status_invalid) { - sdCtx->Finalize(registrar.HasRegisteredRegistrant() ? kDNSServiceErr_NoError : kDNSServiceErr_Unknown); + str = kPathStatusInvalid; + } + else if (status == nw_path_status_unsatisfied) + { + str = kPathStatusUnsatisfied; + } + else if (status == nw_path_status_satisfied) + { + str = kPathStatusSatisfied; + } + else if (status == nw_path_status_satisfiable) + { + str = kPathStatusSatisfiable; + } + else + { + str = kPathStatusUnknown; } -} -} // namespace + return str; +} -bool InterfaceRegistrant::Init(const struct ifaddrs * ifa, Inet::IPAddressType addressType, uint32_t interfaceId) +const char * GetInterfaceTypeString(nw_interface_type_t type) { - VerifyOrReturnValue(ifa != nullptr, false); - VerifyOrReturnValue(ifa->ifa_addr != nullptr, false); - VerifyOrReturnValue(HasValidFlags(ifa->ifa_flags), false); - VerifyOrReturnValue(IsValidInterfaceId(interfaceId, if_nametoindex(ifa->ifa_name)), false); - VerifyOrReturnValue(HasValidType(addressType, ifa->ifa_addr->sa_family), false); + const char * str = nullptr; - // The incoming interface id can be kDNSServiceInterfaceIndexAny, but here what needs to be done is to - // associate a given ip with a specific interface id, so the incoming interface id is used as a hint - // to validate if the current interface is of interest or not, but it is not what is stored internally. - mInterfaceId = if_nametoindex(ifa->ifa_name); - mInterfaceAddressType = ifa->ifa_addr->sa_family; - - if (IsIPv4()) + if (type == nw_interface_type_cellular) + { + str = kInterfaceTypeCellular; + } + else if (type == nw_interface_type_wifi) { - mInterfaceAddress.ipv4 = reinterpret_cast(ifa->ifa_addr)->sin_addr; + str = kInterfaceTypeWiFi; + } + else if (type == nw_interface_type_wired) + { + str = kInterfaceTypeWired; + } + else if (type == nw_interface_type_loopback) + { + str = kInterfaceTypeLoopback; + } + else if (type == nw_interface_type_other) + { + str = kInterfaceTypeOther; } else { - mInterfaceAddress.ipv6 = reinterpret_cast(ifa->ifa_addr)->sin6_addr; + str = kInterfaceTypeUnknown; } - return true; + return str; } -DNSServiceErrorType InterfaceRegistrant::Register(DNSServiceRef sdRef, RegisterRecordContext * sdCtx, const char * hostname) const +void LogDetails(uint32_t interfaceId, InetInterfacesVector inetInterfaces, Inet6InterfacesVector inet6Interfaces) { - LogDetail(); + for (auto & inetInterface : inetInterfaces) + { + if (interfaceId == inetInterface.first) + { + char addr[INET_ADDRSTRLEN] = {}; + inet_ntop(AF_INET, &inetInterface.second, addr, sizeof(addr)); + ChipLogDetail(Discovery, "\t\t* ipv4: %s", addr); + } + } - uint16_t rrtype = IsIPv4() ? kDNSServiceType_A : kDNSServiceType_AAAA; - uint16_t rdlen = IsIPv4() ? sizeof(in_addr) : sizeof(in6_addr); - const void * rdata = IsIPv4() ? static_cast(GetIPv4()) : static_cast(GetIPv6()); + for (auto & inet6Interface : inet6Interfaces) + { + if (interfaceId == inet6Interface.first) + { + char addr[INET6_ADDRSTRLEN] = {}; + inet_ntop(AF_INET6, &inet6Interface.second, addr, sizeof(addr)); + ChipLogDetail(Discovery, "\t\t* ipv6: %s", addr); + } + } +} - DNSRecordRef dnsRecordRef; - return DNSServiceRegisterRecord(sdRef, &dnsRecordRef, kRegisterRecordFlags, mInterfaceId, hostname, rrtype, kDNSServiceClass_IN, - rdlen, rdata, 0, OnRegisterRecord, sdCtx); +void LogDetails(nw_path_t path) +{ + auto status = nw_path_get_status(path); + ChipLogDetail(Discovery, "Status: %s", GetPathStatusString(status)); } -bool InterfaceRegistrant::HasValidFlags(unsigned int flags) +void LogDetails(InetInterfacesVector inetInterfaces, Inet6InterfacesVector inet6Interfaces) { - return !(flags & IFF_POINTOPOINT) && (flags & IFF_RUNNING) && (flags & IFF_MULTICAST); + std::set interfaceIds; + for (auto & inetInterface : inetInterfaces) + { + interfaceIds.insert(inetInterface.first); + } + + for (auto & inet6Interface : inet6Interfaces) + { + interfaceIds.insert(inet6Interface.first); + } + + for (auto interfaceId : interfaceIds) + { + char interfaceName[IFNAMSIZ] = {}; + if_indextoname(interfaceId, interfaceName); + ChipLogDetail(Discovery, "\t%s (%u)", interfaceName, interfaceId); + LogDetails(interfaceId, inetInterfaces, inet6Interfaces); + } } -bool InterfaceRegistrant::HasValidType(Inet::IPAddressType addressType, const sa_family_t addressFamily) +void LogDetails(nw_interface_t interface, InetInterfacesVector inetInterfaces, Inet6InterfacesVector inet6Interfaces) { - bool useIPv4 = addressType == Inet::IPAddressType::kIPv4 || addressType == Inet::IPAddressType::kAny; - bool useIPv6 = addressType == Inet::IPAddressType::kIPv6 || addressType == Inet::IPAddressType::kAny; + auto interfaceId = nw_interface_get_index(interface); + auto interfaceName = nw_interface_get_name(interface); + auto interfaceType = nw_interface_get_type(interface); + ChipLogDetail(Discovery, "\t%s (%u / %s)", interfaceName, interfaceId, GetInterfaceTypeString(interfaceType)); + LogDetails(interfaceId, inetInterfaces, inet6Interfaces); +} +#endif // CHIP_DETAIL_LOGGING - return (useIPv6 && addressFamily == AF_INET6) || (useIPv4 && addressFamily == AF_INET); +bool HasValidFlags(unsigned int flags, bool allowLoopbackOnly) +{ + VerifyOrReturnValue(!allowLoopbackOnly || (flags & IFF_LOOPBACK), false); + VerifyOrReturnValue(!(flags & IFF_POINTOPOINT), false); + VerifyOrReturnValue((flags & IFF_RUNNING), false); + VerifyOrReturnValue((flags & IFF_MULTICAST), false); + return true; +} + +bool HasValidNetworkType(nw_interface_t interface) +{ + auto interfaceType = nw_interface_get_type(interface); + return interfaceType == nw_interface_type_wifi || interfaceType == nw_interface_type_wired; } -bool InterfaceRegistrant::IsValidInterfaceId(uint32_t targetInterfaceId, unsigned int currentInterfaceId) +bool IsValidInterfaceId(uint32_t targetInterfaceId, nw_interface_t interface) { + auto currentInterfaceId = nw_interface_get_index(interface); return targetInterfaceId == kDNSServiceInterfaceIndexAny || targetInterfaceId == currentInterfaceId; } -void InterfaceRegistrant::LogDetail() const +void ShouldUseVersion(chip::Inet::IPAddressType addressType, bool & shouldUseIPv4, bool & shouldUseIPv6) { - char interfaceName[IFNAMSIZ] = {}; - VerifyOrReturn(if_indextoname(mInterfaceId, interfaceName) != nullptr); +#if INET_CONFIG_ENABLE_IPV4 + shouldUseIPv4 = addressType == Inet::IPAddressType::kIPv4 || addressType == Inet::IPAddressType::kAny; +#else + shouldUseIPv4 = false; +#endif // INET_CONFIG_ENABLE_IPV4 + shouldUseIPv6 = addressType == Inet::IPAddressType::kIPv6 || addressType == Inet::IPAddressType::kAny; +} - if (IsIPv4()) - { - char addr[INET_ADDRSTRLEN] = {}; - inet_ntop(AF_INET, GetIPv4(), addr, sizeof(addr)); - ChipLogDetail(Discovery, "\tInterface: %s (%u) ipv4: %s", interfaceName, mInterfaceId, addr); - } - else +static void OnRegisterRecord(DNSServiceRef sdRef, DNSRecordRef recordRef, DNSServiceFlags flags, DNSServiceErrorType err, + void * context) +{ + ChipLogDetail(Discovery, "Mdns: %s flags: %d", __func__, flags); + if (kDNSServiceErr_NoError != err) { - char addr[INET6_ADDRSTRLEN] = {}; - inet_ntop(AF_INET6, GetIPv6(), addr, sizeof(addr)); - ChipLogDetail(Discovery, "\tInterface: %s (%u) ipv6: %s", interfaceName, mInterfaceId, addr); + ChipLogError(Discovery, "%s (%s)", __func__, Error::ToString(err)); } } -bool HostNameRegistrar::Init(const char * hostname, Inet::IPAddressType addressType, uint32_t interfaceId) +void GetInterfaceAddresses(uint32_t interfaceId, chip::Inet::IPAddressType addressType, InetInterfacesVector & inetInterfaces, + Inet6InterfacesVector & inet6Interfaces, bool searchLoopbackOnly = false) { - mHostName = hostname; - - // When the target interface is kDNSServiceInterfaceIndexLocalOnly, there is no need to map the hostname to - // an IP address. - VerifyOrReturnValue(interfaceId != kDNSServiceInterfaceIndexLocalOnly, true); + bool shouldUseIPv4, shouldUseIPv6; + ShouldUseVersion(addressType, shouldUseIPv4, shouldUseIPv6); - struct ifaddrs * ifap; - VerifyOrReturnValue(getifaddrs(&ifap) >= 0, false); + ifaddrs * ifap; + VerifyOrReturn(getifaddrs(&ifap) >= 0); - for (struct ifaddrs * ifa = ifap; ifa; ifa = ifa->ifa_next) + for (struct ifaddrs * ifa = ifap; ifa != nullptr; ifa = ifa->ifa_next) { - InterfaceRegistrant registrant; - if (registrant.Init(ifa, addressType, interfaceId)) + auto interfaceAddress = ifa->ifa_addr; + if (interfaceAddress == nullptr) { - mRegistry.push_back(registrant); + continue; + } + + if (!HasValidFlags(ifa->ifa_flags, searchLoopbackOnly)) + { + continue; + } + + auto currentInterfaceId = if_nametoindex(ifa->ifa_name); + if (interfaceId != kDNSServiceInterfaceIndexAny && interfaceId != currentInterfaceId) + { + continue; + } + + if (shouldUseIPv4 && (AF_INET == interfaceAddress->sa_family)) + { + auto inetAddress = reinterpret_cast(interfaceAddress)->sin_addr; + inetInterfaces.push_back(InetInterface(currentInterfaceId, inetAddress)); + } + else if (shouldUseIPv6 && (AF_INET6 == interfaceAddress->sa_family)) + { + auto inet6Address = reinterpret_cast(interfaceAddress)->sin6_addr; + inet6Interfaces.push_back(Inet6Interface(currentInterfaceId, inet6Address)); } } freeifaddrs(ifap); +} +} // namespace - return mRegistry.size() != 0; +void HostNameRegistrar::Init(const char * hostname, Inet::IPAddressType addressType, uint32_t interfaceId) +{ + mHostname = hostname; + mInterfaceId = interfaceId; + mAddressType = addressType; + mServiceRef = nullptr; + mInterfaceMonitor = nullptr; } -CHIP_ERROR HostNameRegistrar::Register(RegisterContext * registerCtx) +CHIP_ERROR HostNameRegistrar::Register() { // If the target interface is kDNSServiceInterfaceIndexLocalOnly, there are no interfaces to register against // the dns daemon. - if (mRegistry.size() == 0) - { - return registerCtx->Finalize(); - } + VerifyOrReturnError(!IsLocalOnly(), CHIP_NO_ERROR); + + return StartMonitorInterfaces(^(InetInterfacesVector inetInterfaces, Inet6InterfacesVector inet6Interfaces) { + ReturnOnFailure(StartSharedConnection()); + RegisterInterfaces(inetInterfaces, kDNSServiceType_A); + RegisterInterfaces(inet6Interfaces, kDNSServiceType_AAAA); + }); +} + +CHIP_ERROR HostNameRegistrar::RegisterInterface(uint32_t interfaceId, uint16_t rtype, const void * rdata, uint16_t rdlen) +{ + DNSRecordRef dnsRecordRef; + auto err = DNSServiceRegisterRecord(mServiceRef, &dnsRecordRef, kRegisterRecordFlags, interfaceId, mHostname.c_str(), rtype, + kDNSServiceClass_IN, rdlen, rdata, 0, OnRegisterRecord, nullptr); + return Error::ToChipError(err); +} + +void HostNameRegistrar::Unregister() +{ + // If the target interface is kDNSServiceInterfaceIndexLocalOnly, there are no interfaces to register against + // the dns daemon. + VerifyOrReturn(!IsLocalOnly()); + + StopMonitorInterfaces(); + StopSharedConnection(); +} + +CHIP_ERROR HostNameRegistrar::StartMonitorInterfaces(OnInterfaceChanges interfaceChangesBlock) +{ + mInterfaceMonitor = nw_path_monitor_create(); + VerifyOrReturnError(mInterfaceMonitor != nullptr, CHIP_ERROR_NO_MEMORY); - DNSServiceRef sdRef; - auto err = DNSServiceCreateConnection(&sdRef); - VerifyOrReturnError(kDNSServiceErr_NoError == err, CHIP_ERROR_INTERNAL); + nw_path_monitor_set_queue(mInterfaceMonitor, chip::DeviceLayer::PlatformMgrImpl().GetWorkQueue()); - RegisterRecordContext * sdCtx = Platform::New(registerCtx); - VerifyOrReturnError(nullptr != sdCtx, CHIP_ERROR_NO_MEMORY); + nw_path_monitor_set_update_handler(mInterfaceMonitor, ^(nw_path_t path) { +#if CHIP_DETAIL_LOGGING + LogDetails(path); +#endif // CHIP_DETAIL_LOGGING - ChipLogDetail(Discovery, "Mdns: Mapping %s to:", mHostName.c_str()); + __block InetInterfacesVector inet; + __block Inet6InterfacesVector inet6; - for (auto & registrant : mRegistry) - { - err = registrant.Register(sdRef, sdCtx, mHostName.c_str()); + // The loopback interfaces needs to be manually added. While lo0 is usually 1, this is not guaranteed. So search for a + // loopback interface with the specified interface id. If the specified interface id is kDNSServiceInterfaceIndexAny, it + // will look for all available loopback interfaces. + GetInterfaceAddresses(mInterfaceId, mAddressType, inet, inet6, true /* searchLoopbackOnly */); +#if CHIP_DETAIL_LOGGING + LogDetails(inet, inet6); +#endif // CHIP_DETAIL_LOGGING - // An error to register a particular registrant is not fatal unless all registrants have failed. - // Otherwise, if there is an errror, it indicates that this registrant will not trigger a callback - // with its registration status. So we take the registration failure into account here. - if (kDNSServiceErr_NoError != err) + auto status = nw_path_get_status(path); + if (status == nw_path_status_satisfied) { - VerifyOrReturnError(IncrementRegistrationCount(err), sdCtx->Finalize(err)); + nw_path_enumerate_interfaces(path, ^(nw_interface_t interface) { + VerifyOrReturnValue(HasValidNetworkType(interface), true); + VerifyOrReturnValue(IsValidInterfaceId(mInterfaceId, interface), true); + + auto targetInterfaceId = nw_interface_get_index(interface); + GetInterfaceAddresses(targetInterfaceId, mAddressType, inet, inet6); +#if CHIP_DETAIL_LOGGING + LogDetails(interface, inet, inet6); +#endif // CHIP_DETAIL_LOGGING + return true; + }); } - } - return MdnsContexts::GetInstance().Add(sdCtx, sdRef); + interfaceChangesBlock(inet, inet6); + }); + + nw_path_monitor_start(mInterfaceMonitor); + + return CHIP_NO_ERROR; } -bool HostNameRegistrar::IncrementRegistrationCount(DNSServiceErrorType err) +void HostNameRegistrar::StopMonitorInterfaces() { - mRegistrationCount++; - VerifyOrDie(mRegistrationCount <= mRegistry.size()); + if (mInterfaceMonitor != nullptr) + { + nw_path_monitor_cancel(mInterfaceMonitor); + nw_release(mInterfaceMonitor); + mInterfaceMonitor = nullptr; + } +} - // A single registration success is enough to consider the whole process a success. - // This is very permissive in the sense that the interface that has succeeded may not be - // enough to do anything useful, but on the other hand, the failure of a single interface - // to successfuly registered does not makes it obvious that it won't work. - if (kDNSServiceErr_NoError == err) +CHIP_ERROR HostNameRegistrar::StartSharedConnection() +{ + auto err = DNSServiceCreateConnection(&mServiceRef); + VerifyOrReturnValue(kDNSServiceErr_NoError == err, Error::ToChipError(err)); + + err = DNSServiceSetDispatchQueue(mServiceRef, chip::DeviceLayer::PlatformMgrImpl().GetWorkQueue()); + if (kDNSServiceErr_NoError != err) { - mRegistrationSuccess = true; + StopSharedConnection(); } - return mRegistrationCount != mRegistry.size(); + return Error::ToChipError(err); +} + +void HostNameRegistrar::StopSharedConnection() +{ + if (mServiceRef != nullptr) + { + // All the DNSRecordRefs registered to the shared DNSServiceRef will be deallocated. + DNSServiceRefDeallocate(mServiceRef); + mServiceRef = nullptr; + } +} + +CHIP_ERROR HostNameRegistrar::ResetSharedConnection() +{ + StopSharedConnection(); + ReturnLogErrorOnFailure(StartSharedConnection()); + return CHIP_NO_ERROR; } } // namespace Dnssd diff --git a/src/platform/Darwin/DnssdHostNameRegistrar.h b/src/platform/Darwin/DnssdHostNameRegistrar.h index 2b23c3cdb81593..ae6b7efa0f937b 100644 --- a/src/platform/Darwin/DnssdHostNameRegistrar.h +++ b/src/platform/Darwin/DnssdHostNameRegistrar.h @@ -23,80 +23,53 @@ #include #include +#include + namespace chip { namespace Dnssd { -struct RegisterContext; -struct RegisterRecordContext; - -class InterfaceRegistrant -{ -public: - /** - * Initialize an interface if it match filtering arguments. - * - * @param[in] ifa The interface to initialize from. - * @param[in] addressType An allowed address type. - * Passing in Inet::IPAddressType::kAny effectively allow all address types. - * @param[in] interfaceId An allowed interface id. - * Passing in kDNSServiceInterfaceIndexAny effectively allow all interface ids. - * - * @return A boolean indicating if the initialization from the data of the ifaddrs was allowed by the filtering parameters. - */ - bool Init(const struct ifaddrs * ifa, Inet::IPAddressType addressType, uint32_t interfaceId); - - DNSServiceErrorType Register(DNSServiceRef sdRef, RegisterRecordContext * sdCtx, const char * hostname) const; - -private: - static bool HasValidFlags(unsigned int flags); - static bool HasValidType(Inet::IPAddressType addressType, const sa_family_t addressFamily); - static bool IsValidInterfaceId(uint32_t targetInterfaceId, unsigned int currentInterfaceId); - - const struct in_addr * GetIPv4() const { return &mInterfaceAddress.ipv4; } - const struct in6_addr * GetIPv6() const { return &mInterfaceAddress.ipv6; } - - bool IsIPv4() const { return mInterfaceAddressType == AF_INET; }; - bool IsIPv6() const { return mInterfaceAddressType == AF_INET6; }; - - void LogDetail() const; - - union InterfaceAddress - { - struct in_addr ipv4; - struct in6_addr ipv6; - }; + typedef std::pair InetInterface; + typedef std::pair Inet6Interface; + typedef std::vector InetInterfacesVector; + typedef std::vector> Inet6InterfacesVector; + typedef void (^OnInterfaceChanges)(InetInterfacesVector inetInterfaces, Inet6InterfacesVector inet6Interfaces); + + class HostNameRegistrar { + public: + void Init(const char * hostname, Inet::IPAddressType addressType, uint32_t interfaceId); + + CHIP_ERROR Register(); + void Unregister(); + + private: + bool IsLocalOnly() const { return mInterfaceId == kDNSServiceInterfaceIndexLocalOnly; }; + + template void RegisterInterfaces(std::vector> interfaces, uint16_t type) + { + for (auto & interface : interfaces) { + auto interfaceId = interface.first; + auto interfaceAddress = static_cast(&interface.second); + auto interfaceAddressLen = sizeof(interface.second); - uint32_t mInterfaceId; - InterfaceAddress mInterfaceAddress; - sa_family_t mInterfaceAddressType; -}; - -class HostNameRegistrar -{ -public: - bool Init(const char * hostname, Inet::IPAddressType addressType, uint32_t interfaceId); - - CHIP_ERROR Register(RegisterContext * registerCtx); - - /** - * IncrementRegistrationCount is used to indicate a registrant status. - * When all registrants status has been recovered, it returns false to indicate - * that the registration process is finished. - * - * @param[in] err The registration status - * - * @return A boolean indicating if the registration process needs to continue. - */ - bool IncrementRegistrationCount(DNSServiceErrorType err); - - bool HasRegisteredRegistrant() { return mRegistrationSuccess; } - -private: - std::string mHostName; - std::vector mRegistry; - uint8_t mRegistrationCount = 0; - bool mRegistrationSuccess = false; -}; + LogErrorOnFailure(RegisterInterface(interfaceId, type, interfaceAddress, interfaceAddressLen)); + } + } + + CHIP_ERROR RegisterInterface(uint32_t interfaceId, uint16_t rtype, const void * rdata, uint16_t rdlen); + + CHIP_ERROR StartSharedConnection(); + void StopSharedConnection(); + CHIP_ERROR ResetSharedConnection(); + DNSServiceRef mServiceRef; + + CHIP_ERROR StartMonitorInterfaces(OnInterfaceChanges interfaceChangesBlock); + void StopMonitorInterfaces(); + nw_path_monitor_t mInterfaceMonitor; + + std::string mHostname; + uint32_t mInterfaceId; + Inet::IPAddressType mAddressType; + }; } // namespace Dnssd } // namespace chip diff --git a/src/platform/Darwin/DnssdImpl.cpp b/src/platform/Darwin/DnssdImpl.cpp index ea370fcdf7c96d..c8c94ca174baa7 100644 --- a/src/platform/Darwin/DnssdImpl.cpp +++ b/src/platform/Darwin/DnssdImpl.cpp @@ -173,11 +173,7 @@ static void OnRegister(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErr ChipLogDetail(Discovery, "Mdns: %s name: %s, type: %s, domain: %s, flags: %d", __func__, name, type, domain, flags); auto sdCtx = reinterpret_cast(context); - VerifyOrReturn(kDNSServiceErr_NoError == err, sdCtx->Finalize(err)); - - // Once a service has been properly published it is normally unreachable because the hostname has not been yet - // registered against the dns daemon. Register the records mapping the hostname to our IP. - sdCtx->mHostNameRegistrar.Register(sdCtx); + sdCtx->Finalize(err); }; CHIP_ERROR Register(void * context, DnssdPublishCallback callback, uint32_t interfaceId, const char * type, const char * name, @@ -197,8 +193,7 @@ CHIP_ERROR Register(void * context, DnssdPublishCallback callback, uint32_t inte sdCtx = chip::Platform::New(type, name, callback, context); VerifyOrReturnError(nullptr != sdCtx, CHIP_ERROR_NO_MEMORY); - VerifyOrReturnError(sdCtx->mHostNameRegistrar.Init(hostname, addressType, interfaceId), - sdCtx->Finalize(kDNSServiceErr_BadInterfaceIndex)); + sdCtx->mHostNameRegistrar.Init(hostname, addressType, interfaceId); DNSServiceRef sdRef; auto err = DNSServiceRegister(&sdRef, kRegisterFlags, interfaceId, name, type, kLocalDot, hostname, ntohs(port), record.size(), @@ -394,15 +389,6 @@ CHIP_ERROR ChipDnssdRemoveServices() { err = CHIP_NO_ERROR; } - ReturnErrorOnFailure(err); - - err = MdnsContexts::GetInstance().RemoveAllOfType(ContextType::RegisterRecord); - if (CHIP_ERROR_KEY_NOT_FOUND == err) - { - err = CHIP_NO_ERROR; - } - ReturnErrorOnFailure(err); - return err; } diff --git a/src/platform/Darwin/DnssdImpl.h b/src/platform/Darwin/DnssdImpl.h index d6bb8246703d9a..b60a8c97c6bc90 100644 --- a/src/platform/Darwin/DnssdImpl.h +++ b/src/platform/Darwin/DnssdImpl.h @@ -32,7 +32,6 @@ namespace Dnssd { enum class ContextType { Register, - RegisterRecord, Browse, Resolve, }; @@ -99,7 +98,7 @@ struct RegisterContext : public GenericContext HostNameRegistrar mHostNameRegistrar; RegisterContext(const char * sType, const char * instanceName, DnssdPublishCallback cb, void * cbContext); - virtual ~RegisterContext() {} + virtual ~RegisterContext() { mHostNameRegistrar.Unregister(); } void DispatchFailure(DNSServiceErrorType err) override; void DispatchSuccess() override; @@ -107,17 +106,6 @@ struct RegisterContext : public GenericContext bool matches(const char * sType) { return mType.compare(sType) == 0; } }; -struct RegisterRecordContext : public GenericContext -{ - RegisterContext * mRegisterContext; - - RegisterRecordContext(RegisterContext * context); - virtual ~RegisterRecordContext(){}; - - void DispatchFailure(DNSServiceErrorType err) override; - void DispatchSuccess() override; -}; - struct BrowseContext : public GenericContext { DnssdBrowseCallback callback;