| /* |
| * |
| * Copyright (c) 2021 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 <cstdio> |
| #include <sstream> |
| #include <string.h> |
| |
| #include <lib/support/CHIPMem.h> |
| #include <lib/support/CHIPMemString.h> |
| #include <lib/support/CodeUtils.h> |
| #include <lib/support/SafeInt.h> |
| #include <lib/support/logging/CHIPLogging.h> |
| #include <platform/CHIPDeviceLayer.h> |
| |
| using namespace chip::Dnssd; |
| |
| namespace { |
| |
| constexpr const char * kLocalDot = "local."; |
| constexpr const char * kProtocolTcp = "._tcp"; |
| constexpr const char * kProtocolUdp = "._udp"; |
| constexpr uint8_t kDnssdKeyMaxSize = 32; |
| |
| bool IsSupportedProtocol(DnssdServiceProtocol protocol) |
| { |
| return (protocol == DnssdServiceProtocol::kDnssdProtocolUdp) || (protocol == DnssdServiceProtocol::kDnssdProtocolTcp); |
| } |
| |
| uint32_t GetInterfaceId(chip::Inet::InterfaceId interfaceId) |
| { |
| return interfaceId.IsPresent() ? interfaceId.GetPlatformInterface() : kDNSServiceInterfaceIndexAny; |
| } |
| |
| std::string GetFullType(const char * type, DnssdServiceProtocol protocol) |
| { |
| std::ostringstream typeBuilder; |
| typeBuilder << type; |
| typeBuilder << (protocol == DnssdServiceProtocol::kDnssdProtocolUdp ? kProtocolUdp : kProtocolTcp); |
| return typeBuilder.str(); |
| } |
| |
| std::string GetFullTypeWithSubTypes(const char * type, DnssdServiceProtocol protocol, const char * subTypes[], size_t subTypeSize) |
| { |
| std::ostringstream typeBuilder; |
| typeBuilder << type; |
| typeBuilder << (protocol == DnssdServiceProtocol::kDnssdProtocolUdp ? kProtocolUdp : kProtocolTcp); |
| for (int i = 0; i < (int) subTypeSize; i++) |
| { |
| typeBuilder << ","; |
| typeBuilder << subTypes[i]; |
| } |
| return typeBuilder.str(); |
| } |
| |
| } // namespace |
| |
| namespace chip { |
| namespace Dnssd { |
| |
| MdnsContexts MdnsContexts::sInstance; |
| |
| void MdnsContexts::Delete(GenericContext * context) |
| { |
| if (context->type == ContextType::GetAddrInfo) |
| { |
| GetAddrInfoContext * addrInfoContext = reinterpret_cast<GetAddrInfoContext *>(context); |
| std::vector<TextEntry>::iterator textEntry; |
| for (textEntry = addrInfoContext->textEntries.begin(); textEntry != addrInfoContext->textEntries.end(); textEntry++) |
| { |
| free(const_cast<char *>(textEntry->mKey)); |
| free(const_cast<uint8_t *>(textEntry->mData)); |
| } |
| } |
| |
| if (context->serviceRef != nullptr) |
| { |
| DNSServiceRefDeallocate(context->serviceRef); |
| } |
| chip::Platform::Delete(context); |
| } |
| |
| MdnsContexts::~MdnsContexts() |
| { |
| std::vector<GenericContext *>::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); |
| VerifyOrReturnError(sdRef != nullptr, CHIP_ERROR_INVALID_ARGUMENT); |
| |
| context->serviceRef = sdRef; |
| mContexts.push_back(context); |
| |
| return CHIP_NO_ERROR; |
| } |
| |
| CHIP_ERROR MdnsContexts::Remove(GenericContext * context) |
| { |
| bool found = false; |
| |
| std::vector<GenericContext *>::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::Removes(ContextType type) |
| { |
| bool found = false; |
| |
| std::vector<GenericContext *>::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; |
| } |
| |
| CHIP_ERROR MdnsContexts::Get(ContextType type, GenericContext ** context) |
| { |
| bool found = false; |
| std::vector<GenericContext *>::iterator iter; |
| |
| for (iter = mContexts.begin(); iter != mContexts.end(); iter++) |
| { |
| if ((*iter)->type == type) |
| { |
| *context = *iter; |
| found = true; |
| break; |
| } |
| } |
| |
| return found ? CHIP_NO_ERROR : CHIP_ERROR_KEY_NOT_FOUND; |
| } |
| |
| CHIP_ERROR MdnsContexts::GetRegisterType(const char * type, GenericContext ** context) |
| { |
| bool found = false; |
| std::vector<GenericContext *>::iterator iter; |
| |
| for (iter = mContexts.begin(); iter != mContexts.end(); iter++) |
| { |
| if ((*iter)->type == ContextType::Register && ((RegisterContext *) (*iter))->matches(type)) |
| { |
| *context = *iter; |
| found = true; |
| break; |
| } |
| } |
| |
| 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<uint8_t>(entry.mDataSize), CHIP_ERROR_INVALID_ARGUMENT); |
| |
| err = TXTRecordSetValue(record, entry.mKey, static_cast<uint8_t>(entry.mDataSize), entry.mData); |
| VerifyOrReturnError(err == kDNSServiceErr_NoError, CHIP_ERROR_INVALID_ARGUMENT); |
| } |
| |
| return CHIP_NO_ERROR; |
| } |
| |
| 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; |
| } |
| |
| if (kDNSServiceErr_NoError != err) |
| { |
| ChipLogError(DeviceLayer, "%s (%s)", name, Error::ToString(err)); |
| |
| if (useCallback) |
| { |
| switch (context->type) |
| { |
| case ContextType::Register: |
| // Nothing special to do. Maybe ChipDnssdPublishService should take a callback ? |
| break; |
| case ContextType::Browse: { |
| BrowseContext * browseContext = reinterpret_cast<BrowseContext *>(context); |
| browseContext->callback(browseContext->context, nullptr, 0, CHIP_ERROR_INTERNAL); |
| break; |
| } |
| case ContextType::Resolve: { |
| ResolveContext * resolveContext = reinterpret_cast<ResolveContext *>(context); |
| resolveContext->callback(resolveContext->context, nullptr, CHIP_ERROR_INTERNAL); |
| break; |
| } |
| case ContextType::GetAddrInfo: { |
| GetAddrInfoContext * resolveContext = reinterpret_cast<GetAddrInfoContext *>(context); |
| resolveContext->callback(resolveContext->context, nullptr, CHIP_ERROR_INTERNAL); |
| break; |
| } |
| } |
| } |
| |
| if (CHIP_ERROR_KEY_NOT_FOUND == MdnsContexts::GetInstance().Remove(context)) |
| { |
| chip::Platform::Delete(context); |
| } |
| |
| return false; |
| } |
| |
| return true; |
| } |
| |
| static void OnRegister(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType err, const char * name, const char * type, |
| const char * domain, void * context) |
| { |
| RegisterContext * sdCtx = reinterpret_cast<RegisterContext *>(context); |
| VerifyOrReturn(CheckForSuccess(sdCtx, __func__, err)); |
| |
| ChipLogDetail(DeviceLayer, "Mdns: %s name: %s, type: %s, domain: %s, flags: %d", __func__, name, type, domain, flags); |
| }; |
| |
| CHIP_ERROR Register(uint32_t interfaceId, const char * type, const char * name, uint16_t port, TXTRecordRef * recordRef) |
| { |
| DNSServiceErrorType err; |
| DNSServiceRef sdRef; |
| GenericContext * sdCtx = nullptr; |
| |
| uint16_t recordLen = TXTRecordGetLength(recordRef); |
| const void * recordBytesPtr = TXTRecordGetBytesPtr(recordRef); |
| |
| if (CHIP_NO_ERROR == MdnsContexts::GetInstance().GetRegisterType(type, &sdCtx)) |
| { |
| err = DNSServiceUpdateRecord(sdCtx->serviceRef, NULL, 0 /* flags */, recordLen, recordBytesPtr, 0 /* ttl */); |
| TXTRecordDeallocate(recordRef); |
| VerifyOrReturnError(CheckForSuccess(sdCtx, __func__, err), CHIP_ERROR_INTERNAL); |
| return CHIP_NO_ERROR; |
| } |
| |
| sdCtx = chip::Platform::New<RegisterContext>(type, nullptr); |
| err = DNSServiceRegister(&sdRef, 0 /* flags */, interfaceId, name, type, kLocalDot, NULL, ntohs(port), recordLen, |
| recordBytesPtr, OnRegister, sdCtx); |
| TXTRecordDeallocate(recordRef); |
| |
| VerifyOrReturnError(CheckForSuccess(sdCtx, __func__, err), 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); |
| } |
| |
| void OnBrowseAdd(BrowseContext * context, const char * name, const char * type, const char * domain, |
| chip::Inet::InterfaceId interfaceId) |
| { |
| ChipLogDetail(DeviceLayer, "Mdns: %s name: %s, type: %s, domain: %s, interface: %d", __func__, name, type, domain, |
| interfaceId.GetPlatformInterface()); |
| |
| VerifyOrReturn(strcmp(kLocalDot, domain) == 0); |
| |
| DnssdService service = {}; |
| service.mInterface = interfaceId; |
| service.mProtocol = context->protocol; |
| |
| Platform::CopyString(service.mName, name); |
| Platform::CopyString(service.mType, type); |
| |
| // only the first token after '.' should be included in the type |
| for (char * p = service.mType; *p != '\0'; p++) |
| { |
| if (*p == '.') |
| { |
| *p = '\0'; |
| break; |
| } |
| } |
| |
| context->services.push_back(service); |
| } |
| |
| void OnBrowseRemove(BrowseContext * context, const char * name, const char * type, const char * domain, |
| chip::Inet::InterfaceId interfaceId) |
| { |
| ChipLogDetail(DeviceLayer, "Mdns: %s name: %s, type: %s, domain: %s, interface: %d", __func__, name, type, domain, |
| interfaceId.GetPlatformInterface()); |
| |
| VerifyOrReturn(strcmp(kLocalDot, domain) == 0); |
| |
| 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; |
| }); |
| } |
| |
| 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<BrowseContext *>(context); |
| VerifyOrReturn(CheckForSuccess(sdCtx, __func__, err, true)); |
| |
| (flags & kDNSServiceFlagsAdd) ? OnBrowseAdd(sdCtx, name, type, domain, Inet::InterfaceId(interfaceId)) |
| : OnBrowseRemove(sdCtx, name, type, domain, Inet::InterfaceId(interfaceId)); |
| |
| if (!(flags & kDNSServiceFlagsMoreComing)) |
| { |
| sdCtx->callback(sdCtx->context, sdCtx->services.data(), sdCtx->services.size(), CHIP_NO_ERROR); |
| MdnsContexts::GetInstance().Remove(sdCtx); |
| } |
| } |
| |
| 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); |
| } |
| |
| sdCtx = chip::Platform::New<BrowseContext>(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); |
| |
| return MdnsContexts::GetInstance().Add(sdCtx, sdRef); |
| } |
| |
| 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<GetAddrInfoContext *>(context); |
| VerifyOrReturn(CheckForSuccess(sdCtx, __func__, err, true)); |
| |
| ChipLogDetail(DeviceLayer, "Mdns: %s hostname:%s", __func__, hostname); |
| |
| DnssdService service = {}; |
| service.mPort = sdCtx->port; |
| service.mTextEntries = sdCtx->textEntries.empty() ? nullptr : sdCtx->textEntries.data(); |
| service.mTextEntrySize = sdCtx->textEntries.empty() ? 0 : sdCtx->textEntries.size(); |
| chip::Inet::IPAddress ip; |
| CHIP_ERROR status = chip::Inet::IPAddress::GetIPAddressFromSockAddr(*address, ip); |
| service.mAddress.SetValue(ip); |
| Platform::CopyString(service.mName, sdCtx->name); |
| Platform::CopyString(service.mHostName, hostname); |
| service.mInterface = Inet::InterfaceId(sdCtx->interfaceId); |
| |
| sdCtx->callback(sdCtx->context, &service, 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) |
| { |
| DNSServiceErrorType err; |
| DNSServiceRef sdRef; |
| GetAddrInfoContext * sdCtx; |
| |
| sdCtx = chip::Platform::New<GetAddrInfoContext>(context, callback, name, interfaceId, port); |
| |
| 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++) |
| { |
| 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<const uint8_t *>(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; |
| } |
| #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); |
| } |
| else |
| { |
| 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<struct sockaddr *>(&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<ResolveContext *>(context); |
| VerifyOrReturn(CheckForSuccess(sdCtx, __func__, err, true)); |
| |
| GetAddrInfo(sdCtx->context, sdCtx->callback, interfaceId, sdCtx->addressType, sdCtx->name, hostname, ntohs(port), txtLen, |
| txtRecord); |
| MdnsContexts::GetInstance().Remove(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; |
| |
| sdCtx = chip::Platform::New<ResolveContext>(context, callback, name, addressType); |
| err = DNSServiceResolve(&sdRef, 0 /* flags */, interfaceId, name, type, kLocalDot, OnResolve, 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); |
| |
| return MdnsContexts::GetInstance().Add(sdCtx, sdRef); |
| } |
| |
| CHIP_ERROR ChipDnssdInit(DnssdAsyncReturnCallback successCallback, DnssdAsyncReturnCallback errorCallback, void * context) |
| { |
| VerifyOrReturnError(successCallback != nullptr, CHIP_ERROR_INVALID_ARGUMENT); |
| VerifyOrReturnError(errorCallback != nullptr, CHIP_ERROR_INVALID_ARGUMENT); |
| |
| successCallback(context, CHIP_NO_ERROR); |
| return CHIP_NO_ERROR; |
| } |
| |
| CHIP_ERROR ChipDnssdShutdown() |
| { |
| return CHIP_NO_ERROR; |
| } |
| |
| CHIP_ERROR ChipDnssdPublishService(const DnssdService * service) |
| { |
| VerifyOrReturnError(service != nullptr, CHIP_ERROR_INVALID_ARGUMENT); |
| VerifyOrReturnError(IsSupportedProtocol(service->mProtocol), 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)); |
| |
| 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(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)) |
| { |
| return CHIP_NO_ERROR; |
| } |
| |
| return MdnsContexts::GetInstance().Removes(ContextType::Register); |
| } |
| |
| CHIP_ERROR ChipDnssdFinalizeServiceUpdate() |
| { |
| return CHIP_NO_ERROR; |
| } |
| |
| CHIP_ERROR ChipDnssdBrowse(const char * type, DnssdServiceProtocol protocol, chip::Inet::IPAddressType addressType, |
| chip::Inet::InterfaceId interface, DnssdBrowseCallback callback, void * context) |
| { |
| VerifyOrReturnError(type != nullptr, CHIP_ERROR_INVALID_ARGUMENT); |
| 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); |
| |
| return Browse(context, callback, interfaceId, regtype.c_str(), protocol); |
| } |
| |
| CHIP_ERROR ChipDnssdResolve(DnssdService * service, chip::Inet::InterfaceId interface, DnssdResolveCallback callback, |
| void * context) |
| { |
| 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); |
| |
| return Resolve(context, callback, interfaceId, service->mAddressType, regtype.c_str(), service->mName); |
| } |
| |
| } // namespace Dnssd |
| } // namespace chip |