diff --git a/config/nrfconnect/app/sample-defaults.conf b/config/nrfconnect/app/sample-defaults.conf index f9c65c06d0bb5d..28f95614f7fe9e 100644 --- a/config/nrfconnect/app/sample-defaults.conf +++ b/config/nrfconnect/app/sample-defaults.conf @@ -66,7 +66,6 @@ CONFIG_OPENTHREAD_FTD=n CONFIG_OPENTHREAD_SLAAC=y CONFIG_OPENTHREAD_DHCP6_CLIENT=y CONFIG_OPENTHREAD_SNTP_CLIENT=y -CONFIG_OPENTHREAD_DNS_CLIENT=y CONFIG_OPENTHREAD_MTD_NETDIAG=y CONFIG_OPENTHREAD_ENABLE_SERVICE=y CONFIG_OPENTHREAD_MANUAL_START=y diff --git a/config/zephyr/Kconfig b/config/zephyr/Kconfig index 32f548f455bd84..30ce4da510ba20 100644 --- a/config/zephyr/Kconfig +++ b/config/zephyr/Kconfig @@ -86,6 +86,13 @@ config CHIP_ENABLE_DNSSD_SRP help Enables DNS-SD SRP client support +config CHIP_ENABLE_DNS_CLIENT + bool "Enable support for DNS client" + default y + imply OPENTHREAD_DNS_CLIENT + help + Enables DNS client support used for resolving and browsing services. + config APP_LINK_WITH_CHIP bool "Link 'app' with Connected Home over IP" default y diff --git a/docs/guides/nrfconnect_examples_cli.md b/docs/guides/nrfconnect_examples_cli.md index 3b4e75e79aa8d8..01cd09aed2ad9e 100644 --- a/docs/guides/nrfconnect_examples_cli.md +++ b/docs/guides/nrfconnect_examples_cli.md @@ -307,3 +307,42 @@ Prints the information about the NFC tag emulation status. uart:~$ matter nfc state NFC tag emulation is disabled ``` + +### dns + +Handles a group of commands that are used to trigger performing DNS queries. You +must use this command together with one of the additional subcommands listed +below. + +#### browse + +Browses for DNS services of `_matterc_udp` type and prints the received +response. Takes no argument. + +```shell +uart:~$ matter dns browse +Browsing ... +DNS browse succeeded: + Hostname: 0E824F0CA6DE309C + Vendor ID: 9050 + Product ID: 20043 + Long discriminator: 3840 + Device type: 0 + Device name: + Commissioning mode: 0 + IP addresses: + fd08:b65e:db8e:f9c7:2cc2:2043:1366:3b31 +``` + +#### resolve + +Resolves the specified Matter node service given by the and +. + +```shell +uart:~$ matter dns resolve +Resolving ... +DNS resolve for 000000014A77CBB3-0000000000BC5C01 succeeded: + IP address: fd08:b65e:db8e:f9c7:8052:1a8e:4dd4:e1f3 + Port: 11097 +``` diff --git a/src/include/platform/CHIPDeviceConfig.h b/src/include/platform/CHIPDeviceConfig.h index ad1fa207a66dd8..a475df7d1a7f4a 100644 --- a/src/include/platform/CHIPDeviceConfig.h +++ b/src/include/platform/CHIPDeviceConfig.h @@ -659,6 +659,24 @@ #define CHIP_DEVICE_CONFIG_THREAD_SRP_MAX_SERVICES 3 #endif +/** + * CHIP_DEVICE_CONFIG_ENABLE_THREAD_COMMISSIONABLE_DISCOVERY + * + * Enable support to Commissionable Discovery for Thread devices. + */ +#ifndef CHIP_DEVICE_CONFIG_ENABLE_THREAD_COMMISSIONABLE_DISCOVERY +#define CHIP_DEVICE_CONFIG_ENABLE_THREAD_COMMISSIONABLE_DISCOVERY 0 +#endif + +/** + * CHIP_DEVICE_CONFIG_ENABLE_THREAD_DNS_CLIENT + * + * Enable support to DNS client usage for resolving and browsing services in CHIP. + */ +#ifndef CHIP_DEVICE_CONFIG_ENABLE_THREAD_DNS_CLIENT +#define CHIP_DEVICE_CONFIG_ENABLE_THREAD_DNS_CLIENT 0 +#endif + // -------------------- Thread Configuration -------------------- /** diff --git a/src/include/platform/ThreadStackManager.h b/src/include/platform/ThreadStackManager.h index e78e89530674eb..d253518ca584de 100644 --- a/src/include/platform/ThreadStackManager.h +++ b/src/include/platform/ThreadStackManager.h @@ -29,7 +29,8 @@ namespace chip { namespace Mdns { struct TextEntry; -} +struct MdnsService; +} // namespace Mdns namespace DeviceLayer { @@ -56,6 +57,12 @@ template class GenericThreadStackManagerImpl_FreeRTOS; } // namespace Internal +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_DNS_CLIENT +// Declaration of callback types corresponding to MdnsResolveCallback and MdnsBrowseCallback to avoid circular including. +using DnsResolveCallback = void (*)(void * context, chip::Mdns::MdnsService * result, CHIP_ERROR error); +using DnsBrowseCallback = void (*)(void * context, chip::Mdns::MdnsService * services, size_t servicesSize, CHIP_ERROR error); +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_DNS_CLIENT + /** * Provides features for initializing and interacting with the Thread stack on * a chip-enabled device. @@ -86,11 +93,17 @@ class ThreadStackManager CHIP_ERROR SetThreadEnabled(bool val); #if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT - CHIP_ERROR AddSrpService(const char * aInstanceName, const char * aName, uint16_t aPort, chip::Mdns::TextEntry * aTxtEntries, - size_t aTxtEntiresSize, uint32_t aLeaseInterval, uint32_t aKeyLeaseInterval); + CHIP_ERROR + AddSrpService(const char * aInstanceName, const char * aName, uint16_t aPort, chip::Mdns::TextEntry * aTxtEntries, + size_t aTxtEntiresSize, uint32_t aLeaseInterval, uint32_t aKeyLeaseInterval); CHIP_ERROR RemoveSrpService(const char * aInstanceName, const char * aName); CHIP_ERROR RemoveAllSrpServices(); CHIP_ERROR SetupSrpHost(const char * aHostName); + +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_DNS_CLIENT + CHIP_ERROR DnsBrowse(const char * aServiceName, DnsBrowseCallback aCallback, void * aContext); + CHIP_ERROR DnsResolve(const char * aServiceName, const char * aInstanceName, DnsResolveCallback aCallback, void * aContext); +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_DNS_CLIENT #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT private: @@ -249,6 +262,20 @@ inline CHIP_ERROR ThreadStackManager::SetupSrpHost(const char * aHostName) { return static_cast(this)->_SetupSrpHost(aHostName); } + +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_DNS_CLIENT +inline CHIP_ERROR ThreadStackManager::DnsBrowse(const char * aServiceName, DnsBrowseCallback aCallback, void * aContext) +{ + return static_cast(this)->_DnsBrowse(aServiceName, aCallback, aContext); +} + +inline CHIP_ERROR ThreadStackManager::DnsResolve(const char * aServiceName, const char * aInstanceName, + DnsResolveCallback aCallback, void * aContext) +{ + return static_cast(this)->_DnsResolve(aServiceName, aInstanceName, aCallback, aContext); +} + +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_DNS_CLIENT #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT inline bool ThreadStackManager::IsThreadProvisioned() diff --git a/src/lib/mdns/Discovery_ImplPlatform.cpp b/src/lib/mdns/Discovery_ImplPlatform.cpp index 5ea0345fad056f..3a500eaac9a213 100644 --- a/src/lib/mdns/Discovery_ImplPlatform.cpp +++ b/src/lib/mdns/Discovery_ImplPlatform.cpp @@ -450,7 +450,15 @@ void DiscoveryImplPlatform::HandleNodeBrowse(void * context, MdnsService * servi { for (size_t i = 0; i < servicesSize; ++i) { - ChipMdnsResolve(&services[i], INET_NULL_INTERFACEID, HandleNodeResolve, context); + // For some platforms browsed services are already resolved, so verify if resolve is really needed or call resolve callback + if (!services[i].mAddress.HasValue()) + { + ChipMdnsResolve(&services[i], services[i].mInterface, HandleNodeResolve, context); + } + else + { + HandleNodeResolve(context, &services[i], error); + } } } diff --git a/src/lib/shell/Commands.h b/src/lib/shell/Commands.h index 84a325b4279f6c..24bfe62a5c5182 100644 --- a/src/lib/shell/Commands.h +++ b/src/lib/shell/Commands.h @@ -68,5 +68,11 @@ void RegisterWiFiCommands(); */ void RegisterNFCCommands(); +/** + * This function registers the DNS client commands. + * + */ +void RegisterDnsCommands(); + } // namespace Shell } // namespace chip diff --git a/src/lib/shell/Engine.cpp b/src/lib/shell/Engine.cpp index d57252a8c3b68b..583e08196a3434 100644 --- a/src/lib/shell/Engine.cpp +++ b/src/lib/shell/Engine.cpp @@ -111,6 +111,9 @@ void Engine::RegisterDefaultCommands() #if CHIP_DEVICE_CONFIG_ENABLE_NFC RegisterNFCCommands(); #endif +#if CHIP_DEVICE_CONFIG_ENABLE_MDNS + RegisterDnsCommands(); +#endif } } // namespace Shell diff --git a/src/lib/shell/commands/BUILD.gn b/src/lib/shell/commands/BUILD.gn index b4ec8c1efabc2d..83cf85cf15d560 100644 --- a/src/lib/shell/commands/BUILD.gn +++ b/src/lib/shell/commands/BUILD.gn @@ -45,6 +45,10 @@ source_set("commands") { sources += [ "NFC.cpp" ] } + if (chip_mdns != "none" && chip_device_platform != "none") { + sources += [ "Dns.cpp" ] + } + public_deps = [ "${chip_root}/src/lib/shell:shell_core" ] if (chip_device_platform != "none") { diff --git a/src/lib/shell/commands/Dns.cpp b/src/lib/shell/commands/Dns.cpp new file mode 100644 index 00000000000000..b6cc208d768080 --- /dev/null +++ b/src/lib/shell/commands/Dns.cpp @@ -0,0 +1,141 @@ +/* + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace chip { +namespace Shell { + +static chip::Shell::Engine sShellDnsSubcommands; +static bool isResolverStarted; + +class DnsShellResolverDelegate : public chip::Mdns::ResolverDelegate +{ +public: + void OnNodeIdResolved(const chip::Mdns::ResolvedNodeData & nodeData) override + { + streamer_printf(streamer_get(), "DNS resolve for " ChipLogFormatX64 "-" ChipLogFormatX64 " succeeded:\n", + ChipLogValueX64(nodeData.mPeerId.GetFabricId()), ChipLogValueX64(nodeData.mPeerId.GetNodeId())); + streamer_printf(streamer_get(), " IP address: %s\n", nodeData.mAddress.ToString(ipAddressBuf)); + streamer_printf(streamer_get(), " Port: %d\n", nodeData.mPort); + } + + void OnNodeIdResolutionFailed(const PeerId & peerId, CHIP_ERROR error) override {} + + void OnNodeDiscoveryComplete(const chip::Mdns::DiscoveredNodeData & nodeData) override + { + if (!nodeData.IsValid()) + { + streamer_printf(streamer_get(), "DNS browse failed - not found valid services \n"); + return; + } + streamer_printf(streamer_get(), "DNS browse succeeded: \n"); + streamer_printf(streamer_get(), " Hostname: %s\n", nodeData.hostName); + streamer_printf(streamer_get(), " Vendor ID: %d\n", nodeData.vendorId); + streamer_printf(streamer_get(), " Product ID: %d\n", nodeData.productId); + streamer_printf(streamer_get(), " Long discriminator: %d\n", nodeData.longDiscriminator); + streamer_printf(streamer_get(), " Device type: %d\n", nodeData.deviceType); + streamer_printf(streamer_get(), " Device name: %s\n", nodeData.deviceName); + streamer_printf(streamer_get(), " Commissioning mode: %d\n", nodeData.commissioningMode); + streamer_printf(streamer_get(), " IP addresses:\n"); + for (uint8_t i = 0; i < nodeData.kMaxIPAddresses; i++) + { + if (nodeData.ipAddress[i] != chip::Inet::IPAddress::Any) + streamer_printf(streamer_get(), " %s\n", nodeData.ipAddress[i].ToString(ipAddressBuf)); + } + } + +private: + char ipAddressBuf[chip::Inet::kMaxIPAddressStringLength]; +}; + +static DnsShellResolverDelegate sDnsShellResolverDelegate; + +CHIP_ERROR DnsHelpHandler(int argc, char ** argv) +{ + sShellDnsSubcommands.ForEachCommand(PrintCommandHelp, nullptr); + return CHIP_NO_ERROR; +} + +static CHIP_ERROR ResolveHandler(int argc, char ** argv) +{ + streamer_printf(streamer_get(), "Resolving ...\r\n"); + + VerifyOrReturnError(argc == 2, CHIP_ERROR_INVALID_ARGUMENT); + + PeerId peerId; + peerId.SetFabricId(strtoull(argv[0], NULL, 10)); + peerId.SetNodeId(strtoull(argv[1], NULL, 10)); + + return chip::Mdns::Resolver::Instance().ResolveNodeId(peerId, Inet::kIPAddressType_Any); +} + +static CHIP_ERROR BrowseHandler(int argc, char ** argv) +{ + streamer_printf(streamer_get(), "Browsing ...\r\n"); + + return chip::Mdns::Resolver::Instance().FindCommissionableNodes(); +} + +static CHIP_ERROR DnsHandler(int argc, char ** argv) +{ + if (!isResolverStarted) + { + chip::Mdns::Resolver::Instance().StartResolver(&chip::DeviceLayer::InetLayer, chip::Mdns::kMdnsPort); + chip::Mdns::Resolver::Instance().SetResolverDelegate(&sDnsShellResolverDelegate); + + isResolverStarted = true; + } + + if (argc == 0) + { + DnsHelpHandler(argc, argv); + return CHIP_NO_ERROR; + } + return sShellDnsSubcommands.ExecCommand(argc, argv); +} + +void RegisterDnsCommands() +{ + static const shell_command_t sDnsSubCommands[] = { + { &ResolveHandler, "resolve", + "Resolve the DNS service. Usage: dns resolve (e.g. dns resolve 5544332211 1)" }, + { &BrowseHandler, "browse", "Browse the services published by mdns. Usage: dns browse" }, + }; + + static const shell_command_t sDnsCommand = { &DnsHandler, "dns", "Dns client commands" }; + + // Register `dns` subcommands with the local shell dispatcher. + sShellDnsSubcommands.RegisterCommands(sDnsSubCommands, ArraySize(sDnsSubCommands)); + + // Register the root `dns` command with the top-level shell. + Engine::Root().RegisterCommands(&sDnsCommand, 1); +} + +} // namespace Shell +} // namespace chip diff --git a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.cpp b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.cpp index 20146bff517f5c..69346732331bca 100644 --- a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.cpp +++ b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.cpp @@ -1000,7 +1000,7 @@ void GenericThreadStackManagerImpl_OpenThread::OnSrpClientNotificatio otSrpClientService * next = nullptr; using Service = typename SrpClient::Service; - // Free memory for all removed services. + // Clear memory for all removed services. do { next = otService->mNext; @@ -1059,6 +1059,13 @@ void GenericThreadStackManagerImpl_OpenThread::OnSrpClientStateChange Encoding::BigEndian::HostSwap16(aServerSockAddr->mAddress.mFields.m16[5]), Encoding::BigEndian::HostSwap16(aServerSockAddr->mAddress.mFields.m16[6]), Encoding::BigEndian::HostSwap16(aServerSockAddr->mAddress.mFields.m16[7])); + +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_DNS_CLIENT + // Set DNS server config to be set at the SRP server address + otDnsQueryConfig dnsConfig = *otDnsClientGetDefaultConfig(ThreadStackMgrImpl().OTInstance()); + dnsConfig.mServerSockAddr.mAddress = aServerSockAddr->mAddress; + otDnsClientSetDefaultConfig(ThreadStackMgrImpl().OTInstance(), &dnsConfig); +#endif } else { @@ -1237,6 +1244,250 @@ CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_SetupSrpHost(co return error; } +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_DNS_CLIENT +template +CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::FromOtDnsResponseToMdnsData( + otDnsServiceInfo & serviceInfo, const char * serviceType, chip::Mdns::MdnsService & mdnsService, + DnsServiceTxtEntries & serviceTxtEntries) +{ + char protocol[chip::Mdns::kMdnsProtocolTextMaxSize + 1]; + + if (strchr(serviceInfo.mHostNameBuffer, '.') == nullptr) + return CHIP_ERROR_INVALID_ARGUMENT; + + // Extract from the .. the part. + size_t substringSize = strchr(serviceInfo.mHostNameBuffer, '.') - serviceInfo.mHostNameBuffer; + strncpy(mdnsService.mHostName, serviceInfo.mHostNameBuffer, substringSize); + // Append string terminating character. + mdnsService.mHostName[substringSize] = '\0'; + + if (strchr(serviceType, '.') == nullptr) + return CHIP_ERROR_INVALID_ARGUMENT; + + // Extract from the ... the part. + substringSize = strchr(serviceType, '.') - serviceType; + strncpy(mdnsService.mType, serviceType, substringSize); + // Append string terminating character. + mdnsService.mType[substringSize] = '\0'; + + // Extract from the ... the part. + const char * protocolSubstringStart = serviceType + substringSize + 1; + + if (strchr(protocolSubstringStart, '.') == nullptr) + return CHIP_ERROR_INVALID_ARGUMENT; + + substringSize = strchr(protocolSubstringStart, '.') - protocolSubstringStart; + strncpy(protocol, protocolSubstringStart, substringSize); + // Append string terminating character. + protocol[substringSize] = '\0'; + + if (strncmp(protocol, "_udp", chip::Mdns::kMdnsProtocolTextMaxSize) == 0) + { + mdnsService.mProtocol = chip::Mdns::MdnsServiceProtocol::kMdnsProtocolUdp; + } + else if (strncmp(protocol, "_tcp", chip::Mdns::kMdnsProtocolTextMaxSize) == 0) + { + mdnsService.mProtocol = chip::Mdns::MdnsServiceProtocol::kMdnsProtocolTcp; + } + else + { + mdnsService.mProtocol = chip::Mdns::MdnsServiceProtocol::kMdnsProtocolUnknown; + } + mdnsService.mPort = serviceInfo.mPort; + mdnsService.mInterface = INET_NULL_INTERFACEID; + mdnsService.mAddressType = Inet::kIPAddressType_IPv6; + mdnsService.mAddress = chip::Optional(ToIPAddress(serviceInfo.mHostAddress)); + + otDnsTxtEntryIterator iterator; + otDnsInitTxtEntryIterator(&iterator, serviceInfo.mTxtData, serviceInfo.mTxtDataSize); + + otDnsTxtEntry txtEntry; + + uint8_t entryIndex = 0; + while ((otDnsGetNextTxtEntry(&iterator, &txtEntry) == OT_ERROR_NONE) && entryIndex < kMaxDnsServiceTxtEntriesNumber) + { + if (txtEntry.mKey && strlen(txtEntry.mKey) < kMaxDnsServiceTxtKeySize && txtEntry.mValue && + txtEntry.mValueLength <= kMaxDnsServiceTxtValueSize) + { + strcpy(serviceTxtEntries.mTxtKeyBuffers[entryIndex], txtEntry.mKey); + serviceTxtEntries.mTxtEntries[entryIndex].mKey = serviceTxtEntries.mTxtKeyBuffers[entryIndex]; + serviceTxtEntries.mTxtEntries[entryIndex].mDataSize = txtEntry.mValueLength; + memcpy(serviceTxtEntries.mTxtValueBuffers[entryIndex], txtEntry.mValue, txtEntry.mValueLength); + serviceTxtEntries.mTxtEntries[entryIndex].mData = serviceTxtEntries.mTxtValueBuffers[entryIndex]; + entryIndex++; + } + } + + mdnsService.mTextEntries = serviceTxtEntries.mTxtEntries; + mdnsService.mTextEntrySize = entryIndex; + + return CHIP_NO_ERROR; +} + +template +void GenericThreadStackManagerImpl_OpenThread::OnDnsBrowseResult(otError aError, const otDnsBrowseResponse * aResponse, + void * aContext) +{ + CHIP_ERROR error; + DnsResult browseResult; + // type buffer size is kMdnsTypeAndProtocolMaxSize + . + kMaxDomainNameSize + . + termination character + char type[chip::Mdns::kMdnsTypeAndProtocolMaxSize + SrpClient::kMaxDomainNameSize + 3]; + // hostname buffer size is kMdnsHostNameMaxSize + . + kMaxDomainNameSize + . + termination character + char hostname[chip::Mdns::kMdnsHostNameMaxSize + SrpClient::kMaxDomainNameSize + 3]; + + uint8_t txtBuffer[kMaxDnsServiceTxtEntriesNumber * + (kMaxDnsServiceTxtKeySize + kMaxDnsServiceTxtValueSize + sizeof(chip::Mdns::TextEntry))]; + otDnsServiceInfo serviceInfo; + uint16_t index = 0; + bool wasAnythingBrowsed; + + if (ThreadStackMgrImpl().mDnsBrowseCallback == nullptr) + { + ChipLogError(DeviceLayer, "Invalid dns browse callback"); + return; + } + + ThreadStackMgrImpl().LockThreadStack(); + + VerifyOrExit(aError == OT_ERROR_NONE, error = MapOpenThreadError(aError)); + + error = MapOpenThreadError(otDnsBrowseResponseGetServiceName(aResponse, type, sizeof(type))); + + VerifyOrExit(error == CHIP_NO_ERROR, ); + + while (otDnsBrowseResponseGetServiceInstance(aResponse, index, browseResult.mMdnsService.mName, + sizeof(browseResult.mMdnsService.mName)) == OT_ERROR_NONE) + { + serviceInfo.mHostNameBuffer = hostname; + serviceInfo.mHostNameBufferSize = sizeof(hostname); + serviceInfo.mTxtData = txtBuffer; + serviceInfo.mTxtDataSize = sizeof(txtBuffer); + + error = MapOpenThreadError(otDnsBrowseResponseGetServiceInfo(aResponse, browseResult.mMdnsService.mName, &serviceInfo)); + + VerifyOrExit(error == CHIP_NO_ERROR, ); + + if (FromOtDnsResponseToMdnsData(serviceInfo, type, browseResult.mMdnsService, browseResult.mServiceTxtEntry) == + CHIP_NO_ERROR) + { + // Invoke callback for every service one by one instead of for the whole list due to large memory size needed to + // allocate on + // stack. + ThreadStackMgrImpl().mDnsBrowseCallback(aContext, &browseResult.mMdnsService, 1, MapOpenThreadError(aError)); + wasAnythingBrowsed = true; + } + index++; + } + +exit: + + ThreadStackMgrImpl().UnlockThreadStack(); + + // In case no service was found invoke callback to notify about failure. In other case it was already called before. + if (!wasAnythingBrowsed) + ThreadStackMgrImpl().mDnsBrowseCallback(aContext, nullptr, 0, error); +} + +template +CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_DnsBrowse(const char * aServiceName, DnsBrowseCallback aCallback, + void * aContext) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + + Impl()->LockThreadStack(); + const otDnsQueryConfig * defaultConfig = otDnsClientGetDefaultConfig(mOTInst); + + VerifyOrExit(aServiceName, error = CHIP_ERROR_INVALID_ARGUMENT); + + mDnsBrowseCallback = aCallback; + + // Append default SRP domain name to the service name. + // fullServiceName buffer size is kMdnsTypeAndProtocolMaxSize + . separator + kDefaultDomainNameSize + termination character. + char fullServiceName[chip::Mdns::kMdnsTypeAndProtocolMaxSize + 1 + SrpClient::kDefaultDomainNameSize + 1]; + snprintf(fullServiceName, sizeof(fullServiceName), "%s.%s", aServiceName, SrpClient::kDefaultDomainName); + + error = otDnsClientBrowse(mOTInst, fullServiceName, OnDnsBrowseResult, aContext, defaultConfig); + +exit: + + Impl()->UnlockThreadStack(); + + return error; +} + +template +void GenericThreadStackManagerImpl_OpenThread::OnDnsResolveResult(otError aError, const otDnsServiceResponse * aResponse, + void * aContext) +{ + CHIP_ERROR error; + DnsResult resolveResult; + // type buffer size is kMdnsTypeAndProtocolMaxSize + . + kMaxDomainNameSize + . + termination character + char type[chip::Mdns::kMdnsTypeAndProtocolMaxSize + SrpClient::kMaxDomainNameSize + 3]; + // hostname buffer size is kMdnsHostNameMaxSize + . + kMaxDomainNameSize + . + termination character + char hostname[chip::Mdns::kMdnsHostNameMaxSize + SrpClient::kMaxDomainNameSize + 3]; + uint8_t txtBuffer[kMaxDnsServiceTxtEntriesNumber * + (kMaxDnsServiceTxtKeySize + kMaxDnsServiceTxtValueSize + sizeof(chip::Mdns::TextEntry))]; + otDnsServiceInfo serviceInfo; + + if (ThreadStackMgrImpl().mDnsResolveCallback == nullptr) + { + ChipLogError(DeviceLayer, "Invalid dns browse callback"); + return; + } + + ThreadStackMgrImpl().LockThreadStack(); + + VerifyOrExit(aError == OT_ERROR_NONE, error = MapOpenThreadError(aError)); + + error = MapOpenThreadError(otDnsServiceResponseGetServiceName(aResponse, resolveResult.mMdnsService.mName, + sizeof(resolveResult.mMdnsService.mName), type, sizeof(type))); + + VerifyOrExit(error == CHIP_NO_ERROR, ); + + serviceInfo.mHostNameBuffer = hostname; + serviceInfo.mHostNameBufferSize = sizeof(hostname); + serviceInfo.mTxtData = txtBuffer; + serviceInfo.mTxtDataSize = sizeof(txtBuffer); + + error = MapOpenThreadError(otDnsServiceResponseGetServiceInfo(aResponse, &serviceInfo)); + + VerifyOrExit(error == CHIP_NO_ERROR, ); + + error = FromOtDnsResponseToMdnsData(serviceInfo, type, resolveResult.mMdnsService, resolveResult.mServiceTxtEntry); + +exit: + + ThreadStackMgrImpl().UnlockThreadStack(); + ThreadStackMgrImpl().mDnsResolveCallback(aContext, &(resolveResult.mMdnsService), error); +} + +template +CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_DnsResolve(const char * aServiceName, const char * aInstanceName, + DnsResolveCallback aCallback, void * aContext) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + + Impl()->LockThreadStack(); + const otDnsQueryConfig * defaultConfig = otDnsClientGetDefaultConfig(mOTInst); + + VerifyOrExit(aServiceName && aInstanceName, error = CHIP_ERROR_INVALID_ARGUMENT); + + mDnsResolveCallback = aCallback; + + // Append default SRP domain name to the service name. + // fullServiceName buffer size is kMdnsTypeAndProtocolMaxSize + . separator + kDefaultDomainNameSize + termination character. + char fullServiceName[chip::Mdns::kMdnsTypeAndProtocolMaxSize + 1 + SrpClient::kDefaultDomainNameSize + 1]; + snprintf(fullServiceName, sizeof(fullServiceName), "%s.%s", aServiceName, SrpClient::kDefaultDomainName); + + error = otDnsClientResolveService(mOTInst, aInstanceName, fullServiceName, OnDnsResolveResult, aContext, defaultConfig); + +exit: + + Impl()->UnlockThreadStack(); + + return error; +} +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_DNS_CLIENT #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT } // namespace Internal diff --git a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.h b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.h index 34b3911a30522a..cd542ec69f4481 100644 --- a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.h +++ b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.h @@ -32,6 +32,10 @@ #include #endif +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_DNS_CLIENT +#include +#endif + #include #include @@ -93,11 +97,16 @@ class GenericThreadStackManagerImpl_OpenThread void _OnWoBLEAdvertisingStop(void); #if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT - CHIP_ERROR _AddSrpService(const char * aInstanceName, const char * aName, uint16_t aPort, chip::Mdns::TextEntry * aTxtEntries, - size_t aTxtEntiresSize, uint32_t aLeaseInterval, uint32_t aKeyLeaseInterval); + CHIP_ERROR + _AddSrpService(const char * aInstanceName, const char * aName, uint16_t aPort, chip::Mdns::TextEntry * aTxtEntries, + size_t aTxtEntiresSize, uint32_t aLeaseInterval, uint32_t aKeyLeaseInterval); CHIP_ERROR _RemoveSrpService(const char * aInstanceName, const char * aName); CHIP_ERROR _RemoveAllSrpServices(); CHIP_ERROR _SetupSrpHost(const char * aHostName); +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_DNS_CLIENT + CHIP_ERROR _DnsBrowse(const char * aServiceName, DnsBrowseCallback aCallback, void * aContext); + CHIP_ERROR _DnsResolve(const char * aServiceName, const char * aInstanceName, DnsResolveCallback aCallback, void * aContext); +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_DNS_CLIENT #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT // ===== Members available to the implementation subclass. @@ -119,14 +128,25 @@ class GenericThreadStackManagerImpl_OpenThread struct SrpClient { - static constexpr uint8_t kMaxServicesNumber = CHIP_DEVICE_CONFIG_THREAD_SRP_MAX_SERVICES; - static constexpr uint8_t kMaxInstanceNameSize = chip::Mdns::kMdnsInstanceNameMaxSize; - static constexpr uint8_t kMaxNameSize = chip::Mdns::kMdnsTypeAndProtocolMaxSize; - static constexpr uint8_t kMaxHostNameSize = 16; - // Thread only supports operational discovery + static constexpr uint8_t kMaxServicesNumber = CHIP_DEVICE_CONFIG_THREAD_SRP_MAX_SERVICES; + static constexpr uint8_t kMaxInstanceNameSize = chip::Mdns::kMdnsInstanceNameMaxSize; + static constexpr uint8_t kMaxNameSize = chip::Mdns::kMdnsTypeAndProtocolMaxSize; + static constexpr uint8_t kMaxHostNameSize = 16; + static constexpr const char * kDefaultDomainName = "default.service.arpa"; + static constexpr uint8_t kDefaultDomainNameSize = 20; + static constexpr uint8_t kMaxDomainNameSize = 32; + +#if CHIP_DEVICE_CONFIG_ENABLE_EXTENDED_DISCOVERY + // Thread supports both operational and commissionable discovery, so buffers sizes must be worst case. + static constexpr uint8_t kMaxTxtEntriesNumber = chip::Mdns::CommissionAdvertisingParameters::kNumAdvertisingTxtEntries; + static constexpr uint8_t kMaxTxtValueSize = chip::Mdns::CommissionAdvertisingParameters::kTxtMaxValueSize; + static constexpr uint8_t kMaxTxtKeySize = chip::Mdns::OperationalAdvertisingParameters::kTxtMaxKeySize; +#else + // Thread only supports operational discovery. static constexpr uint8_t kMaxTxtEntriesNumber = chip::Mdns::OperationalAdvertisingParameters::kNumAdvertisingTxtEntries; static constexpr uint8_t kMaxTxtValueSize = chip::Mdns::OperationalAdvertisingParameters::kTxtMaxValueSize; static constexpr uint8_t kMaxTxtKeySize = chip::Mdns::OperationalAdvertisingParameters::kTxtMaxKeySize; +#endif // CHIP_DEVICE_CONFIG_ENABLE_EXTENDED_DISCOVERY struct Service { @@ -149,6 +169,42 @@ class GenericThreadStackManagerImpl_OpenThread const otSrpClientService * aRemovedServices, void * aContext); static void OnSrpClientStateChange(const otSockAddr * aServerSockAddr, void * aContext); +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_DNS_CLIENT +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_COMMISSIONABLE_DISCOVERY + // Thread supports both operational and commissionable discovery, so buffers sizes must be worst case. + static constexpr uint8_t kMaxDnsServiceTxtEntriesNumber = + chip::Mdns::CommissionAdvertisingParameters::kNumAdvertisingTxtEntries; + static constexpr uint8_t kMaxDnsServiceTxtValueSize = chip::Mdns::CommissionAdvertisingParameters::kTxtMaxValueSize; + static constexpr uint8_t kMaxDnsServiceTxtKeySize = chip::Mdns::OperationalAdvertisingParameters::kTxtMaxKeySize; +#else + // Thread only supports operational discovery. + static constexpr uint8_t kMaxDnsServiceTxtEntriesNumber = + chip::Mdns::OperationalAdvertisingParameters::kNumAdvertisingTxtEntries; + static constexpr uint8_t kMaxDnsServiceTxtValueSize = chip::Mdns::OperationalAdvertisingParameters::kTxtMaxValueSize; + static constexpr uint8_t kMaxDnsServiceTxtKeySize = chip::Mdns::OperationalAdvertisingParameters::kTxtMaxKeySize; +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_COMMISSIONABLE_DISCOVERY + + DnsBrowseCallback mDnsBrowseCallback; + DnsResolveCallback mDnsResolveCallback; + + struct DnsServiceTxtEntries + { + chip::Mdns::TextEntry mTxtEntries[kMaxDnsServiceTxtEntriesNumber]; + uint8_t mTxtValueBuffers[kMaxDnsServiceTxtEntriesNumber][kMaxDnsServiceTxtValueSize]; + char mTxtKeyBuffers[kMaxDnsServiceTxtEntriesNumber][kMaxDnsServiceTxtKeySize]; + }; + + struct DnsResult + { + chip::Mdns::MdnsService mMdnsService; + DnsServiceTxtEntries mServiceTxtEntry; + }; + + static void OnDnsBrowseResult(otError aError, const otDnsBrowseResponse * aResponse, void * aContext); + static void OnDnsResolveResult(otError aError, const otDnsServiceResponse * aResponse, void * aContext); + static CHIP_ERROR FromOtDnsResponseToMdnsData(otDnsServiceInfo & serviceInfo, const char * serviceType, + chip::Mdns::MdnsService & mdnsService, DnsServiceTxtEntries & serviceTxtEntries); +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_DNS_CLIENT #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT static void OnJoinerComplete(otError aError, void * aContext); diff --git a/src/platform/OpenThread/MdnsImpl.cpp b/src/platform/OpenThread/MdnsImpl.cpp index 831da3e2248026..d581c89b443563 100644 --- a/src/platform/OpenThread/MdnsImpl.cpp +++ b/src/platform/OpenThread/MdnsImpl.cpp @@ -39,6 +39,7 @@ const char * GetProtocolString(MdnsServiceProtocol protocol) CHIP_ERROR ChipMdnsPublishService(const MdnsService * service) { +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT CHIP_ERROR result = CHIP_NO_ERROR; VerifyOrExit(service, result = CHIP_ERROR_INVALID_ARGUMENT); @@ -56,15 +57,23 @@ CHIP_ERROR ChipMdnsPublishService(const MdnsService * service) exit: return result; +#else + return CHIP_ERROR_NOT_IMPLEMENTED; +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT } CHIP_ERROR ChipMdnsStopPublish() { +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT return ThreadStackMgr().RemoveAllSrpServices(); +#else + return CHIP_ERROR_NOT_IMPLEMENTED; +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT } CHIP_ERROR ChipMdnsStopPublishService(const MdnsService * service) { +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT if (service == nullptr) return CHIP_ERROR_INVALID_ARGUMENT; @@ -72,17 +81,40 @@ CHIP_ERROR ChipMdnsStopPublishService(const MdnsService * service) snprintf(serviceType, sizeof(serviceType), "%s.%s", service->mType, GetProtocolString(service->mProtocol)); return ThreadStackMgr().RemoveSrpService(service->mName, serviceType); +#else + return CHIP_ERROR_NOT_IMPLEMENTED; +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT } CHIP_ERROR ChipMdnsBrowse(const char * type, MdnsServiceProtocol protocol, Inet::IPAddressType addressType, Inet::InterfaceId interface, MdnsBrowseCallback callback, void * context) { +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT && CHIP_DEVICE_CONFIG_ENABLE_THREAD_DNS_CLIENT + if (type == nullptr || callback == nullptr) + return CHIP_ERROR_INVALID_ARGUMENT; + + char serviceType[chip::Mdns::kMdnsTypeAndProtocolMaxSize + 1]; + snprintf(serviceType, sizeof(serviceType), "%s.%s", type, GetProtocolString(protocol)); + + return ThreadStackMgr().DnsBrowse(serviceType, callback, context); +#else return CHIP_ERROR_NOT_IMPLEMENTED; +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT && CHIP_DEVICE_CONFIG_ENABLE_THREAD_DNS_CLIENT } CHIP_ERROR ChipMdnsResolve(MdnsService * browseResult, Inet::InterfaceId interface, MdnsResolveCallback callback, void * context) { +#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT && CHIP_DEVICE_CONFIG_ENABLE_THREAD_DNS_CLIENT + if (browseResult == nullptr || callback == nullptr) + return CHIP_ERROR_INVALID_ARGUMENT; + + char serviceType[chip::Mdns::kMdnsTypeAndProtocolMaxSize + 1]; + snprintf(serviceType, sizeof(serviceType), "%s.%s", browseResult->mType, GetProtocolString(browseResult->mProtocol)); + + return ThreadStackMgr().DnsResolve(serviceType, browseResult->mName, callback, context); +#else return CHIP_ERROR_NOT_IMPLEMENTED; +#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT && CHIP_DEVICE_CONFIG_ENABLE_THREAD_DNS_CLIENT } } // namespace Mdns diff --git a/src/platform/nrfconnect/CHIPDevicePlatformConfig.h b/src/platform/nrfconnect/CHIPDevicePlatformConfig.h index 346638d38b98fd..b2096a58d07f0a 100644 --- a/src/platform/nrfconnect/CHIPDevicePlatformConfig.h +++ b/src/platform/nrfconnect/CHIPDevicePlatformConfig.h @@ -75,4 +75,8 @@ #ifdef CONFIG_CHIP_ENABLE_DNSSD_SRP #define CHIP_DEVICE_CONFIG_ENABLE_MDNS 1 #define CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT 1 +#ifdef CONFIG_CHIP_ENABLE_DNS_CLIENT +#define CHIP_DEVICE_CONFIG_ENABLE_THREAD_DNS_CLIENT 1 +#define CHIP_DEVICE_CONFIG_ENABLE_THREAD_COMMISSIONABLE_DISCOVERY 1 +#endif // CONFIG_CHIP_ENABLE_DNS_CLIENT #endif // CONFIG_CHIP_ENABLE_DNSSD_SRP