diff --git a/src/platform/Darwin/BUILD.gn b/src/platform/Darwin/BUILD.gn index 5aa6668ce00460..f47ebbba4e64a1 100644 --- a/src/platform/Darwin/BUILD.gn +++ b/src/platform/Darwin/BUILD.gn @@ -51,6 +51,7 @@ static_library("Darwin") { "DeviceInfoProviderImpl.h", "DiagnosticDataProviderImpl.cpp", "DiagnosticDataProviderImpl.h", + "DnssdContexts.cpp", "DnssdImpl.cpp", "DnssdImpl.h", "InetPlatformConfig.h", diff --git a/src/platform/Darwin/DnssdContexts.cpp b/src/platform/Darwin/DnssdContexts.cpp new file mode 100644 index 00000000000000..bd68b126e004e7 --- /dev/null +++ b/src/platform/Darwin/DnssdContexts.cpp @@ -0,0 +1,425 @@ +/* + * + * Copyright (c) 2021-2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "DnssdImpl.h" +#include "MdnsError.h" + +#include +#include + +using namespace chip::Dnssd; + +namespace { + +constexpr uint8_t kDnssdKeyMaxSize = 32; +constexpr uint8_t kDnssdTxtRecordMaxEntries = 20; + +std::string GetHostNameWithoutDomain(const char * hostnameWithDomain) +{ + std::string hostname(hostnameWithDomain); + size_t position = hostname.find("."); + if (position != std::string::npos) + { + hostname.erase(position); + } + + return hostname; +} + +void GetTextEntries(DnssdService & service, const unsigned char * data, uint16_t len) +{ + uint16_t recordCount = TXTRecordGetCount(len, data); + service.mTextEntrySize = recordCount; + service.mTextEntries = static_cast(chip::Platform::MemoryCalloc(kDnssdTxtRecordMaxEntries, sizeof(TextEntry))); + + for (uint16_t i = 0; i < recordCount; i++) + { + char key[kDnssdKeyMaxSize]; + uint8_t valueLen; + const void * valuePtr; + + auto err = TXTRecordGetItemAtIndex(len, data, i, kDnssdKeyMaxSize, key, &valueLen, &valuePtr); + if (kDNSServiceErr_NoError != err) + { + // If there is an error with a txt record stop the parsing here. + service.mTextEntrySize = i; + break; + } + + if (valueLen >= chip::Dnssd::kDnssdTextMaxSize) + { + // Truncation, but nothing better we can do + valueLen = chip::Dnssd::kDnssdTextMaxSize - 1; + } + + char value[chip::Dnssd::kDnssdTextMaxSize]; + memcpy(value, valuePtr, valueLen); + value[valueLen] = 0; + + auto & textEntry = service.mTextEntries[i]; + textEntry.mKey = strdup(key); + textEntry.mData = reinterpret_cast(strdup(value)); + textEntry.mDataSize = valueLen; + } +} + +DNSServiceProtocol GetProtocol(const chip::Inet::IPAddressType & addressType) +{ +#if INET_CONFIG_ENABLE_IPV4 + if (addressType == chip::Inet::IPAddressType::kIPv4) + { + return kDNSServiceProtocol_IPv4; + } + + if (addressType == chip::Inet::IPAddressType::kIPv6) + { + return kDNSServiceProtocol_IPv6; + } + + return kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6; +#else + // without IPv4, IPv6 is the only option + return kDNSServiceProtocol_IPv6; +#endif +} + +} // namespace + +namespace chip { +namespace Dnssd { + +CHIP_ERROR GenericContext::Finalize(DNSServiceErrorType err) +{ + if (MdnsContexts::GetInstance().Has(this) == CHIP_NO_ERROR) + { + if (kDNSServiceErr_NoError == err) + { + DispatchSuccess(); + } + else + { + DispatchFailure(err); + } + } + else + { + chip::Platform::Delete(this); + } + + return (kDNSServiceErr_NoError == err) ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; +} + +MdnsContexts::~MdnsContexts() +{ + std::vector::const_iterator iter = mContexts.cbegin(); + while (iter != mContexts.cend()) + { + Delete(*iter); + mContexts.erase(iter); + } +} + +CHIP_ERROR MdnsContexts::Add(GenericContext * context, DNSServiceRef sdRef) +{ + VerifyOrReturnError(context != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + + if (sdRef == nullptr) + { + chip::Platform::Delete(context); + return CHIP_ERROR_INVALID_ARGUMENT; + } + + auto err = DNSServiceSetDispatchQueue(sdRef, chip::DeviceLayer::PlatformMgrImpl().GetWorkQueue()); + if (kDNSServiceErr_NoError != err) + { + chip::Platform::Delete(context); + return CHIP_ERROR_INTERNAL; + } + + context->serviceRef = sdRef; + mContexts.push_back(context); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR MdnsContexts::Remove(GenericContext * context) +{ + bool found = false; + + std::vector::const_iterator iter = mContexts.cbegin(); + while (iter != mContexts.cend()) + { + if (*iter != context) + { + iter++; + continue; + } + + Delete(*iter); + mContexts.erase(iter); + found = true; + break; + } + + return found ? CHIP_NO_ERROR : CHIP_ERROR_KEY_NOT_FOUND; +} + +CHIP_ERROR MdnsContexts::RemoveAllOfType(ContextType type) +{ + bool found = false; + + std::vector::const_iterator iter = mContexts.cbegin(); + while (iter != mContexts.cend()) + { + if ((*iter)->type != type) + { + iter++; + continue; + } + + Delete(*iter); + mContexts.erase(iter); + found = true; + } + + return found ? CHIP_NO_ERROR : CHIP_ERROR_KEY_NOT_FOUND; +} + +void MdnsContexts::Delete(GenericContext * context) +{ + if (context->serviceRef != nullptr) + { + DNSServiceRefDeallocate(context->serviceRef); + } + chip::Platform::Delete(context); +} + +CHIP_ERROR MdnsContexts::Has(GenericContext * context) +{ + std::vector::iterator iter; + + for (iter = mContexts.begin(); iter != mContexts.end(); iter++) + { + if ((*iter) == context) + { + return CHIP_NO_ERROR; + } + } + + return CHIP_ERROR_KEY_NOT_FOUND; +} + +CHIP_ERROR MdnsContexts::GetRegisterContextOfType(const char * type, RegisterContext ** context) +{ + bool found = false; + std::vector::iterator iter; + + for (iter = mContexts.begin(); iter != mContexts.end(); iter++) + { + if ((*iter)->type == ContextType::Register && (static_cast(*iter))->matches(type)) + { + *context = static_cast(*iter); + found = true; + break; + } + } + + return found ? CHIP_NO_ERROR : CHIP_ERROR_KEY_NOT_FOUND; +} + +RegisterContext::RegisterContext(const char * sType, DnssdPublishCallback cb, void * cbContext) +{ + type = ContextType::Register; + context = cbContext; + callback = cb; + + Platform::CopyString(mType, sType); +} + +void RegisterContext::DispatchFailure(DNSServiceErrorType err) +{ + ChipLogError(DeviceLayer, "Register (%s)", Error::ToString(err)); + callback(context, nullptr, CHIP_ERROR_INTERNAL); + MdnsContexts::GetInstance().Remove(this); +} + +void RegisterContext::DispatchSuccess() +{ + callback(context, mType, CHIP_NO_ERROR); +} + +BrowseContext::BrowseContext(void * cbContext, DnssdBrowseCallback cb, DnssdServiceProtocol cbContextProtocol) +{ + type = ContextType::Browse; + context = cbContext; + callback = cb; + protocol = cbContextProtocol; +} + +void BrowseContext::DispatchFailure(DNSServiceErrorType err) +{ + ChipLogError(DeviceLayer, "Browse (%s)", Error::ToString(err)); + callback(context, nullptr, 0, CHIP_ERROR_INTERNAL); + MdnsContexts::GetInstance().Remove(this); +} + +void BrowseContext::DispatchSuccess() +{ + callback(context, services.data(), services.size(), CHIP_NO_ERROR); + MdnsContexts::GetInstance().Remove(this); +} + +ResolveContext::ResolveContext(void * cbContext, DnssdResolveCallback cb, chip::Inet::IPAddressType cbAddressType) +{ + type = ContextType::Resolve; + context = cbContext; + callback = cb; + protocol = GetProtocol(cbAddressType); +} + +ResolveContext::~ResolveContext() +{ + RemoveInterfaces(); +} + +void ResolveContext::DispatchFailure(DNSServiceErrorType err) +{ + ChipLogError(DeviceLayer, "Resolve (%s)", Error::ToString(err)); + callback(context, nullptr, Span(), CHIP_ERROR_INTERNAL); + MdnsContexts::GetInstance().Remove(this); +} + +void ResolveContext::DispatchSuccess() +{ + for (auto & interface : interfaces) + { + auto & ips = interface.second.addresses; + + // Some interface may not have any ips, just ignore them. + if (ips.size() == 0) + { + continue; + } + + // Use the first IP we got for the DnssdService. + interface.second.service.mAddress.SetValue(ips.front()); + ips.erase(ips.begin()); + callback(context, &interface.second.service, Span(ips.data(), ips.size()), CHIP_NO_ERROR); + break; + } + + MdnsContexts::GetInstance().Remove(this); +} + +CHIP_ERROR ResolveContext::OnNewAddress(uint32_t interfaceId, const struct sockaddr * address) +{ + chip::Inet::IPAddress ip; + ReturnErrorOnFailure(chip::Inet::IPAddress::GetIPAddressFromSockAddr(*address, ip)); + interfaces[interfaceId].addresses.push_back(ip); + +#ifdef CHIP_DETAIL_LOGGING + char addrStr[INET6_ADDRSTRLEN]; + ip.ToString(addrStr, sizeof(addrStr)); + ChipLogDetail(DeviceLayer, "Mdns: %s interface: %" PRIu32 " ip:%s", __func__, interfaceId, addrStr); +#endif // CHIP_DETAIL_LOGGING + + return CHIP_NO_ERROR; +} + +CHIP_ERROR ResolveContext::OnNewLocalOnlyAddress() +{ + sockaddr_in6 sockaddr; + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sin6_len = sizeof(sockaddr); + sockaddr.sin6_family = AF_INET6; + sockaddr.sin6_addr = in6addr_loopback; + sockaddr.sin6_port = htons((unsigned short) interfaces[kDNSServiceInterfaceIndexLocalOnly].service.mPort); + + return OnNewAddress(kDNSServiceInterfaceIndexLocalOnly, reinterpret_cast(&sockaddr)); +} + +bool ResolveContext::HasAddress() +{ + for (auto & interface : interfaces) + { + if (interface.second.addresses.size()) + { + return true; + } + } + + return false; +} + +void ResolveContext::OnNewInterface(uint32_t interfaceId, const char * fullname, const char * hostnameWithDomain, uint16_t port, + uint16_t txtLen, const unsigned char * txtRecord) +{ + ChipLogDetail(DeviceLayer, "Mdns : %s hostname:%s fullname:%s interface: %" PRIu32, __func__, hostnameWithDomain, fullname, + interfaceId); + + InterfaceInfo interface; + interface.service.mPort = ntohs(port); + + if (kDNSServiceInterfaceIndexLocalOnly == interfaceId) + { + // Set interface to ANY (0) - network stack can decide how to route this. + interface.service.mInterface = Inet::InterfaceId(0); + } + else + { + interface.service.mInterface = Inet::InterfaceId(interfaceId); + } + + // The hostname parameter contains the hostname followed by the domain. But the mHostName field is sized + // to contain either a 12 bytes mac address or an extended address of at most 16 bytes, not the domain name. + auto hostname = GetHostNameWithoutDomain(hostnameWithDomain); + Platform::CopyString(interface.service.mHostName, hostname.c_str()); + Platform::CopyString(interface.service.mName, fullname); + + GetTextEntries(interface.service, txtRecord, txtLen); + + // If for some reason the hostname can not fit into the hostname field (e.g it is not a mac address) then + // DNSServiceGetAddrInfo will never return anything. So instead, copy the name as the FQDN and use it for + // resolving. + interface.fullyQualifiedDomainName = hostnameWithDomain; + + interfaces.insert(std::pair(interfaceId, interface)); +} + +bool ResolveContext::HasInterface() +{ + return interfaces.size(); +} + +void ResolveContext::RemoveInterfaces() +{ + for (auto & interface : interfaces) + { + size_t count = interface.second.service.mTextEntrySize; + for (size_t i = 0; i < count; i++) + { + const auto & textEntry = interface.second.service.mTextEntries[i]; + free(const_cast(textEntry.mKey)); + free(const_cast(textEntry.mData)); + } + Platform::MemoryFree(const_cast(interface.second.service.mTextEntries)); + } + + interfaces.clear(); +} + +} // namespace Dnssd +} // namespace chip diff --git a/src/platform/Darwin/DnssdImpl.cpp b/src/platform/Darwin/DnssdImpl.cpp index 2669fbe2693162..1358d1d124e994 100644 --- a/src/platform/Darwin/DnssdImpl.cpp +++ b/src/platform/Darwin/DnssdImpl.cpp @@ -15,7 +15,6 @@ * limitations under the License. */ #include "DnssdImpl.h" - #include "MdnsError.h" #include @@ -36,7 +35,11 @@ namespace { constexpr const char * kLocalDot = "local."; constexpr const char * kProtocolTcp = "._tcp"; constexpr const char * kProtocolUdp = "._udp"; -constexpr uint8_t kDnssdKeyMaxSize = 32; + +constexpr DNSServiceFlags kRegisterFlags = kDNSServiceFlagsNoAutoRename; +constexpr DNSServiceFlags kBrowseFlags = 0; +constexpr DNSServiceFlags kGetAddrInfoFlags = kDNSServiceFlagsTimeout | kDNSServiceFlagsShareConnection; +constexpr DNSServiceFlags kResolveFlags = kDNSServiceFlagsShareConnection; bool IsSupportedProtocol(DnssdServiceProtocol protocol) { @@ -56,6 +59,11 @@ std::string GetFullType(const char * type, DnssdServiceProtocol protocol) return typeBuilder.str(); } +std::string GetFullType(const DnssdService * service) +{ + return GetFullType(service->mType, service->mProtocol); +} + std::string GetFullTypeWithSubTypes(const char * type, DnssdServiceProtocol protocol, const char * subTypes[], size_t subTypeSize) { std::ostringstream typeBuilder; @@ -69,259 +77,134 @@ std::string GetFullTypeWithSubTypes(const char * type, DnssdServiceProtocol prot return typeBuilder.str(); } -} // namespace - -namespace chip { -namespace Dnssd { - -MdnsContexts MdnsContexts::sInstance; - -void MdnsContexts::Delete(GenericContext * context) +std::string GetFullTypeWithSubTypes(const char * type, DnssdServiceProtocol protocol) { - if (context->type == ContextType::GetAddrInfo) - { - GetAddrInfoContext * addrInfoContext = reinterpret_cast(context); - std::vector::iterator textEntry; - for (textEntry = addrInfoContext->textEntries.begin(); textEntry != addrInfoContext->textEntries.end(); textEntry++) - { - free(const_cast(textEntry->mKey)); - free(const_cast(textEntry->mData)); - } - } + auto fullType = GetFullType(type, protocol); - if (context->serviceRef != nullptr) + std::string subtypeDelimiter = "._sub."; + size_t position = fullType.find(subtypeDelimiter); + if (position != std::string::npos) { - DNSServiceRefDeallocate(context->serviceRef); + fullType = fullType.substr(position + subtypeDelimiter.size()) + "," + fullType.substr(0, position); } - chip::Platform::Delete(context); -} -MdnsContexts::~MdnsContexts() -{ - std::vector::const_iterator iter = mContexts.cbegin(); - while (iter != mContexts.cend()) - { - Delete(*iter); - mContexts.erase(iter); - } + return fullType; } -CHIP_ERROR MdnsContexts::Add(GenericContext * context, DNSServiceRef sdRef) +std::string GetFullTypeWithSubTypes(const DnssdService * service) { - VerifyOrReturnError(context != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(sdRef != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - - context->serviceRef = sdRef; - mContexts.push_back(context); - - return CHIP_NO_ERROR; + return GetFullTypeWithSubTypes(service->mType, service->mProtocol, service->mSubTypes, service->mSubTypeSize); } -CHIP_ERROR MdnsContexts::Remove(GenericContext * context) +void LogOnFailure(const char * name, DNSServiceErrorType err) { - bool found = false; - - std::vector::const_iterator iter = mContexts.cbegin(); - while (iter != mContexts.cend()) + if (kDNSServiceErr_NoError != err) { - if (*iter != context) - { - iter++; - continue; - } - - Delete(*iter); - mContexts.erase(iter); - found = true; - break; + ChipLogError(DeviceLayer, "%s (%s)", name, Error::ToString(err)); } - - return found ? CHIP_NO_ERROR : CHIP_ERROR_KEY_NOT_FOUND; } -CHIP_ERROR MdnsContexts::Removes(ContextType type) +class ScopedTXTRecord { - bool found = false; +public: + ScopedTXTRecord() {} - std::vector::const_iterator iter = mContexts.cbegin(); - while (iter != mContexts.cend()) + ~ScopedTXTRecord() { - if ((*iter)->type != type) + if (mDataSize != 0) { - iter++; - continue; + TXTRecordDeallocate(&mRecordRef); } - - Delete(*iter); - mContexts.erase(iter); - found = true; } - return found ? CHIP_NO_ERROR : CHIP_ERROR_KEY_NOT_FOUND; -} + CHIP_ERROR Init(TextEntry * textEntries, size_t textEntrySize) + { + VerifyOrReturnError(textEntrySize <= kDnssdTextMaxSize, CHIP_ERROR_INVALID_ARGUMENT); -CHIP_ERROR MdnsContexts::Get(ContextType type, GenericContext ** context) -{ - bool found = false; - std::vector::iterator iter; + TXTRecordCreate(&mRecordRef, sizeof(mRecordBuffer), mRecordBuffer); - for (iter = mContexts.begin(); iter != mContexts.end(); iter++) - { - if ((*iter)->type == type) + for (size_t i = 0; i < textEntrySize; i++) { - *context = *iter; - found = true; - break; - } - } - - return found ? CHIP_NO_ERROR : CHIP_ERROR_KEY_NOT_FOUND; -} + TextEntry entry = textEntries[i]; + VerifyOrReturnError(chip::CanCastTo(entry.mDataSize), CHIP_ERROR_INVALID_ARGUMENT); -CHIP_ERROR MdnsContexts::GetRegisterType(const char * type, GenericContext ** context) -{ - bool found = false; - std::vector::iterator iter; + auto err = TXTRecordSetValue(&mRecordRef, entry.mKey, static_cast(entry.mDataSize), entry.mData); + VerifyOrReturnError(err == kDNSServiceErr_NoError, CHIP_ERROR_INVALID_ARGUMENT); + } - for (iter = mContexts.begin(); iter != mContexts.end(); iter++) - { - if ((*iter)->type == ContextType::Register && ((RegisterContext *) (*iter))->matches(type)) + mDataSize = TXTRecordGetLength(&mRecordRef); + if (mDataSize == 0) { - *context = *iter; - found = true; - break; + TXTRecordDeallocate(&mRecordRef); } - } - - return found ? CHIP_NO_ERROR : CHIP_ERROR_KEY_NOT_FOUND; -} - -void MdnsContexts::PrepareSelect(fd_set & readFdSet, fd_set & writeFdSet, fd_set & errorFdSet, int & maxFd, timeval & timeout) {} - -void MdnsContexts::HandleSelectResult(fd_set & readFdSet, fd_set & writeFdSet, fd_set & errorFdSet) {} -CHIP_ERROR PopulateTextRecord(TXTRecordRef * record, char * buffer, uint16_t bufferLen, TextEntry * textEntries, - size_t textEntrySize) -{ - VerifyOrReturnError(textEntrySize <= kDnssdTextMaxSize, CHIP_ERROR_INVALID_ARGUMENT); - - DNSServiceErrorType err; - TXTRecordCreate(record, bufferLen, buffer); - - for (size_t i = 0; i < textEntrySize; i++) - { - TextEntry entry = textEntries[i]; - VerifyOrReturnError(chip::CanCastTo(entry.mDataSize), CHIP_ERROR_INVALID_ARGUMENT); - - err = TXTRecordSetValue(record, entry.mKey, static_cast(entry.mDataSize), entry.mData); - VerifyOrReturnError(err == kDNSServiceErr_NoError, CHIP_ERROR_INVALID_ARGUMENT); + mData = TXTRecordGetBytesPtr(&mRecordRef); + return CHIP_NO_ERROR; } - return CHIP_NO_ERROR; -} + uint16_t size() { return mDataSize; } + const void * data() { return mData; } -bool CheckForSuccess(GenericContext * context, const char * name, DNSServiceErrorType err, bool useCallback = false) -{ - if (context == nullptr) - { - ChipLogError(DeviceLayer, "%s (%s)", name, "Mdns context is null."); - return false; - } +private: + uint16_t mDataSize = 0; + const void * mData = nullptr; - if (kDNSServiceErr_NoError != err) - { - ChipLogError(DeviceLayer, "%s (%s)", name, Error::ToString(err)); + TXTRecordRef mRecordRef; + char mRecordBuffer[kDnssdTextMaxSize]; +}; - if (useCallback) - { - switch (context->type) - { - case ContextType::Register: { - RegisterContext * registerContext = reinterpret_cast(context); - registerContext->callback(registerContext->context, nullptr, CHIP_ERROR_INTERNAL); - break; - } - case ContextType::Browse: { - BrowseContext * browseContext = reinterpret_cast(context); - browseContext->callback(browseContext->context, nullptr, 0, CHIP_ERROR_INTERNAL); - break; - } - case ContextType::Resolve: { - ResolveContext * resolveContext = reinterpret_cast(context); - resolveContext->callback(resolveContext->context, nullptr, Span(), CHIP_ERROR_INTERNAL); - break; - } - case ContextType::GetAddrInfo: { - GetAddrInfoContext * resolveContext = reinterpret_cast(context); - resolveContext->callback(resolveContext->context, nullptr, Span(), CHIP_ERROR_INTERNAL); - break; - } - } - } +} // namespace - if (CHIP_ERROR_KEY_NOT_FOUND == MdnsContexts::GetInstance().Remove(context)) - { - chip::Platform::Delete(context); - } +namespace chip { +namespace Dnssd { - return false; - } +MdnsContexts MdnsContexts::sInstance; - return true; -} +namespace { static void OnRegister(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType err, const char * name, const char * type, const char * domain, void * context) { - RegisterContext * sdCtx = reinterpret_cast(context); - VerifyOrReturn(CheckForSuccess(sdCtx, __func__, err)); - ChipLogDetail(DeviceLayer, "Mdns: %s name: %s, type: %s, domain: %s, flags: %d", __func__, name, type, domain, flags); - sdCtx->callback(sdCtx->context, type, CHIP_NO_ERROR); + auto sdCtx = reinterpret_cast(context); + sdCtx->Finalize(err); }; CHIP_ERROR Register(void * context, DnssdPublishCallback callback, uint32_t interfaceId, const char * type, const char * name, - uint16_t port, TXTRecordRef * recordRef) + uint16_t port, ScopedTXTRecord & record) { - DNSServiceErrorType err; - DNSServiceRef sdRef; - GenericContext * sdCtx = nullptr; + ChipLogProgress(DeviceLayer, "Publishing service %s on port %u with type: %s on interface id: %" PRIu32, name, port, type, + interfaceId); - uint16_t recordLen = TXTRecordGetLength(recordRef); - const void * recordBytesPtr = TXTRecordGetBytesPtr(recordRef); - - if (CHIP_NO_ERROR == MdnsContexts::GetInstance().GetRegisterType(type, &sdCtx)) + RegisterContext * sdCtx = nullptr; + if (CHIP_NO_ERROR == MdnsContexts::GetInstance().GetRegisterContextOfType(type, &sdCtx)) { - err = DNSServiceUpdateRecord(sdCtx->serviceRef, nullptr, 0 /* flags */, recordLen, recordBytesPtr, 0 /* ttl */); - TXTRecordDeallocate(recordRef); - VerifyOrReturnError(CheckForSuccess(sdCtx, __func__, err), CHIP_ERROR_INTERNAL); + auto err = DNSServiceUpdateRecord(sdCtx->serviceRef, nullptr, kRegisterFlags, record.size(), record.data(), 0 /* ttl */); + VerifyOrReturnError(kDNSServiceErr_NoError == err, sdCtx->Finalize(err)); return CHIP_NO_ERROR; } sdCtx = chip::Platform::New(type, callback, context); - err = DNSServiceRegister(&sdRef, 0 /* flags */, interfaceId, name, type, kLocalDot, nullptr, ntohs(port), recordLen, - recordBytesPtr, OnRegister, sdCtx); - TXTRecordDeallocate(recordRef); - - VerifyOrReturnError(CheckForSuccess(sdCtx, __func__, err), CHIP_ERROR_INTERNAL); + VerifyOrReturnError(nullptr != sdCtx, CHIP_ERROR_NO_MEMORY); - err = DNSServiceSetDispatchQueue(sdRef, chip::DeviceLayer::PlatformMgrImpl().GetWorkQueue()); - VerifyOrReturnError(CheckForSuccess(sdCtx, __func__, err, true), CHIP_ERROR_INTERNAL); + DNSServiceRef sdRef; + auto err = DNSServiceRegister(&sdRef, kRegisterFlags, interfaceId, name, type, kLocalDot, nullptr, ntohs(port), record.size(), + record.data(), OnRegister, sdCtx); + VerifyOrReturnError(kDNSServiceErr_NoError == err, sdCtx->Finalize(err)); return MdnsContexts::GetInstance().Add(sdCtx, sdRef); } -void OnBrowseAdd(BrowseContext * context, const char * name, const char * type, const char * domain, - chip::Inet::InterfaceId interfaceId) +void OnBrowseAdd(BrowseContext * context, const char * name, const char * type, const char * domain, uint32_t interfaceId) { - ChipLogDetail(DeviceLayer, "Mdns: %s name: %s, type: %s, domain: %s, interface: %d", __func__, name, type, domain, - interfaceId.GetPlatformInterface()); + ChipLogDetail(DeviceLayer, "Mdns: %s name: %s, type: %s, domain: %s, interface: %" PRIu32, __func__, name, type, domain, + interfaceId); VerifyOrReturn(strcmp(kLocalDot, domain) == 0); DnssdService service = {}; - service.mInterface = interfaceId; + service.mInterface = Inet::InterfaceId(interfaceId); service.mProtocol = context->protocol; Platform::CopyString(service.mName, name); @@ -340,19 +223,17 @@ void OnBrowseAdd(BrowseContext * context, const char * name, const char * type, context->services.push_back(service); } -void OnBrowseRemove(BrowseContext * context, const char * name, const char * type, const char * domain, - chip::Inet::InterfaceId interfaceId) +void OnBrowseRemove(BrowseContext * context, const char * name, const char * type, const char * domain, uint32_t interfaceId) { - ChipLogDetail(DeviceLayer, "Mdns: %s name: %s, type: %s, domain: %s, interface: %d", __func__, name, type, domain, - interfaceId.GetPlatformInterface()); + ChipLogDetail(DeviceLayer, "Mdns: %s name: %s, type: %s, domain: %s, interface: %" PRIu32, __func__, name, type, domain, + interfaceId); VerifyOrReturn(strcmp(kLocalDot, domain) == 0); context->services.erase(std::remove_if(context->services.begin(), context->services.end(), [name, type, interfaceId](const DnssdService & service) { - return strcmp(name, service.mName) == 0 && - type == GetFullType(service.mType, service.mProtocol) && - service.mInterface == interfaceId; + return strcmp(name, service.mName) == 0 && type == GetFullType(&service) && + service.mInterface == Inet::InterfaceId(interfaceId); }), context->services.end()); } @@ -360,40 +241,28 @@ void OnBrowseRemove(BrowseContext * context, const char * name, const char * typ static void OnBrowse(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceId, DNSServiceErrorType err, const char * name, const char * type, const char * domain, void * context) { - BrowseContext * sdCtx = reinterpret_cast(context); - VerifyOrReturn(CheckForSuccess(sdCtx, __func__, err, true)); + auto sdCtx = reinterpret_cast(context); + VerifyOrReturn(kDNSServiceErr_NoError == err, sdCtx->Finalize(err)); - (flags & kDNSServiceFlagsAdd) ? OnBrowseAdd(sdCtx, name, type, domain, Inet::InterfaceId(interfaceId)) - : OnBrowseRemove(sdCtx, name, type, domain, Inet::InterfaceId(interfaceId)); + (flags & kDNSServiceFlagsAdd) ? OnBrowseAdd(sdCtx, name, type, domain, interfaceId) + : OnBrowseRemove(sdCtx, name, type, domain, interfaceId); if (!(flags & kDNSServiceFlagsMoreComing)) { - sdCtx->callback(sdCtx->context, sdCtx->services.data(), sdCtx->services.size(), CHIP_NO_ERROR); - MdnsContexts::GetInstance().Remove(sdCtx); + sdCtx->Finalize(); } } CHIP_ERROR Browse(void * context, DnssdBrowseCallback callback, uint32_t interfaceId, const char * type, DnssdServiceProtocol protocol) { - DNSServiceErrorType err; - DNSServiceRef sdRef; - BrowseContext * sdCtx; - - std::string regtype(type); - std::string subtypeDelimiter = "._sub."; - size_t position = regtype.find(subtypeDelimiter); - if (position != std::string::npos) - { - regtype = regtype.substr(position + subtypeDelimiter.size()) + "," + regtype.substr(0, position); - } + auto sdCtx = chip::Platform::New(context, callback, protocol); + VerifyOrReturnError(nullptr != sdCtx, CHIP_ERROR_NO_MEMORY); - sdCtx = chip::Platform::New(context, callback, protocol); - err = DNSServiceBrowse(&sdRef, 0 /* flags */, interfaceId, regtype.c_str(), kLocalDot, OnBrowse, sdCtx); - VerifyOrReturnError(CheckForSuccess(sdCtx, __func__, err), CHIP_ERROR_INTERNAL); - - err = DNSServiceSetDispatchQueue(sdRef, chip::DeviceLayer::PlatformMgrImpl().GetWorkQueue()); - VerifyOrReturnError(CheckForSuccess(sdCtx, __func__, err, true), CHIP_ERROR_INTERNAL); + ChipLogProgress(DeviceLayer, "Browsing for: %s", type); + DNSServiceRef sdRef; + auto err = DNSServiceBrowse(&sdRef, kBrowseFlags, interfaceId, type, kLocalDot, OnBrowse, sdCtx); + VerifyOrReturnError(kDNSServiceErr_NoError == err, sdCtx->Finalize(err)); return MdnsContexts::GetInstance().Add(sdCtx, sdRef); } @@ -401,160 +270,82 @@ CHIP_ERROR Browse(void * context, DnssdBrowseCallback callback, uint32_t interfa static void OnGetAddrInfo(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceId, DNSServiceErrorType err, const char * hostname, const struct sockaddr * address, uint32_t ttl, void * context) { - GetAddrInfoContext * sdCtx = reinterpret_cast(context); - VerifyOrReturn(CheckForSuccess(sdCtx, __func__, err, true)); - - ChipLogDetail(DeviceLayer, "Mdns: %s hostname:%s", __func__, hostname); - - chip::Inet::IPAddress ip; - CHIP_ERROR status = chip::Inet::IPAddress::GetIPAddressFromSockAddr(*address, ip); - if (status == CHIP_NO_ERROR) - { - sdCtx->addresses.push_back(ip); - } + auto sdCtx = reinterpret_cast(context); + ReturnOnFailure(MdnsContexts::GetInstance().Has(sdCtx)); + LogOnFailure(__func__, err); - if (flags & kDNSServiceFlagsMoreComing) + if (kDNSServiceErr_NoError == err) { - // Wait for that. - return; + sdCtx->OnNewAddress(interfaceId, address); } - DnssdService service = {}; - service.mPort = sdCtx->port; - service.mTextEntries = sdCtx->textEntries.empty() ? nullptr : sdCtx->textEntries.data(); - service.mTextEntrySize = sdCtx->textEntries.empty() ? 0 : sdCtx->textEntries.size(); - // Use the first IP we got for the DnssdService. - if (sdCtx->addresses.size() != 0) + if (!(flags & kDNSServiceFlagsMoreComing)) { - service.mAddress.SetValue(sdCtx->addresses.front()); - sdCtx->addresses.erase(sdCtx->addresses.begin()); + VerifyOrReturn(sdCtx->HasAddress(), sdCtx->Finalize(kDNSServiceErr_BadState)); + sdCtx->Finalize(); } - Platform::CopyString(service.mName, sdCtx->name); - Platform::CopyString(service.mHostName, hostname); - service.mInterface = Inet::InterfaceId(sdCtx->interfaceId); - - // TODO: Does it really make sense to pass in the status from our last "get the IP address" operation? - sdCtx->callback(sdCtx->context, &service, Span(sdCtx->addresses.data(), sdCtx->addresses.size()), status); - MdnsContexts::GetInstance().Remove(sdCtx); } -static CHIP_ERROR GetAddrInfo(void * context, DnssdResolveCallback callback, uint32_t interfaceId, - chip::Inet::IPAddressType addressType, const char * name, const char * hostname, uint16_t port, - uint16_t txtLen, const unsigned char * txtRecord) +static void GetAddrInfo(ResolveContext * sdCtx) { - DNSServiceErrorType err; - DNSServiceRef sdRef; - GetAddrInfoContext * sdCtx; - - sdCtx = chip::Platform::New(context, callback, name, interfaceId, port); + auto protocol = sdCtx->protocol; - char key[kDnssdKeyMaxSize]; - char value[kDnssdTextMaxSize]; - uint8_t valueLen; - const void * valuePtr; - - uint16_t recordCount = TXTRecordGetCount(txtLen, txtRecord); - for (uint16_t i = 0; i < recordCount; i++) + for (auto & interface : sdCtx->interfaces) { - err = TXTRecordGetItemAtIndex(txtLen, txtRecord, i, kDnssdKeyMaxSize, key, &valueLen, &valuePtr); - VerifyOrReturnError(CheckForSuccess(sdCtx, __func__, err, true), CHIP_ERROR_INTERNAL); - - if (valueLen >= sizeof(value)) - { - // Truncation, but nothing better we can do - valueLen = sizeof(value) - 1; - } - memcpy(value, valuePtr, valueLen); - value[valueLen] = 0; - - sdCtx->textEntries.push_back(TextEntry{ strdup(key), reinterpret_cast(strdup(value)), valueLen }); - } - - DNSServiceProtocol protocol; - -#if INET_CONFIG_ENABLE_IPV4 - if (addressType == chip::Inet::IPAddressType::kIPv4) - { - protocol = kDNSServiceProtocol_IPv4; - } - else if (addressType == chip::Inet::IPAddressType::kIPv6) - { - protocol = kDNSServiceProtocol_IPv6; - } - else - { - protocol = kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6; + auto interfaceId = interface.first; + auto hostname = interface.second.fullyQualifiedDomainName.c_str(); + auto sdRefCopy = sdCtx->serviceRef; // Mandatory copy because of kDNSServiceFlagsShareConnection + auto err = DNSServiceGetAddrInfo(&sdRefCopy, kGetAddrInfoFlags, interfaceId, protocol, hostname, OnGetAddrInfo, sdCtx); + VerifyOrReturn(kDNSServiceErr_NoError == err, sdCtx->Finalize(err)); } -#else - // without IPv4, IPv6 is the only option - protocol = kDNSServiceProtocol_IPv6; -#endif - - if (interfaceId != kDNSServiceInterfaceIndexLocalOnly) - { - // -1 is the local only interface. If we're not on that interface, we need to get the address for the given hostname. - err = DNSServiceGetAddrInfo(&sdRef, 0 /* flags */, interfaceId, protocol, hostname, OnGetAddrInfo, sdCtx); - VerifyOrReturnError(CheckForSuccess(sdCtx, __func__, err, true), CHIP_ERROR_INTERNAL); - - err = DNSServiceSetDispatchQueue(sdRef, chip::DeviceLayer::PlatformMgrImpl().GetWorkQueue()); - VerifyOrReturnError(CheckForSuccess(sdCtx, __func__, err, true), CHIP_ERROR_INTERNAL); - - return MdnsContexts::GetInstance().Add(sdCtx, sdRef); - } - - sockaddr_in6 sockaddr; - memset(&sockaddr, 0, sizeof(sockaddr)); - sockaddr.sin6_len = sizeof(sockaddr); - sockaddr.sin6_family = AF_INET6; - sockaddr.sin6_addr = in6addr_loopback; - sockaddr.sin6_port = htons((unsigned short) port); - uint32_t ttl = 120; // default TTL for records with hostnames is 120 seconds - uint32_t interface = 0; // Set interface to ANY (0) - network stack can decide how to route this. - OnGetAddrInfo(nullptr, 0 /* flags */, interface, kDNSServiceErr_NoError, hostname, - reinterpret_cast(&sockaddr), ttl, sdCtx); - - // Don't leak memory. - sdCtx->serviceRef = nullptr; - MdnsContexts::GetInstance().Delete(sdCtx); - return CHIP_NO_ERROR; } static void OnResolve(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceId, DNSServiceErrorType err, const char * fullname, const char * hostname, uint16_t port, uint16_t txtLen, const unsigned char * txtRecord, void * context) { - ChipLogDetail(DeviceLayer, "Resolved interface id: %u", interfaceId); - - ResolveContext * sdCtx = reinterpret_cast(context); - VerifyOrReturn(CheckForSuccess(sdCtx, __func__, err, true)); + auto sdCtx = reinterpret_cast(context); + ReturnOnFailure(MdnsContexts::GetInstance().Has(sdCtx)); + LogOnFailure(__func__, err); - GetAddrInfo(sdCtx->context, sdCtx->callback, interfaceId, sdCtx->addressType, sdCtx->name, hostname, ntohs(port), txtLen, - txtRecord); + if (kDNSServiceErr_NoError == err) + { + sdCtx->OnNewInterface(interfaceId, fullname, hostname, port, txtLen, txtRecord); + if (kDNSServiceInterfaceIndexLocalOnly == interfaceId) + { + sdCtx->OnNewLocalOnlyAddress(); + sdCtx->Finalize(); + return; + } + } - // TODO: If flags & kDNSServiceFlagsMoreComing should we keep waiting to see - // what else we resolve instead of calling Remove() here? - MdnsContexts::GetInstance().Remove(sdCtx); + if (!(flags & kDNSServiceFlagsMoreComing)) + { + VerifyOrReturn(sdCtx->HasInterface(), sdCtx->Finalize(kDNSServiceErr_BadState)); + GetAddrInfo(sdCtx); + } } static CHIP_ERROR Resolve(void * context, DnssdResolveCallback callback, uint32_t interfaceId, chip::Inet::IPAddressType addressType, const char * type, const char * name) { - DNSServiceErrorType err; - DNSServiceRef sdRef; - ResolveContext * sdCtx; + ChipLogDetail(DeviceLayer, "Resolve type=%s name=%s interface=%" PRIu32, type, name, interfaceId); - ChipLogProgress(Controller, "Resolve type=%s name=%s", type, name); + auto sdCtx = chip::Platform::New(context, callback, addressType); + VerifyOrReturnError(nullptr != sdCtx, CHIP_ERROR_NO_MEMORY); - sdCtx = chip::Platform::New(context, callback, name, addressType); - err = DNSServiceResolve(&sdRef, 0 /* flags */, interfaceId, name, type, kLocalDot, OnResolve, sdCtx); - VerifyOrReturnError(CheckForSuccess(sdCtx, __func__, err), CHIP_ERROR_INTERNAL); + auto err = DNSServiceCreateConnection(&sdCtx->serviceRef); + VerifyOrReturnError(kDNSServiceErr_NoError == err, sdCtx->Finalize(err)); - err = DNSServiceSetDispatchQueue(sdRef, chip::DeviceLayer::PlatformMgrImpl().GetWorkQueue()); - VerifyOrReturnError(CheckForSuccess(sdCtx, __func__, err, true), CHIP_ERROR_INTERNAL); + auto sdRefCopy = sdCtx->serviceRef; // Mandatory copy because of kDNSServiceFlagsShareConnection + err = DNSServiceResolve(&sdRefCopy, kResolveFlags, interfaceId, name, type, kLocalDot, OnResolve, sdCtx); + VerifyOrReturnError(kDNSServiceErr_NoError == err, sdCtx->Finalize(err)); - return MdnsContexts::GetInstance().Add(sdCtx, sdRef); + return MdnsContexts::GetInstance().Add(sdCtx, sdCtx->serviceRef); } +} // namespace + CHIP_ERROR ChipDnssdInit(DnssdAsyncReturnCallback successCallback, DnssdAsyncReturnCallback errorCallback, void * context) { VerifyOrReturnError(successCallback != nullptr, CHIP_ERROR_INVALID_ARGUMENT); @@ -575,31 +366,23 @@ CHIP_ERROR ChipDnssdPublishService(const DnssdService * service, DnssdPublishCal VerifyOrReturnError(IsSupportedProtocol(service->mProtocol), CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(callback != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - if (strcmp(service->mHostName, "") != 0) - { - MdnsContexts::GetInstance().SetHostname(service->mHostName); - } - std::string regtype = GetFullTypeWithSubTypes(service->mType, service->mProtocol, service->mSubTypes, service->mSubTypeSize); - uint32_t interfaceId = GetInterfaceId(service->mInterface); - - TXTRecordRef record; - char buffer[kDnssdTextMaxSize]; - ReturnErrorOnFailure(PopulateTextRecord(&record, buffer, sizeof(buffer), service->mTextEntries, service->mTextEntrySize)); + ScopedTXTRecord record; + ReturnErrorOnFailure(record.Init(service->mTextEntries, service->mTextEntrySize)); - ChipLogProgress(DeviceLayer, "Publishing service %s on port %u with type: %s on interface id: %" PRIu32, service->mName, - service->mPort, regtype.c_str(), interfaceId); - return Register(context, callback, interfaceId, regtype.c_str(), service->mName, service->mPort, &record); + auto regtype = GetFullTypeWithSubTypes(service); + auto interfaceId = GetInterfaceId(service->mInterface); + return Register(context, callback, interfaceId, regtype.c_str(), service->mName, service->mPort, record); } CHIP_ERROR ChipDnssdRemoveServices() { - GenericContext * sdCtx = nullptr; - if (CHIP_ERROR_KEY_NOT_FOUND == MdnsContexts::GetInstance().Get(ContextType::Register, &sdCtx)) + auto err = MdnsContexts::GetInstance().RemoveAllOfType(ContextType::Register); + if (CHIP_ERROR_KEY_NOT_FOUND == err) { return CHIP_NO_ERROR; } - return MdnsContexts::GetInstance().Removes(ContextType::Register); + return err; } CHIP_ERROR ChipDnssdFinalizeServiceUpdate() @@ -614,9 +397,8 @@ CHIP_ERROR ChipDnssdBrowse(const char * type, DnssdServiceProtocol protocol, chi VerifyOrReturnError(callback != nullptr, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(IsSupportedProtocol(protocol), CHIP_ERROR_INVALID_ARGUMENT); - std::string regtype = GetFullType(type, protocol); - uint32_t interfaceId = GetInterfaceId(interface); - + auto regtype = GetFullTypeWithSubTypes(type, protocol); + auto interfaceId = GetInterfaceId(interface); return Browse(context, callback, interfaceId, regtype.c_str(), protocol); } @@ -626,9 +408,8 @@ CHIP_ERROR ChipDnssdResolve(DnssdService * service, chip::Inet::InterfaceId inte VerifyOrReturnError(service != nullptr, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(IsSupportedProtocol(service->mProtocol), CHIP_ERROR_INVALID_ARGUMENT); - std::string regtype = GetFullType(service->mType, service->mProtocol); - uint32_t interfaceId = GetInterfaceId(interface); - + auto regtype = GetFullType(service); + auto interfaceId = GetInterfaceId(interface); return Resolve(context, callback, interfaceId, service->mAddressType, regtype.c_str(), service->mName); } diff --git a/src/platform/Darwin/DnssdImpl.h b/src/platform/Darwin/DnssdImpl.h index a23470c232c638..b3934cedae1fff 100644 --- a/src/platform/Darwin/DnssdImpl.h +++ b/src/platform/Darwin/DnssdImpl.h @@ -19,9 +19,8 @@ #include #include -#include -#include +#include #include #include @@ -33,7 +32,6 @@ enum class ContextType Register, Browse, Resolve, - GetAddrInfo, }; struct GenericContext @@ -41,6 +39,53 @@ struct GenericContext ContextType type; void * context; DNSServiceRef serviceRef; + + virtual ~GenericContext() {} + + CHIP_ERROR Finalize(DNSServiceErrorType err = kDNSServiceErr_NoError); + virtual void DispatchFailure(DNSServiceErrorType err) = 0; + virtual void DispatchSuccess() = 0; +}; + +struct RegisterContext; + +class MdnsContexts +{ +public: + MdnsContexts(const MdnsContexts &) = delete; + MdnsContexts & operator=(const MdnsContexts &) = delete; + ~MdnsContexts(); + static MdnsContexts & GetInstance() { return sInstance; } + + CHIP_ERROR Add(GenericContext * context, DNSServiceRef sdRef); + CHIP_ERROR Remove(GenericContext * context); + CHIP_ERROR RemoveAllOfType(ContextType type); + CHIP_ERROR Has(GenericContext * context); + + /** + * @brief + * Returns a pointer to a RegisterContext that has previously been registered + * with a given type. + * + * @param[in] type A service type. Service type are composed of + * of the service name, the service protocol, and the PTR records. + * Example: + * _matterc._udp,_V65521,_S15,_L3840,_CM + * _matter._tcp,_I4CEEAD044CC35B63 + * @param[out] context A reference to the context previously registered + * + * @return On success, the context parameter will point to the previously + * registered context. + */ + CHIP_ERROR GetRegisterContextOfType(const char * type, RegisterContext ** context); + + void Delete(GenericContext * context); + +private: + MdnsContexts(){}; + static MdnsContexts sInstance; + + std::vector mContexts; }; struct RegisterContext : public GenericContext @@ -48,14 +93,11 @@ struct RegisterContext : public GenericContext DnssdPublishCallback callback; char mType[kDnssdTypeMaxSize + 1]; - RegisterContext(const char * sType, DnssdPublishCallback cb, void * cbContext) - { - type = ContextType::Register; - context = cbContext; - callback = cb; + RegisterContext(const char * sType, DnssdPublishCallback cb, void * cbContext); + virtual ~RegisterContext() {} - Platform::CopyString(mType, sType); - } + void DispatchFailure(DNSServiceErrorType err) override; + void DispatchSuccess() override; bool matches(const char * sType) { return (strcmp(mType, sType) == 0); } }; @@ -66,83 +108,40 @@ struct BrowseContext : public GenericContext std::vector services; DnssdServiceProtocol protocol; - BrowseContext(void * cbContext, DnssdBrowseCallback cb, DnssdServiceProtocol cbContextProtocol) - { - type = ContextType::Browse; - context = cbContext; - callback = cb; - protocol = cbContextProtocol; - } -}; - -struct ResolveContext : public GenericContext -{ - DnssdResolveCallback callback; - - char name[Common::kInstanceNameMaxLength + 1]; - chip::Inet::IPAddressType addressType; - - ResolveContext(void * cbContext, DnssdResolveCallback cb, const char * cbContextName, chip::Inet::IPAddressType cbAddressType) - { - type = ContextType::Resolve; - context = cbContext; - callback = cb; - addressType = cbAddressType; + BrowseContext(void * cbContext, DnssdBrowseCallback cb, DnssdServiceProtocol cbContextProtocol); + virtual ~BrowseContext() {} - Platform::CopyString(name, cbContextName); - } + void DispatchFailure(DNSServiceErrorType err) override; + void DispatchSuccess() override; }; -struct GetAddrInfoContext : public GenericContext +struct InterfaceInfo { - DnssdResolveCallback callback; + DnssdService service; std::vector addresses; - std::vector textEntries; - char name[Common::kInstanceNameMaxLength + 1]; - uint32_t interfaceId; - uint16_t port; - - GetAddrInfoContext(void * cbContext, DnssdResolveCallback cb, const char * cbContextName, uint32_t cbInterfaceId, - uint16_t cbContextPort) - { - type = ContextType::GetAddrInfo; - context = cbContext; - callback = cb; - interfaceId = cbInterfaceId; - port = cbContextPort; - - Platform::CopyString(name, cbContextName); - } + std::string fullyQualifiedDomainName; }; -class MdnsContexts +struct ResolveContext : public GenericContext { -public: - MdnsContexts(const MdnsContexts &) = delete; - MdnsContexts & operator=(const MdnsContexts &) = delete; - ~MdnsContexts(); - static MdnsContexts & GetInstance() { return sInstance; } - - void PrepareSelect(fd_set & readFdSet, fd_set & writeFdSet, fd_set & errorFdSet, int & maxFd, timeval & timeout); - void HandleSelectResult(fd_set & readFdSet, fd_set & writeFdSet, fd_set & errorFdSet); - - CHIP_ERROR Add(GenericContext * context, DNSServiceRef sdRef); - CHIP_ERROR Remove(GenericContext * context); - CHIP_ERROR Removes(ContextType type); - CHIP_ERROR Get(ContextType type, GenericContext ** context); - CHIP_ERROR GetRegisterType(const char * type, GenericContext ** context); + DnssdResolveCallback callback; + std::map interfaces; + DNSServiceProtocol protocol; - void SetHostname(const char * name) { mHostname = name; } - const char * GetHostname() { return mHostname.c_str(); } + ResolveContext(void * cbContext, DnssdResolveCallback cb, chip::Inet::IPAddressType cbAddressType); + virtual ~ResolveContext(); - void Delete(GenericContext * context); + void DispatchFailure(DNSServiceErrorType err) override; + void DispatchSuccess() override; -private: - MdnsContexts(){}; - static MdnsContexts sInstance; - std::string mHostname; + CHIP_ERROR OnNewAddress(uint32_t interfaceId, const struct sockaddr * address); + CHIP_ERROR OnNewLocalOnlyAddress(); + bool HasAddress(); - std::vector mContexts; + void OnNewInterface(uint32_t interfaceId, const char * fullname, const char * hostname, uint16_t port, uint16_t txtLen, + const unsigned char * txtRecord); + bool HasInterface(); + void RemoveInterfaces(); }; } // namespace Dnssd