From ca26e5dbdfde5326615e04825370018614bc3c91 Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Tue, 8 Dec 2020 12:29:23 -0500 Subject: [PATCH 01/19] Initial definition of an mDNS advertiser --- src/lib/mdns/Advertiser.h | 86 ++++++ src/lib/mdns/Advertiser_ImplMinimalMdns.cpp | 244 ++++++++++++++++++ src/lib/mdns/Advertiser_ImplNone.cpp | 52 ++++ src/lib/mdns/BUILD.gn | 15 ++ src/lib/mdns/minimal/records/ResourceRecord.h | 6 +- src/lib/mdns/minimal/records/Srv.h | 5 +- src/lib/mdns/minimal/responders/Srv.h | 4 +- 7 files changed, 407 insertions(+), 5 deletions(-) create mode 100644 src/lib/mdns/Advertiser.h create mode 100644 src/lib/mdns/Advertiser_ImplMinimalMdns.cpp create mode 100644 src/lib/mdns/Advertiser_ImplNone.cpp diff --git a/src/lib/mdns/Advertiser.h b/src/lib/mdns/Advertiser.h new file mode 100644 index 00000000000000..d9f6f5bdc11817 --- /dev/null +++ b/src/lib/mdns/Advertiser.h @@ -0,0 +1,86 @@ +/* + * + * Copyright (c) 2020 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. + */ + +#pragma once + +#include + +#include +#include + +namespace chip { +namespace Mdns { + +/// Defines parameters required for advertising a CHIP node +/// over mDNS as an 'operationally ready' node. +class OperationalAdvertisingParameters +{ +public: + OperationalAdvertisingParameters & SetFabricId(uint64_t fabricId) + { + mFabricId = fabricId; + return *this; + } + uint64_t GetFabricId() const { return mFabricId; } + + OperationalAdvertisingParameters & SetNodeId(uint64_t nodeId) + { + mNodeId = nodeId; + return *this; + } + uint64_t GetNodeId() const { return mNodeId; } + + OperationalAdvertisingParameters & SetPort(uint16_t port) + { + mPort = port; + return *this; + } + uint64_t GetPort() const { return mPort; } + + OperationalAdvertisingParameters & EnableIpV4(bool enable) + { + mEnableIPv4 = enable; + return *this; + } + bool IsIPv4Enabled() const { return mEnableIPv4; } + +private: + uint64_t mFabricId = 0; + uint64_t mNodeId = 0; + uint16_t mPort = CHIP_PORT; + bool mEnableIPv4 = true; +}; + +/// Handles advertising of CHIP nodes +class ServiceAdvertiser +{ +public: + virtual ~ServiceAdvertiser() {} + + /// Starts the advertiser. Items 'Advertised' will become visible. + /// May be called before OR after Advertise() calls. + virtual CHIP_ERROR Start(chip::Inet::InetLayer * inetLayer, uint16_t port) = 0; + + /// Advertises the CHIP node as an operational node + virtual CHIP_ERROR Advertise(const OperationalAdvertisingParameters & params) = 0; + + /// Provides the system-wide implementation of the service advertiser + static ServiceAdvertiser & Instance(); +}; + +} // namespace Mdns +} // namespace chip \ No newline at end of file diff --git a/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp b/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp new file mode 100644 index 00000000000000..1f768d4c8384e6 --- /dev/null +++ b/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp @@ -0,0 +1,244 @@ +/* + * + * Copyright (c) 2020 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 "Advertiser.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace chip { +namespace Mdns { +namespace { + +class AllInterfaces : public mdns::Minimal::ListenIterator +{ +public: + AllInterfaces() {} + + bool Next(chip::Inet::InterfaceId * id, chip::Inet::IPAddressType * type) override + { + if (mState == State::kIpV4) + { + *id = INET_NULL_INTERFACEID; + *type = chip::Inet::kIPAddressType_IPv4; + mState = State::kIpV6; + + SkipToFirstValidInterface(); + return true; + } + + if (!mIterator.HasCurrent()) + { + return false; + } + + *id = mIterator.GetInterfaceId(); + *type = chip::Inet::kIPAddressType_IPv6; + + for (mIterator.Next(); SkipCurrentInterface(); mIterator.Next()) + { + } + return true; + } + +private: + enum class State + { + kIpV4, + kIpV6, + }; + State mState; + chip::Inet::InterfaceIterator mIterator; + + void SkipToFirstValidInterface() + { + if (SkipCurrentInterface()) + { + while (mIterator.Next()) + { + if (!SkipCurrentInterface()) + { + break; + } + } + } + } + + bool SkipCurrentInterface() + { + if (!mIterator.HasCurrent()) + { + return false; // nothing to try. + } + + if (!mIterator.IsUp() || !mIterator.SupportsMulticast()) + { + return true; // not a usable interface + } + char name[64]; + if (!mIterator.GetInterfaceName(name, sizeof(name)) == CHIP_NO_ERROR) + { + ChipLogError(Discovery, "Interface iterator failed to get interface name."); + return true; + } + + if (strncmp(name, "lo", 2) == 0) + { + ChipLogDetail(Discovery, "Skipping interface '%s' (assume local loopback)", name); + return true; + } + return false; + } +}; + +class AdvertiserMinMdns : public ServiceAdvertiser, + public mdns::Minimal::ServerDelegate, // gets queries + public mdns::Minimal::ParserDelegate // parses queries +{ +public: + AdvertiserMinMdns() : + mResponseSender(&mServer, &mQueryResponder), mPtrResponder(mServerQName, mOperationalServiceQName), + mSrvResponder(mOperationalServiceQName, + mdns::Minimal::SrvResourceRecord(mOperationalServiceQName, mServerQName, CHIP_PORT)), + mIPv4Responder(mServerQName), mIPv6Responder(mServerQName) + + {} + + // Service advertiser + CHIP_ERROR Start(chip::Inet::InetLayer * inetLayer, uint16_t port) override; + CHIP_ERROR Advertise(const OperationalAdvertisingParameters & params) override; + + // ServerDelegate + void OnQuery(const mdns::Minimal::BytesRange & data, const chip::Inet::IPPacketInfo * info) override; + void OnResponse(const mdns::Minimal::BytesRange & data, const chip::Inet::IPPacketInfo * info) override {} + + // ParserDelegate + void OnHeader(mdns::Minimal::ConstHeaderRef & header) override { mMessageId = header.GetMessageId(); } + void OnResource(mdns::Minimal::ResourceType type, const mdns::Minimal::ResourceData & data) override {} + void OnQuery(const mdns::Minimal::QueryData & data) override; + +private: + static constexpr size_t kMaxEndPoints = 10; + static constexpr size_t kMaxRecords = 16; + + mdns::Minimal::Server mServer; + mdns::Minimal::QueryResponder mQueryResponder; + mdns::Minimal::ResponseSender mResponseSender; + + // current request handling + const chip::Inet::IPPacketInfo * mCurrentSource = nullptr; + uint32_t mMessageId = 0; + + /// data members for variable things + char mServerName[64] = ""; + + mdns::Minimal::QNamePart mServerQName[2] = { mServerName, "local" }; + mdns::Minimal::QNamePart mOperationalServiceQName[4] = { mServerName, "_chip", "_tcp", "local" }; + + /// responders + mdns::Minimal::PtrResponder mPtrResponder; + mdns::Minimal::SrvResponder mSrvResponder; + mdns::Minimal::IPv4Responder mIPv4Responder; + mdns::Minimal::IPv6Responder mIPv6Responder; +}; + +void AdvertiserMinMdns::OnQuery(const mdns::Minimal::BytesRange & data, const chip::Inet::IPPacketInfo * info) +{ + mCurrentSource = info; + if (!mdns::Minimal::ParsePacket(data, this)) + { + ChipLogError(Discovery, "Failed to parse mDNS query"); + } + mCurrentSource = nullptr; +} + +void AdvertiserMinMdns::OnQuery(const mdns::Minimal::QueryData & data) +{ + if (mCurrentSource == nullptr) + { + ChipLogError(Discovery, "INTERNAL CONSISTENCY ERROR: missing query source"); + return; + } + + CHIP_ERROR err = mResponseSender.Respond(mMessageId, data, mCurrentSource); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Discovery, "Failed to reply to query: %s", ErrorStr(err)); + } +} + +CHIP_ERROR AdvertiserMinMdns::Start(chip::Inet::InetLayer * inetLayer, uint16_t port) +{ + AllInterfaces allInterfaces; + + return mServer.Listen(inetLayer, &allInterfaces, port); +} + +CHIP_ERROR AdvertiserMinMdns::Advertise(const OperationalAdvertisingParameters & params) +{ + mQueryResponder.Init(); // start fresh + + /// need to set server name + size_t len = snprintf(mServerName, sizeof(mServerName), "%" PRIu64 "-%" PRIu64, params.GetFabricId(), params.GetNodeId()); + if (len >= sizeof(mServerName)) + { + return CHIP_ERROR_NO_MEMORY; + } + + mSrvResponder.SetRecord(mdns::Minimal::SrvResourceRecord(mOperationalServiceQName, mServerQName, params.GetPort())); + if (!mQueryResponder.AddResponder(&mSrvResponder).SetReportInServiceListing(true).IsValid()) + { + ChipLogError(Discovery, "Failed to add SRV record mDNS responder"); + return CHIP_ERROR_NO_MEMORY; + } + + if (!mQueryResponder.AddResponder(&mIPv6Responder).IsValid()) + { + ChipLogError(Discovery, "Failed to add IPv6 mDNS responder"); + return CHIP_ERROR_NO_MEMORY; + } + + if (params.IsIPv4Enabled()) + { + if (!mQueryResponder.AddResponder(&mIPv4Responder).IsValid()) + { + ChipLogError(Discovery, "Failed to add IPv4 mDNS responder"); + return CHIP_ERROR_NO_MEMORY; + } + } + + return CHIP_NO_ERROR; +} + +AdvertiserMinMdns gAdvertiser; +} // namespace + +ServiceAdvertiser & ServiceAdvertiser::Instance() +{ + return gAdvertiser; +} + +} // namespace Mdns +} // namespace chip diff --git a/src/lib/mdns/Advertiser_ImplNone.cpp b/src/lib/mdns/Advertiser_ImplNone.cpp new file mode 100644 index 00000000000000..467a94b1c4e633 --- /dev/null +++ b/src/lib/mdns/Advertiser_ImplNone.cpp @@ -0,0 +1,52 @@ +/* + * + * Copyright (c) 2020 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 "Advertiser.h" + +#include + +namespace chip { +namespace Mdns { +namespace { + +class NoneAdvertiser : public ServiceAdvertiser +{ +public: + CHIP_ERROR Start(chip::Inet::InetLayer * inetLayet, uint16_t port) override + { + ChipLogError(Discovery, "mDNS advertising not available. mDNS start disabled."); + return CHIP_ERROR_NOT_IMPLEMENTED; + } + + CHIP_ERROR Advertise(const OperationalAdvertisingParameters & params) override + { + ChipLogError(Discovery, "mDNS advertising not available. Operational Advertisement failed."); + return CHIP_ERROR_NOT_IMPLEMENTED; + } +}; + +NoneAdvertiser gAdvertiser; + +} // namespace + +ServiceAdvertiser & ServiceAdvertiser::Instance() +{ + return gAdvertiser; +} + +} // namespace Mdns +} // namespace chip \ No newline at end of file diff --git a/src/lib/mdns/BUILD.gn b/src/lib/mdns/BUILD.gn index 0704363be4be50..affd4decf06212 100644 --- a/src/lib/mdns/BUILD.gn +++ b/src/lib/mdns/BUILD.gn @@ -14,6 +14,11 @@ import("//build_overrides/chip.gni") +declare_args() { + # Set up what advertiser to use for mDNS advertisement + chip_mdns_avertiser = "minimal-mdns" +} + source_set("platform_header") { sources = [ "platform/Mdns.h" ] } @@ -29,5 +34,15 @@ static_library("mdns") { sources = [ "DiscoveryManager.cpp", "DiscoveryManager.h", + "Advertiser.h" ] + + if (chip_mdns_avertiser == "none") { + sources += [ "Advertiser_ImplNone.cpp" ] + } else if (chip_mdns_avertiser == "minimal-mdns") { + sources += [ "Advertiser_ImplMinimalMdns.cpp" ] + public_deps += ["${chip_root}/src/lib/mdns/minimal"] + } else { + assert(false, "Unknown mDNS advertiser implementation.") + } } diff --git a/src/lib/mdns/minimal/records/ResourceRecord.h b/src/lib/mdns/minimal/records/ResourceRecord.h index 85d98bba1e449f..74ff2a980d5b28 100644 --- a/src/lib/mdns/minimal/records/ResourceRecord.h +++ b/src/lib/mdns/minimal/records/ResourceRecord.h @@ -35,6 +35,8 @@ class ResourceRecord virtual ~ResourceRecord() {} + ResourceRecord & operator=(const ResourceRecord & other) = default; + const FullQName & GetName() const { return mQName; } QClass GetClass() const { return QClass::IN; } QType GetType() const { return mType; } @@ -57,9 +59,9 @@ class ResourceRecord ResourceRecord(QType type, FullQName name) : mType(type), mQName(name) {} private: - const QType mType; + QType mType; uint64_t mTtl = kDefaultTtl; - const FullQName mQName; + FullQName mQName; }; } // namespace Minimal diff --git a/src/lib/mdns/minimal/records/Srv.h b/src/lib/mdns/minimal/records/Srv.h index 9b1dd51ca6833f..3dc7211cbb5ef3 100644 --- a/src/lib/mdns/minimal/records/Srv.h +++ b/src/lib/mdns/minimal/records/Srv.h @@ -28,6 +28,7 @@ class SrvResourceRecord : public ResourceRecord SrvResourceRecord(const FullQName & qName, const FullQName & serverName, uint16_t port) : ResourceRecord(QType::SRV, qName), mServerName(serverName), mPort(port) {} + SrvResourceRecord & operator=(const SrvResourceRecord & other) = default; FullQName GetServerName() const { return mServerName; } uint16_t GetPort() const { return mPort; } @@ -49,8 +50,8 @@ class SrvResourceRecord : public ResourceRecord } private: - const FullQName mServerName; - const uint16_t mPort; + FullQName mServerName; + uint16_t mPort; uint16_t mPriority = 0; uint16_t mWeight = 0; }; diff --git a/src/lib/mdns/minimal/responders/Srv.h b/src/lib/mdns/minimal/responders/Srv.h index 876c1c62bbae35..54c5afdb0811ed 100644 --- a/src/lib/mdns/minimal/responders/Srv.h +++ b/src/lib/mdns/minimal/responders/Srv.h @@ -28,13 +28,15 @@ class SrvResponder : public Responder public: SrvResponder(const FullQName & qname, const SrvResourceRecord & record) : Responder(QType::SRV, qname), mRecord(record) {} + void SetRecord(const SrvResourceRecord & record) { mRecord = record; } + void AddAllResponses(const chip::Inet::IPPacketInfo * source, ResponderDelegate * delegate) override { delegate->AddResponse(mRecord); } private: - const SrvResourceRecord mRecord; + SrvResourceRecord mRecord; }; } // namespace Minimal From 97a79c228e466e1abea4367f2759c808d4a67d83 Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Tue, 8 Dec 2020 12:34:42 -0500 Subject: [PATCH 02/19] Make chip app server listen on mdns by default --- examples/common/chip-app-server/Server.cpp | 4 ++++ src/lib/mdns/Advertiser.h | 2 ++ src/lib/mdns/Advertiser_ImplMinimalMdns.cpp | 5 +++++ 3 files changed, 11 insertions(+) diff --git a/examples/common/chip-app-server/Server.cpp b/examples/common/chip-app-server/Server.cpp index 0667f37c0a0dbb..bf94b76cf4be45 100644 --- a/examples/common/chip-app-server/Server.cpp +++ b/examples/common/chip-app-server/Server.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -158,6 +159,9 @@ void InitServer(AppDelegate * delegate) SuccessOrExit(err = gRendezvousServer.Init(params, &gTransports)); } + err = Mdns::ServiceAdvertiser::Instance().Start(&DeviceLayer::InetLayer, chip::Mdns::kMdnsPort); + SuccessOrExit(err); + err = gSessions.NewPairing(peer, chip::kTestControllerNodeId, &gTestPairing); SuccessOrExit(err); diff --git a/src/lib/mdns/Advertiser.h b/src/lib/mdns/Advertiser.h index d9f6f5bdc11817..51ee4fff602141 100644 --- a/src/lib/mdns/Advertiser.h +++ b/src/lib/mdns/Advertiser.h @@ -25,6 +25,8 @@ namespace chip { namespace Mdns { +static constexpr uint16_t kMdnsPort = 5353; + /// Defines parameters required for advertising a CHIP node /// over mDNS as an 'operationally ready' node. class OperationalAdvertisingParameters diff --git a/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp b/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp index 1f768d4c8384e6..d9a9684419a2b6 100644 --- a/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp +++ b/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp @@ -39,6 +39,7 @@ class AllInterfaces : public mdns::Minimal::ListenIterator bool Next(chip::Inet::InterfaceId * id, chip::Inet::IPAddressType * type) override { +#if INET_CONFIG_ENABLE_IPV4 if (mState == State::kIpV4) { *id = INET_NULL_INTERFACEID; @@ -48,6 +49,10 @@ class AllInterfaces : public mdns::Minimal::ListenIterator SkipToFirstValidInterface(); return true; } +#else + mState = State::kIpV6; + SkipToFirstValidInterface(); +#endif if (!mIterator.HasCurrent()) { From 38b611fcd35c7fe4d955a9712ecaeae56285b372 Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Tue, 8 Dec 2020 12:59:12 -0500 Subject: [PATCH 03/19] Replace DiscoveryManager with advertiser --- .../esp32/main/DeviceCallbacks.cpp | 13 ++++++++++--- .../common/chip-app-server/RendezvousServer.cpp | 7 +++++-- examples/common/chip-app-server/Server.cpp | 15 ++++++++++++++- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/examples/all-clusters-app/esp32/main/DeviceCallbacks.cpp b/examples/all-clusters-app/esp32/main/DeviceCallbacks.cpp index f40b1fa013e8c3..42f1e7074fba7b 100644 --- a/examples/all-clusters-app/esp32/main/DeviceCallbacks.cpp +++ b/examples/all-clusters-app/esp32/main/DeviceCallbacks.cpp @@ -33,7 +33,7 @@ #include "gen/attribute-id.h" #include "gen/cluster-id.h" #include -#include +#include #include static const char * TAG = "app-devicecallbacks"; @@ -92,7 +92,11 @@ void DeviceCallbacks::OnInternetConnectivityChange(const ChipDeviceEvent * event { ESP_LOGI(TAG, "Server ready at: %s:%d", event->InternetConnectivityChange.address, CHIP_PORT); wifiLED.Set(true); - chip::Mdns::DiscoveryManager::GetInstance().StartPublishDevice(); + + if (chip::Mdns::ServiceAdvertiser::Instance().Start(DeviceLayer::InetLayer, chip::Mdns::kMdnsPort) != CHIP_NO_ERROR) + { + ESP_LOGE(TAG("Failed to start mDNS advertisement")); + } } else if (event->InternetConnectivityChange.IPv4 == kConnectivity_Lost) { @@ -102,7 +106,10 @@ void DeviceCallbacks::OnInternetConnectivityChange(const ChipDeviceEvent * event if (event->InternetConnectivityChange.IPv6 == kConnectivity_Established) { ESP_LOGI(TAG, "IPv6 Server ready..."); - chip::Mdns::DiscoveryManager::GetInstance().StartPublishDevice(); + if (chip::Mdns::ServiceAdvertiser::Instance().Start(DeviceLayer::InetLayer, chip::Mdns::kMdnsPort) != CHIP_NO_ERROR) + { + ESP_LOGE(TAG("Failed to start mDNS advertisement")); + } } else if (event->InternetConnectivityChange.IPv6 == kConnectivity_Lost) { diff --git a/examples/common/chip-app-server/RendezvousServer.cpp b/examples/common/chip-app-server/RendezvousServer.cpp index 1bf3a980285764..bf52764e5d86c1 100644 --- a/examples/common/chip-app-server/RendezvousServer.cpp +++ b/examples/common/chip-app-server/RendezvousServer.cpp @@ -25,7 +25,7 @@ #if CHIP_ENABLE_OPENTHREAD #include #endif -#include +#include using namespace ::chip::Inet; using namespace ::chip::Transport; @@ -97,7 +97,10 @@ void RendezvousServer::OnRendezvousStatusUpdate(Status status, CHIP_ERROR err) case RendezvousSessionDelegate::NetworkProvisioningSuccess: ChipLogProgress(AppServer, "Device was assigned network credentials"); - chip::Mdns::DiscoveryManager::GetInstance().StartPublishDevice(); + if (chip::Mdns::ServiceAdvertiser::Instance().Start(DeviceLayer::InetLayer, chip::Mdns::kMdnsPort) != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "Failed to start mDNS advertisement")); + } if (mDelegate != nullptr) { mDelegate->OnRendezvousStopped(); diff --git a/examples/common/chip-app-server/Server.cpp b/examples/common/chip-app-server/Server.cpp index bf94b76cf4be45..1bcbdfdd611c9e 100644 --- a/examples/common/chip-app-server/Server.cpp +++ b/examples/common/chip-app-server/Server.cpp @@ -146,6 +146,20 @@ void InitServer(AppDelegate * delegate) ChipLogProgress(AppServer, "Rendezvous and Secure Pairing skipped. Using test secret."); err = gSessions.NewPairing(peer, chip::kTestControllerNodeId, &gTestPairing); SuccessOrExit(err); + + constexpr uint64_t kTestFabricId = 12344321; + + err = Mdns::ServiceAdvertiser::Instance().Advertise(Mdns::OperationalAdvertisingParameters() + .SetFabricId(kTestFabricId) + .SetNodeId(chip::kTestDeviceNodeId) + .SetPort(CHIP_PORT) +#if INET_CONFIG_ENABLE_IPV4 + .EnableIpV4(true) +#else + .EnableIpV4(false) +#endif + ); + SuccessOrExit(err); } else { @@ -166,7 +180,6 @@ void InitServer(AppDelegate * delegate) SuccessOrExit(err); gSessions.SetDelegate(&gCallbacks); - chip::Mdns::DiscoveryManager::GetInstance().StartPublishDevice(kIPAddressType_IPv6); exit: if (err != CHIP_NO_ERROR) From fce86dbcb77837f3b32337b380518c76786ad4c9 Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Tue, 8 Dec 2020 13:03:43 -0500 Subject: [PATCH 04/19] Fix compilation, ensure we shutdown before we listen for mDNS server, to make sure multiple start calls work --- examples/all-clusters-app/esp32/main/DeviceCallbacks.cpp | 8 ++++---- examples/common/chip-app-server/RendezvousServer.cpp | 4 ++-- src/lib/mdns/Advertiser_ImplMinimalMdns.cpp | 3 ++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/examples/all-clusters-app/esp32/main/DeviceCallbacks.cpp b/examples/all-clusters-app/esp32/main/DeviceCallbacks.cpp index 42f1e7074fba7b..6f7e8a48b9339a 100644 --- a/examples/all-clusters-app/esp32/main/DeviceCallbacks.cpp +++ b/examples/all-clusters-app/esp32/main/DeviceCallbacks.cpp @@ -93,9 +93,9 @@ void DeviceCallbacks::OnInternetConnectivityChange(const ChipDeviceEvent * event ESP_LOGI(TAG, "Server ready at: %s:%d", event->InternetConnectivityChange.address, CHIP_PORT); wifiLED.Set(true); - if (chip::Mdns::ServiceAdvertiser::Instance().Start(DeviceLayer::InetLayer, chip::Mdns::kMdnsPort) != CHIP_NO_ERROR) + if (chip::Mdns::ServiceAdvertiser::Instance().Start(&DeviceLayer::InetLayer, chip::Mdns::kMdnsPort) != CHIP_NO_ERROR) { - ESP_LOGE(TAG("Failed to start mDNS advertisement")); + ESP_LOGE(TAG, "Failed to start mDNS advertisement"); } } else if (event->InternetConnectivityChange.IPv4 == kConnectivity_Lost) @@ -106,9 +106,9 @@ void DeviceCallbacks::OnInternetConnectivityChange(const ChipDeviceEvent * event if (event->InternetConnectivityChange.IPv6 == kConnectivity_Established) { ESP_LOGI(TAG, "IPv6 Server ready..."); - if (chip::Mdns::ServiceAdvertiser::Instance().Start(DeviceLayer::InetLayer, chip::Mdns::kMdnsPort) != CHIP_NO_ERROR) + if (chip::Mdns::ServiceAdvertiser::Instance().Start(&DeviceLayer::InetLayer, chip::Mdns::kMdnsPort) != CHIP_NO_ERROR) { - ESP_LOGE(TAG("Failed to start mDNS advertisement")); + ESP_LOGE(TAG, "Failed to start mDNS advertisement"); } } else if (event->InternetConnectivityChange.IPv6 == kConnectivity_Lost) diff --git a/examples/common/chip-app-server/RendezvousServer.cpp b/examples/common/chip-app-server/RendezvousServer.cpp index bf52764e5d86c1..9fbd78dc65ca91 100644 --- a/examples/common/chip-app-server/RendezvousServer.cpp +++ b/examples/common/chip-app-server/RendezvousServer.cpp @@ -97,9 +97,9 @@ void RendezvousServer::OnRendezvousStatusUpdate(Status status, CHIP_ERROR err) case RendezvousSessionDelegate::NetworkProvisioningSuccess: ChipLogProgress(AppServer, "Device was assigned network credentials"); - if (chip::Mdns::ServiceAdvertiser::Instance().Start(DeviceLayer::InetLayer, chip::Mdns::kMdnsPort) != CHIP_NO_ERROR) + if (chip::Mdns::ServiceAdvertiser::Instance().Start(&DeviceLayer::InetLayer, chip::Mdns::kMdnsPort) != CHIP_NO_ERROR) { - ChipLogError(AppServer, "Failed to start mDNS advertisement")); + ChipLogError(AppServer, "Failed to start mDNS advertisement"); } if (mDelegate != nullptr) { diff --git a/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp b/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp index d9a9684419a2b6..d782885563911b 100644 --- a/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp +++ b/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp @@ -196,8 +196,9 @@ void AdvertiserMinMdns::OnQuery(const mdns::Minimal::QueryData & data) CHIP_ERROR AdvertiserMinMdns::Start(chip::Inet::InetLayer * inetLayer, uint16_t port) { - AllInterfaces allInterfaces; + mServer.Shutdown(); + AllInterfaces allInterfaces; return mServer.Listen(inetLayer, &allInterfaces, port); } From ac60dc8fb231775d585b36bd7774b2ada90c7954 Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Tue, 8 Dec 2020 13:47:28 -0500 Subject: [PATCH 05/19] Always advertise as operational, add some more logging --- examples/common/chip-app-server/Server.cpp | 29 ++++++++++++--------- src/lib/mdns/Advertiser_ImplMinimalMdns.cpp | 9 ++++++- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/examples/common/chip-app-server/Server.cpp b/examples/common/chip-app-server/Server.cpp index 1bcbdfdd611c9e..853906c0abe02b 100644 --- a/examples/common/chip-app-server/Server.cpp +++ b/examples/common/chip-app-server/Server.cpp @@ -146,10 +146,24 @@ void InitServer(AppDelegate * delegate) ChipLogProgress(AppServer, "Rendezvous and Secure Pairing skipped. Using test secret."); err = gSessions.NewPairing(peer, chip::kTestControllerNodeId, &gTestPairing); SuccessOrExit(err); + } + else + { + RendezvousParameters params; + uint32_t pinCode; - constexpr uint64_t kTestFabricId = 12344321; + SuccessOrExit(err = DeviceLayer::ConfigurationMgr().GetSetupPinCode(pinCode)); + params.SetSetupPINCode(pinCode) + .SetBleLayer(DeviceLayer::ConnectivityMgr().GetBleLayer()) + .SetPeerAddress(Transport::PeerAddress::BLE()); + SuccessOrExit(err = gRendezvousServer.Init(params, &gTransports)); + } - err = Mdns::ServiceAdvertiser::Instance().Advertise(Mdns::OperationalAdvertisingParameters() + // TODO: advertise this only when really operational once we support both + // operational and commisioning advertising is supported. + { + constexpr uint64_t kTestFabricId = 12344321; + err = Mdns::ServiceAdvertiser::Instance().Advertise(Mdns::OperationalAdvertisingParameters() .SetFabricId(kTestFabricId) .SetNodeId(chip::kTestDeviceNodeId) .SetPort(CHIP_PORT) @@ -161,17 +175,6 @@ void InitServer(AppDelegate * delegate) ); SuccessOrExit(err); } - else - { - RendezvousParameters params; - uint32_t pinCode; - - SuccessOrExit(err = DeviceLayer::ConfigurationMgr().GetSetupPinCode(pinCode)); - params.SetSetupPINCode(pinCode) - .SetBleLayer(DeviceLayer::ConnectivityMgr().GetBleLayer()) - .SetPeerAddress(Transport::PeerAddress::BLE()); - SuccessOrExit(err = gRendezvousServer.Init(params, &gTransports)); - } err = Mdns::ServiceAdvertiser::Instance().Start(&DeviceLayer::InetLayer, chip::Mdns::kMdnsPort); SuccessOrExit(err); diff --git a/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp b/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp index d782885563911b..c4b25adb80ec31 100644 --- a/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp +++ b/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp @@ -27,6 +27,7 @@ #include #include #include +#include namespace chip { namespace Mdns { @@ -199,7 +200,11 @@ CHIP_ERROR AdvertiserMinMdns::Start(chip::Inet::InetLayer * inetLayer, uint16_t mServer.Shutdown(); AllInterfaces allInterfaces; - return mServer.Listen(inetLayer, &allInterfaces, port); + + ReturnErrorOnFailure(mServer.Listen(inetLayer, &allInterfaces, port)); + + ChipLogProgress(Discovery, "CHIP minimal mDNS started advertising."); + return CHIP_NO_ERROR; } CHIP_ERROR AdvertiserMinMdns::Advertise(const OperationalAdvertisingParameters & params) @@ -235,6 +240,8 @@ CHIP_ERROR AdvertiserMinMdns::Advertise(const OperationalAdvertisingParameters & } } + ChipLogProgress(Discovery, "CHIP minimal mDNS configured as 'Operational device'."); + return CHIP_NO_ERROR; } From cb54ed0e7ab19c5e5f9985664626add0d4c5bea4 Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Tue, 8 Dec 2020 13:59:28 -0500 Subject: [PATCH 06/19] Register delegates, add some logging, fix PTR records --- examples/common/chip-app-server/Server.cpp | 4 ++-- src/lib/mdns/Advertiser_ImplMinimalMdns.cpp | 21 +++++++++++++++++---- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/examples/common/chip-app-server/Server.cpp b/examples/common/chip-app-server/Server.cpp index 853906c0abe02b..62e5337d159948 100644 --- a/examples/common/chip-app-server/Server.cpp +++ b/examples/common/chip-app-server/Server.cpp @@ -162,10 +162,10 @@ void InitServer(AppDelegate * delegate) // TODO: advertise this only when really operational once we support both // operational and commisioning advertising is supported. { - constexpr uint64_t kTestFabricId = 12344321; + constexpr uint64_t kTestFabricId = 5544332211; err = Mdns::ServiceAdvertiser::Instance().Advertise(Mdns::OperationalAdvertisingParameters() .SetFabricId(kTestFabricId) - .SetNodeId(chip::kTestDeviceNodeId) + .SetNodeId(chip::kTestDev iceNodeId) .SetPort(CHIP_PORT) #if INET_CONFIG_ENABLE_IPV4 .EnableIpV4(true) diff --git a/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp b/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp index c4b25adb80ec31..2a2d6e93694d40 100644 --- a/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp +++ b/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp @@ -125,12 +125,14 @@ class AdvertiserMinMdns : public ServiceAdvertiser, { public: AdvertiserMinMdns() : - mResponseSender(&mServer, &mQueryResponder), mPtrResponder(mServerQName, mOperationalServiceQName), + mResponseSender(&mServer, &mQueryResponder), mPtrResponder(mOperationalServiceQName, mOperationalServerQName), mSrvResponder(mOperationalServiceQName, mdns::Minimal::SrvResourceRecord(mOperationalServiceQName, mServerQName, CHIP_PORT)), mIPv4Responder(mServerQName), mIPv6Responder(mServerQName) - {} + { + mServer.SetDelegate(this); + } // Service advertiser CHIP_ERROR Start(chip::Inet::InetLayer * inetLayer, uint16_t port) override; @@ -160,8 +162,9 @@ class AdvertiserMinMdns : public ServiceAdvertiser, /// data members for variable things char mServerName[64] = ""; + mdns::Minimal::QNamePart mOperationalServiceQName[3] = { "_chip", "_tcp", "local" }; + mdns::Minimal::QNamePart mOperationalServerQName[4] = { mServerName, "_chip", "_tcp", "local" }; mdns::Minimal::QNamePart mServerQName[2] = { mServerName, "local" }; - mdns::Minimal::QNamePart mOperationalServiceQName[4] = { mServerName, "_chip", "_tcp", "local" }; /// responders mdns::Minimal::PtrResponder mPtrResponder; @@ -172,6 +175,8 @@ class AdvertiserMinMdns : public ServiceAdvertiser, void AdvertiserMinMdns::OnQuery(const mdns::Minimal::BytesRange & data, const chip::Inet::IPPacketInfo * info) { + ChipLogDetail(Discovery, "MinMdns received a query."); + mCurrentSource = info; if (!mdns::Minimal::ParsePacket(data, this)) { @@ -217,9 +222,17 @@ CHIP_ERROR AdvertiserMinMdns::Advertise(const OperationalAdvertisingParameters & { return CHIP_ERROR_NO_MEMORY; } + if (!mQueryResponder.AddResponder(&mPtrResponder) + .SetReportAdditional(mOperationalServerQName) + .SetReportInServiceListing(true) + .IsValid()) + { + ChipLogError(Discovery, "Failed to add service PTR record mDNS responder"); + return CHIP_ERROR_NO_MEMORY; + } mSrvResponder.SetRecord(mdns::Minimal::SrvResourceRecord(mOperationalServiceQName, mServerQName, params.GetPort())); - if (!mQueryResponder.AddResponder(&mSrvResponder).SetReportInServiceListing(true).IsValid()) + if (!mQueryResponder.AddResponder(&mSrvResponder).SetReportAdditional(mOperationalServerQName).IsValid()) { ChipLogError(Discovery, "Failed to add SRV record mDNS responder"); return CHIP_ERROR_NO_MEMORY; From ab9472d69552ebd7ef17f456ce939028b743caea Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Tue, 8 Dec 2020 14:00:01 -0500 Subject: [PATCH 07/19] Remove errand space --- examples/common/chip-app-server/Server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/common/chip-app-server/Server.cpp b/examples/common/chip-app-server/Server.cpp index 62e5337d159948..b33e7223f340e4 100644 --- a/examples/common/chip-app-server/Server.cpp +++ b/examples/common/chip-app-server/Server.cpp @@ -165,7 +165,7 @@ void InitServer(AppDelegate * delegate) constexpr uint64_t kTestFabricId = 5544332211; err = Mdns::ServiceAdvertiser::Instance().Advertise(Mdns::OperationalAdvertisingParameters() .SetFabricId(kTestFabricId) - .SetNodeId(chip::kTestDev iceNodeId) + .SetNodeId(chip::kTestDeviceNodeId) .SetPort(CHIP_PORT) #if INET_CONFIG_ENABLE_IPV4 .EnableIpV4(true) From 22123ae281d02641a3952c955ab26753617df412 Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Tue, 8 Dec 2020 14:11:35 -0500 Subject: [PATCH 08/19] Fix crash in ESP code on broadcast --- src/lib/mdns/minimal/Server.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/lib/mdns/minimal/Server.cpp b/src/lib/mdns/minimal/Server.cpp index 453a3f1510da03..b725ac41377097 100644 --- a/src/lib/mdns/minimal/Server.cpp +++ b/src/lib/mdns/minimal/Server.cpp @@ -61,6 +61,26 @@ class ShutdownOnError ServerBase * mServer; }; +chip::System::PacketBufferHandle Clone(chip::System::PacketBufferHandle & original) +{ + chip::System::PacketBufferHandle other = chip::System::PacketBuffer::New(); + if (other.IsNull()) + { + return other; + } + + if (other->AvailableDataLength() < original->DataLength()) + { + other.Adopt(nullptr); + return other; + } + + memcpy(other->Start(), original->Start(), original->DataLength()); + other->SetDataLength(original->DataLength()); + + return other; +} + } // namespace ServerBase::~ServerBase() @@ -173,7 +193,7 @@ CHIP_ERROR ServerBase::BroadcastSend(chip::System::PacketBufferHandle && data, u } // data may be sent over multiple packets. Keep the one ref active all the time - chip::System::PacketBufferHandle extraCopy = data.Retain(); + chip::System::PacketBufferHandle extraCopy = Clone(data); CHIP_ERROR err; From 6996da85b6e3a5c4ff9760574d89f3d3093abdf3 Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Tue, 8 Dec 2020 14:56:02 -0500 Subject: [PATCH 09/19] Fix return value: ref return does not work well --- src/lib/mdns/minimal/ResponseBuilder.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/mdns/minimal/ResponseBuilder.h b/src/lib/mdns/minimal/ResponseBuilder.h index e583b703e9d862..cfa563c3bcb847 100644 --- a/src/lib/mdns/minimal/ResponseBuilder.h +++ b/src/lib/mdns/minimal/ResponseBuilder.h @@ -53,7 +53,7 @@ class ResponseBuilder } CHECK_RETURN_VALUE - chip::System::PacketBufferHandle && ReleasePacket() + chip::System::PacketBufferHandle ReleasePacket() { mHeader = HeaderRef(nullptr); mBuildOk = false; From 91b6dca32ab57db79b9b4b4d5e7635ff01914dc4 Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Tue, 8 Dec 2020 15:47:32 -0500 Subject: [PATCH 10/19] Update logging verbosity on ESP32: chip already configures its logging, so mark esp verbosity to verbose --- src/lib/mdns/Advertiser_ImplMinimalMdns.cpp | 2 +- src/platform/ESP32/Logging.cpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp b/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp index 2a2d6e93694d40..cac0339e8c6cc9 100644 --- a/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp +++ b/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp @@ -232,7 +232,7 @@ CHIP_ERROR AdvertiserMinMdns::Advertise(const OperationalAdvertisingParameters & } mSrvResponder.SetRecord(mdns::Minimal::SrvResourceRecord(mOperationalServiceQName, mServerQName, params.GetPort())); - if (!mQueryResponder.AddResponder(&mSrvResponder).SetReportAdditional(mOperationalServerQName).IsValid()) + if (!mQueryResponder.AddResponder(&mSrvResponder).SetReportAdditional(mServerQName).IsValid()) { ChipLogError(Discovery, "Failed to add SRV record mDNS responder"); return CHIP_ERROR_NO_MEMORY; diff --git a/src/platform/ESP32/Logging.cpp b/src/platform/ESP32/Logging.cpp index e05be9eacca4e2..b3e02f51e80f1e 100644 --- a/src/platform/ESP32/Logging.cpp +++ b/src/platform/ESP32/Logging.cpp @@ -27,6 +27,11 @@ #include +#ifdef LOG_LOCAL_LEVEL +#undef LOG_LOCAL_LEVEL +#endif +#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE + #include "esp_log.h" using namespace ::chip; From b4d08112bd84d5277a791f84cfcc6f85bc74ea1e Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Tue, 8 Dec 2020 15:52:06 -0500 Subject: [PATCH 11/19] hex format server name --- src/lib/mdns/Advertiser_ImplMinimalMdns.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp b/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp index cac0339e8c6cc9..5144ffd82783b4 100644 --- a/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp +++ b/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp @@ -217,7 +217,7 @@ CHIP_ERROR AdvertiserMinMdns::Advertise(const OperationalAdvertisingParameters & mQueryResponder.Init(); // start fresh /// need to set server name - size_t len = snprintf(mServerName, sizeof(mServerName), "%" PRIu64 "-%" PRIu64, params.GetFabricId(), params.GetNodeId()); + size_t len = snprintf(mServerName, sizeof(mServerName), "%" PRIX64 "-%" PRIX64, params.GetFabricId(), params.GetNodeId()); if (len >= sizeof(mServerName)) { return CHIP_ERROR_NO_MEMORY; From 1568e4dabc3e374eedc9d9f211a0a98636e301e6 Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Tue, 8 Dec 2020 16:08:33 -0500 Subject: [PATCH 12/19] Better logging, fix server discovery --- src/lib/mdns/Advertiser_ImplMinimalMdns.cpp | 82 ++++++++++++++++++++- 1 file changed, 80 insertions(+), 2 deletions(-) diff --git a/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp b/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp index 5144ffd82783b4..b68033d4cebfe8 100644 --- a/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp +++ b/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp @@ -33,6 +33,83 @@ namespace chip { namespace Mdns { namespace { +template +class StringBuilder +{ +public: + const char * c_str() const { return mBuffer; } + + StringBuilder & Append(const char * s) + { + size_t available = kSize - mUsed; + size_t len = strlen(s); + + if (len > available) + { + len = available - 1; + } + memcpy(mBuffer + mUsed, s, len); + mUsed += len; + mBuffer[mUsed] = 0; + + return *this; + } + +private: + char mBuffer[kSize] = { 0 }; + size_t mUsed = 0; +}; + +void LogQuery(const mdns::Minimal::QueryData & data) +{ + StringBuilder<128> logString; + + logString.Append("QUERY "); + switch (data.GetClass()) + { + case mdns::Minimal::QClass::IN: + logString.Append("IN"); + break; + default: + logString.Append("???"); + break; + } + logString.Append("/"); + switch (data.GetType()) + { + case mdns::Minimal::QType::ANY: + logString.Append("ANY"); + break; + case mdns::Minimal::QType::A: + logString.Append("A"); + break; + case mdns::Minimal::QType::AAAA: + logString.Append("AAAA"); + break; + case mdns::Minimal::QType::TXT: + logString.Append("TXT"); + break; + case mdns::Minimal::QType::SRV: + logString.Append("SRV"); + break; + case mdns::Minimal::QType::PTR: + logString.Append("PTR"); + break; + default: + logString.Append("???"); + break; + } + logString.Append(": "); + + mdns::Minimal::SerializedQNameIterator name = data.GetName(); + while (name.Next()) + { + logString.Append(name.Value()).Append("."); + } + + ChipLogDetail(Discovery, "%s", logString.c_str()); +} + class AllInterfaces : public mdns::Minimal::ListenIterator { public: @@ -126,8 +203,7 @@ class AdvertiserMinMdns : public ServiceAdvertiser, public: AdvertiserMinMdns() : mResponseSender(&mServer, &mQueryResponder), mPtrResponder(mOperationalServiceQName, mOperationalServerQName), - mSrvResponder(mOperationalServiceQName, - mdns::Minimal::SrvResourceRecord(mOperationalServiceQName, mServerQName, CHIP_PORT)), + mSrvResponder(mOperationalServerQName, mdns::Minimal::SrvResourceRecord(mOperationalServiceQName, mServerQName, CHIP_PORT)), mIPv4Responder(mServerQName), mIPv6Responder(mServerQName) { @@ -193,6 +269,8 @@ void AdvertiserMinMdns::OnQuery(const mdns::Minimal::QueryData & data) return; } + LogQuery(data); + CHIP_ERROR err = mResponseSender.Respond(mMessageId, data, mCurrentSource); if (err != CHIP_NO_ERROR) { From 89d7583ff212f7594496cb23bbbead40e84608dd Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Tue, 8 Dec 2020 16:19:55 -0500 Subject: [PATCH 13/19] Update registration of names --- src/lib/mdns/Advertiser_ImplMinimalMdns.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp b/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp index b68033d4cebfe8..92cc2926fa5ee9 100644 --- a/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp +++ b/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp @@ -203,7 +203,7 @@ class AdvertiserMinMdns : public ServiceAdvertiser, public: AdvertiserMinMdns() : mResponseSender(&mServer, &mQueryResponder), mPtrResponder(mOperationalServiceQName, mOperationalServerQName), - mSrvResponder(mOperationalServerQName, mdns::Minimal::SrvResourceRecord(mOperationalServiceQName, mServerQName, CHIP_PORT)), + mSrvResponder(mOperationalServerQName, mdns::Minimal::SrvResourceRecord(mOperationalServerQName, mServerQName, CHIP_PORT)), mIPv4Responder(mServerQName), mIPv6Responder(mServerQName) { @@ -309,7 +309,7 @@ CHIP_ERROR AdvertiserMinMdns::Advertise(const OperationalAdvertisingParameters & return CHIP_ERROR_NO_MEMORY; } - mSrvResponder.SetRecord(mdns::Minimal::SrvResourceRecord(mOperationalServiceQName, mServerQName, params.GetPort())); + mSrvResponder.SetRecord(mdns::Minimal::SrvResourceRecord(mOperationalServerQName, mServerQName, params.GetPort())); if (!mQueryResponder.AddResponder(&mSrvResponder).SetReportAdditional(mServerQName).IsValid()) { ChipLogError(Discovery, "Failed to add SRV record mDNS responder"); From 6a09a5203541febb22e5e8d5c3643d4e722c963c Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Tue, 8 Dec 2020 16:32:00 -0500 Subject: [PATCH 14/19] Restyle fixes --- src/lib/mdns/Advertiser.h | 2 +- src/lib/mdns/Advertiser_ImplMinimalMdns.cpp | 14 +++++++++++++- src/lib/mdns/Advertiser_ImplNone.cpp | 2 +- src/lib/mdns/BUILD.gn | 4 ++-- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/lib/mdns/Advertiser.h b/src/lib/mdns/Advertiser.h index 51ee4fff602141..f9a7700cb3a887 100644 --- a/src/lib/mdns/Advertiser.h +++ b/src/lib/mdns/Advertiser.h @@ -85,4 +85,4 @@ class ServiceAdvertiser }; } // namespace Mdns -} // namespace chip \ No newline at end of file +} // namespace chip diff --git a/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp b/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp index 92cc2926fa5ee9..8a04df89387a49 100644 --- a/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp +++ b/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp @@ -204,7 +204,8 @@ class AdvertiserMinMdns : public ServiceAdvertiser, AdvertiserMinMdns() : mResponseSender(&mServer, &mQueryResponder), mPtrResponder(mOperationalServiceQName, mOperationalServerQName), mSrvResponder(mOperationalServerQName, mdns::Minimal::SrvResourceRecord(mOperationalServerQName, mServerQName, CHIP_PORT)), - mIPv4Responder(mServerQName), mIPv6Responder(mServerQName) + mIPv4Responder(mServerQName), mIPv6Responder(mServerQName), + mTxtResponder(mdns::Minimal::TxtResourceRecord(mOperationalServerQName, mEmptyTextEntries)) { mServer.SetDelegate(this); @@ -247,6 +248,11 @@ class AdvertiserMinMdns : public ServiceAdvertiser, mdns::Minimal::SrvResponder mSrvResponder; mdns::Minimal::IPv4Responder mIPv4Responder; mdns::Minimal::IPv6Responder mIPv6Responder; + mdns::Minimal::TxtResponder mTxtResponder; + + const char * mEmptyTextEntries[1] = { + "=", + }; }; void AdvertiserMinMdns::OnQuery(const mdns::Minimal::BytesRange & data, const chip::Inet::IPPacketInfo * info) @@ -316,6 +322,12 @@ CHIP_ERROR AdvertiserMinMdns::Advertise(const OperationalAdvertisingParameters & return CHIP_ERROR_NO_MEMORY; } + if (!mQueryResponder.AddResponder(&mTxtResponder).IsValid()) + { + ChipLogError(Discovery, "Failed to add TXT record mDNS responder"); + return CHIP_ERROR_NO_MEMORY; + } + if (!mQueryResponder.AddResponder(&mIPv6Responder).IsValid()) { ChipLogError(Discovery, "Failed to add IPv6 mDNS responder"); diff --git a/src/lib/mdns/Advertiser_ImplNone.cpp b/src/lib/mdns/Advertiser_ImplNone.cpp index 467a94b1c4e633..eec877770b89b1 100644 --- a/src/lib/mdns/Advertiser_ImplNone.cpp +++ b/src/lib/mdns/Advertiser_ImplNone.cpp @@ -49,4 +49,4 @@ ServiceAdvertiser & ServiceAdvertiser::Instance() } } // namespace Mdns -} // namespace chip \ No newline at end of file +} // namespace chip diff --git a/src/lib/mdns/BUILD.gn b/src/lib/mdns/BUILD.gn index affd4decf06212..69fdba410ad0ab 100644 --- a/src/lib/mdns/BUILD.gn +++ b/src/lib/mdns/BUILD.gn @@ -32,16 +32,16 @@ static_library("mdns") { ] sources = [ + "Advertiser.h", "DiscoveryManager.cpp", "DiscoveryManager.h", - "Advertiser.h" ] if (chip_mdns_avertiser == "none") { sources += [ "Advertiser_ImplNone.cpp" ] } else if (chip_mdns_avertiser == "minimal-mdns") { sources += [ "Advertiser_ImplMinimalMdns.cpp" ] - public_deps += ["${chip_root}/src/lib/mdns/minimal"] + public_deps += [ "${chip_root}/src/lib/mdns/minimal" ] } else { assert(false, "Unknown mDNS advertiser implementation.") } From dd48fe57b63dd4a170eb683469ba7049bd843705 Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Tue, 8 Dec 2020 16:43:46 -0500 Subject: [PATCH 15/19] Make ipv4 in minmdns optional --- src/lib/mdns/minimal/Server.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib/mdns/minimal/Server.cpp b/src/lib/mdns/minimal/Server.cpp index b725ac41377097..b556a58f04222d 100644 --- a/src/lib/mdns/minimal/Server.cpp +++ b/src/lib/mdns/minimal/Server.cpp @@ -201,10 +201,12 @@ CHIP_ERROR ServerBase::BroadcastSend(chip::System::PacketBufferHandle && data, u { err = info->udp->SendTo(kBroadcastIp.ipv6, port, info->udp->GetBoundInterface(), extraCopy.Release_ForNow()); } +#if INET_CONFIG_ENABLE_IPV4 else if (info->addressType == chip::Inet::kIPAddressType_IPv4) { err = info->udp->SendTo(kBroadcastIp.ipv4, port, info->udp->GetBoundInterface(), extraCopy.Release_ForNow()); } +#endif else { return CHIP_ERROR_INCORRECT_STATE; @@ -239,10 +241,12 @@ CHIP_ERROR ServerBase::BroadcastSend(chip::System::PacketBuffer * data, uint16_t { err = info->udp->SendTo(kBroadcastIp.ipv6, port, info->udp->GetBoundInterface(), data); } +#if INET_CONFIG_ENABLE_IPV4 else if (info->addressType == chip::Inet::kIPAddressType_IPv4) { err = info->udp->SendTo(kBroadcastIp.ipv4, port, info->udp->GetBoundInterface(), data); } +#endif else { // remove extra ref and then also clear it From cd683413c7294dca67c3827268b8a0eecee90ab1 Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Tue, 8 Dec 2020 16:53:30 -0500 Subject: [PATCH 16/19] Fix logic error in interface lister --- examples/minimal-mdns/AllInterfaceListener.h | 2 +- src/lib/mdns/Advertiser_ImplMinimalMdns.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/minimal-mdns/AllInterfaceListener.h b/examples/minimal-mdns/AllInterfaceListener.h index fa87c3889a0b07..844305ee0b2c17 100644 --- a/examples/minimal-mdns/AllInterfaceListener.h +++ b/examples/minimal-mdns/AllInterfaceListener.h @@ -95,7 +95,7 @@ class AllInterfaces : public mdns::Minimal::ListenIterator return true; // not a usable interface } char name[64]; - if (!mIterator.GetInterfaceName(name, sizeof(name)) == CHIP_NO_ERROR) + if (mIterator.GetInterfaceName(name, sizeof(name)) != CHIP_NO_ERROR) { printf("!!!! FAILED TO GET INTERFACE NAME\n"); return true; diff --git a/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp b/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp index 8a04df89387a49..9f17dafd02fba7 100644 --- a/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp +++ b/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp @@ -181,7 +181,7 @@ class AllInterfaces : public mdns::Minimal::ListenIterator return true; // not a usable interface } char name[64]; - if (!mIterator.GetInterfaceName(name, sizeof(name)) == CHIP_NO_ERROR) + if (mIterator.GetInterfaceName(name, sizeof(name)) != CHIP_NO_ERROR) { ChipLogError(Discovery, "Interface iterator failed to get interface name."); return true; From 43b6bc8c5f8925e6dd35176608a5c3d754a61ef7 Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Wed, 9 Dec 2020 11:09:25 -0500 Subject: [PATCH 17/19] Move Clone into SystemPacketBuffer. Clean up a bit of handle usage in mdns --- examples/minimal-mdns/client.cpp | 2 +- src/lib/mdns/minimal/Server.cpp | 53 ++++++++++--------------------- src/lib/mdns/minimal/Server.h | 4 +-- src/system/SystemPacketBuffer.cpp | 26 +++++++++++++++ src/system/SystemPacketBuffer.h | 9 ++++++ 5 files changed, 54 insertions(+), 40 deletions(-) diff --git a/examples/minimal-mdns/client.cpp b/examples/minimal-mdns/client.cpp index e9ffd1409111f1..a200a1a3e78ca8 100644 --- a/examples/minimal-mdns/client.cpp +++ b/examples/minimal-mdns/client.cpp @@ -277,7 +277,7 @@ void BroadcastPacket(mdns::Minimal::ServerBase * server) return; } - if (server->BroadcastSend(buffer.Release_ForNow(), gOptions.querySendPort) != CHIP_NO_ERROR) + if (server->BroadcastSend(std::move(buffer), gOptions.querySendPort) != CHIP_NO_ERROR) { printf("Error sending\n"); return; diff --git a/src/lib/mdns/minimal/Server.cpp b/src/lib/mdns/minimal/Server.cpp index b556a58f04222d..026a8fe24496d2 100644 --- a/src/lib/mdns/minimal/Server.cpp +++ b/src/lib/mdns/minimal/Server.cpp @@ -61,26 +61,6 @@ class ShutdownOnError ServerBase * mServer; }; -chip::System::PacketBufferHandle Clone(chip::System::PacketBufferHandle & original) -{ - chip::System::PacketBufferHandle other = chip::System::PacketBuffer::New(); - if (other.IsNull()) - { - return other; - } - - if (other->AvailableDataLength() < original->DataLength()) - { - other.Adopt(nullptr); - return other; - } - - memcpy(other->Start(), original->Start(), original->DataLength()); - other->SetDataLength(original->DataLength()); - - return other; -} - } // namespace ServerBase::~ServerBase() @@ -176,7 +156,7 @@ CHIP_ERROR ServerBase::DirectSend(chip::System::PacketBufferHandle && data, cons return CHIP_ERROR_NOT_CONNECTED; } -CHIP_ERROR ServerBase::BroadcastSend(chip::System::PacketBufferHandle && data, uint16_t port, chip::Inet::InterfaceId interface) +CHIP_ERROR ServerBase::BroadcastSend(chip::System::PacketBufferHandle data, uint16_t port, chip::Inet::InterfaceId interface) { for (size_t i = 0; i < mEndpointCount; i++) { @@ -192,19 +172,21 @@ CHIP_ERROR ServerBase::BroadcastSend(chip::System::PacketBufferHandle && data, u continue; } - // data may be sent over multiple packets. Keep the one ref active all the time - chip::System::PacketBufferHandle extraCopy = Clone(data); - CHIP_ERROR err; + /// The same packet needs to be sent over potentially multiple interfaces. + /// LWIP does not like having a pbuf sent over serparate interfaces, hence we create a copy + /// TODO: this wastes one copy of the data and that could be optimized away + chip::System::PacketBufferHandle copy = data.Clone(); + if (info->addressType == chip::Inet::kIPAddressType_IPv6) { - err = info->udp->SendTo(kBroadcastIp.ipv6, port, info->udp->GetBoundInterface(), extraCopy.Release_ForNow()); + err = info->udp->SendTo(kBroadcastIp.ipv6, port, info->udp->GetBoundInterface(), copy.Release_ForNow()); } #if INET_CONFIG_ENABLE_IPV4 else if (info->addressType == chip::Inet::kIPAddressType_IPv4) { - err = info->udp->SendTo(kBroadcastIp.ipv4, port, info->udp->GetBoundInterface(), extraCopy.Release_ForNow()); + err = info->udp->SendTo(kBroadcastIp.ipv4, port, info->udp->GetBoundInterface(), copy.Release_ForNow()); } #endif else @@ -221,7 +203,7 @@ CHIP_ERROR ServerBase::BroadcastSend(chip::System::PacketBufferHandle && data, u return CHIP_NO_ERROR; } -CHIP_ERROR ServerBase::BroadcastSend(chip::System::PacketBuffer * data, uint16_t port) +CHIP_ERROR ServerBase::BroadcastSend(chip::System::PacketBufferHandle data, uint16_t port) { for (size_t i = 0; i < mEndpointCount; i++) { @@ -232,26 +214,25 @@ CHIP_ERROR ServerBase::BroadcastSend(chip::System::PacketBuffer * data, uint16_t continue; } - // data may be sent over multiple packets. Keep the one ref active all the time - data->AddRef(); - CHIP_ERROR err; + /// The same packet needs to be sent over potentially multiple interfaces. + /// LWIP does not like having a pbuf sent over serparate interfaces, hence we create a copy + /// TODO: this wastes one copy of the data and that could be optimized away + chip::System::PacketBufferHandle copy = data.Clone(); + if (info->addressType == chip::Inet::kIPAddressType_IPv6) { - err = info->udp->SendTo(kBroadcastIp.ipv6, port, info->udp->GetBoundInterface(), data); + err = info->udp->SendTo(kBroadcastIp.ipv6, port, info->udp->GetBoundInterface(), copy.Release_ForNow()); } #if INET_CONFIG_ENABLE_IPV4 else if (info->addressType == chip::Inet::kIPAddressType_IPv4) { - err = info->udp->SendTo(kBroadcastIp.ipv4, port, info->udp->GetBoundInterface(), data); + err = info->udp->SendTo(kBroadcastIp.ipv4, port, info->udp->GetBoundInterface(), copy.Release_ForNow()); } #endif else { - // remove extra ref and then also clear it - chip::System::PacketBuffer::Free(data); - chip::System::PacketBuffer::Free(data); return CHIP_ERROR_INCORRECT_STATE; } @@ -264,12 +245,10 @@ CHIP_ERROR ServerBase::BroadcastSend(chip::System::PacketBuffer * data, uint16_t } else if (err != CHIP_NO_ERROR) { - chip::System::PacketBuffer::Free(data); return err; } } - chip::System::PacketBuffer::Free(data); return CHIP_NO_ERROR; } diff --git a/src/lib/mdns/minimal/Server.h b/src/lib/mdns/minimal/Server.h index e5e1dd73e3f07e..e1e66ecce0ddb5 100644 --- a/src/lib/mdns/minimal/Server.h +++ b/src/lib/mdns/minimal/Server.h @@ -95,10 +95,10 @@ class ServerBase chip::Inet::InterfaceId interface); /// Send a specific packet broadcast to all interfaces - CHIP_ERROR BroadcastSend(chip::System::PacketBuffer * data, uint16_t port); + CHIP_ERROR BroadcastSend(chip::System::PacketBufferHandle data, uint16_t port); /// Send a specific packet broadcast to a specific interface - CHIP_ERROR BroadcastSend(chip::System::PacketBufferHandle && data, uint16_t port, chip::Inet::InterfaceId interface); + CHIP_ERROR BroadcastSend(chip::System::PacketBufferHandle data, uint16_t port, chip::Inet::InterfaceId interface); ServerBase & SetDelegate(ServerDelegate * d) { diff --git a/src/system/SystemPacketBuffer.cpp b/src/system/SystemPacketBuffer.cpp index dcc50ae701ee1a..f407419cba6c33 100644 --- a/src/system/SystemPacketBuffer.cpp +++ b/src/system/SystemPacketBuffer.cpp @@ -726,5 +726,31 @@ PacketBufferHandle PacketBufferHandle::PopHead() return PacketBufferHandle(head); } +PacketBufferHandle PacketBufferHandle::Clone() +{ + if (mBuffer->Next() != nullptr) + { + // We do not clone an entire chain. + return PacketBufferHandle(); + } + + PacketBufferHandle other = PacketBuffer::New(); + if (other.IsNull()) + { + return other; + } + + if (other->AvailableDataLength() < mBuffer->DataLength()) + { + other.Adopt(nullptr); + return other; + } + + memcpy(other->Start(), mBuffer->Start(), mBuffer->DataLength()); + other->SetDataLength(mBuffer->DataLength()); + + return other; +} + } // namespace System } // namespace chip diff --git a/src/system/SystemPacketBuffer.h b/src/system/SystemPacketBuffer.h index 32fc9d945c0501..84a34445035ac7 100644 --- a/src/system/SystemPacketBuffer.h +++ b/src/system/SystemPacketBuffer.h @@ -341,6 +341,15 @@ class DLL_EXPORT PacketBufferHandle mBuffer = PacketBuffer::FreeHead(mBuffer); } + /** + * Creates a copy of the data in this packet. + * + * Does NOT support chained buffers. + * + * @returns empty handle on allocation failure. + */ + PacketBufferHandle Clone(); + private: PacketBufferHandle(const PacketBufferHandle &) = delete; PacketBufferHandle & operator=(const PacketBufferHandle &) = delete; From 0f085523c38dd1a02311f18122f78432ee14fc61 Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Wed, 9 Dec 2020 12:03:02 -0500 Subject: [PATCH 18/19] Make stringbuilder a support class --- src/lib/mdns/Advertiser_ImplMinimalMdns.cpp | 79 ++++++----------- src/lib/support/StringBuilder.h | 86 ++++++++++++++++++ src/lib/support/tests/BUILD.gn | 1 + src/lib/support/tests/TestStringBuilder.cpp | 97 +++++++++++++++++++++ 4 files changed, 209 insertions(+), 54 deletions(-) create mode 100644 src/lib/support/StringBuilder.h create mode 100644 src/lib/support/tests/TestStringBuilder.cpp diff --git a/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp b/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp index 9f17dafd02fba7..87daa191ac3da0 100644 --- a/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp +++ b/src/lib/mdns/Advertiser_ImplMinimalMdns.cpp @@ -28,83 +28,54 @@ #include #include #include +#include namespace chip { namespace Mdns { namespace { -template -class StringBuilder +const char * ToString(mdns::Minimal::QClass qClass) { -public: - const char * c_str() const { return mBuffer; } - - StringBuilder & Append(const char * s) - { - size_t available = kSize - mUsed; - size_t len = strlen(s); - - if (len > available) - { - len = available - 1; - } - memcpy(mBuffer + mUsed, s, len); - mUsed += len; - mBuffer[mUsed] = 0; - - return *this; - } - -private: - char mBuffer[kSize] = { 0 }; - size_t mUsed = 0; -}; - -void LogQuery(const mdns::Minimal::QueryData & data) -{ - StringBuilder<128> logString; - - logString.Append("QUERY "); - switch (data.GetClass()) + switch (qClass) { case mdns::Minimal::QClass::IN: - logString.Append("IN"); - break; + return "IN"; default: - logString.Append("???"); - break; + return "???"; } - logString.Append("/"); - switch (data.GetType()) +} + +const char * ToString(mdns::Minimal::QType qType) +{ + switch (qType) { case mdns::Minimal::QType::ANY: - logString.Append("ANY"); - break; + return "ANY"; case mdns::Minimal::QType::A: - logString.Append("A"); - break; + return "A"; case mdns::Minimal::QType::AAAA: - logString.Append("AAAA"); - break; + return "AAAA"; case mdns::Minimal::QType::TXT: - logString.Append("TXT"); - break; + return "TXT"; case mdns::Minimal::QType::SRV: - logString.Append("SRV"); - break; + return "SRV"; case mdns::Minimal::QType::PTR: - logString.Append("PTR"); - break; + return "PTR"; default: - logString.Append("???"); - break; + return "???"; } - logString.Append(": "); +} + +void LogQuery(const mdns::Minimal::QueryData & data) +{ + StringBuilder<128> logString; + + logString.Add("QUERY ").Add(ToString(data.GetClass())).Add("/").Add(ToString(data.GetType())).Add(": "); mdns::Minimal::SerializedQNameIterator name = data.GetName(); while (name.Next()) { - logString.Append(name.Value()).Append("."); + logString.Add(name.Value()).Add("."); } ChipLogDetail(Discovery, "%s", logString.c_str()); diff --git a/src/lib/support/StringBuilder.h b/src/lib/support/StringBuilder.h new file mode 100644 index 00000000000000..b25bc946f68192 --- /dev/null +++ b/src/lib/support/StringBuilder.h @@ -0,0 +1,86 @@ +/* + * + * Copyright (c) 2020 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. + */ + +#pragma once + +#include + +#include "BufferWriter.h" + +namespace chip { + +/// Build a c-style string out of distinct parts +class StringBuilderBase +{ +public: + StringBuilderBase(char * buffer, size_t size) : mWriter(reinterpret_cast(buffer), size - 1) + { + nlASSERT(size > 0); + buffer[0] = 0; // make c-str work by default + } + + /// Append a null terminated string + StringBuilderBase & Add(const char * s) + { + mWriter.Put(s); + NullTerminate(); + return *this; + } + + /// Append an integer value + StringBuilderBase & Add(int value) + { + char buff[32]; + snprintf(buff, sizeof(buff), "%d", value); + buff[sizeof(buff) - 1] = 0; + return Add(buff); + } + + /// did all the values fit? + bool Fit() const { return mWriter.Fit(); } + + /// access the underlying value + const char * c_str() const { return reinterpret_cast(mWriter.Buffer()); } + +private: + Encoding::LittleEndian::BufferWriter mWriter; + + void NullTerminate() + { + if (mWriter.Fit()) + { + mWriter.Buffer()[mWriter.Needed()] = 0; + } + else + { + mWriter.Buffer()[mWriter.Size()] = 0; + } + } +}; + +/// a preallocated sized string builder +template +class StringBuilder : public StringBuilderBase +{ +public: + StringBuilder() : StringBuilderBase(mBuffer, kSize) {} + +private: + char mBuffer[kSize]; +}; + +} // namespace chip \ No newline at end of file diff --git a/src/lib/support/tests/BUILD.gn b/src/lib/support/tests/BUILD.gn index b644042e0e707b..3f31e469663220 100644 --- a/src/lib/support/tests/BUILD.gn +++ b/src/lib/support/tests/BUILD.gn @@ -32,6 +32,7 @@ chip_test_suite("tests") { "TestSafeInt.cpp", "TestScopedBuffer.cpp", "TestSerializableIntegerSet.cpp", + "TestStringBuilder.cpp", "TestTimeUtils.cpp", ] sources = [] diff --git a/src/lib/support/tests/TestStringBuilder.cpp b/src/lib/support/tests/TestStringBuilder.cpp new file mode 100644 index 00000000000000..afc97a87729fac --- /dev/null +++ b/src/lib/support/tests/TestStringBuilder.cpp @@ -0,0 +1,97 @@ +/* + * + * Copyright (c) 2020 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 + +namespace { + +using namespace chip; + +void TestStringBuilder(nlTestSuite * inSuite, void * inContext) +{ + + StringBuilder<64> builder; + + NL_TEST_ASSERT(inSuite, builder.Fit()); + NL_TEST_ASSERT(inSuite, strcmp(builder.c_str(), "") == 0); + + builder.Add("foo"); + NL_TEST_ASSERT(inSuite, builder.Fit()); + NL_TEST_ASSERT(inSuite, strcmp(builder.c_str(), "foo") == 0); + + builder.Add("bar"); + NL_TEST_ASSERT(inSuite, builder.Fit()); + NL_TEST_ASSERT(inSuite, strcmp(builder.c_str(), "foobar") == 0); +} + +void TestIntegerAppend(nlTestSuite * inSuite, void * inContext) +{ + + StringBuilder<64> builder; + + builder.Add("nr: ").Add(1234); + NL_TEST_ASSERT(inSuite, builder.Fit()); + NL_TEST_ASSERT(inSuite, strcmp(builder.c_str(), "nr: 1234") == 0); + + builder.Add(", ").Add(-22); + NL_TEST_ASSERT(inSuite, builder.Fit()); + NL_TEST_ASSERT(inSuite, strcmp(builder.c_str(), "nr: 1234, -22") == 0); +} + +void TestOverflow(nlTestSuite * inSuite, void * inContext) +{ + + { + StringBuilder<4> builder; + + builder.Add("foo"); + NL_TEST_ASSERT(inSuite, builder.Fit()); + NL_TEST_ASSERT(inSuite, strcmp(builder.c_str(), "foo") == 0); + + builder.Add("bar"); + NL_TEST_ASSERT(inSuite, !builder.Fit()); + NL_TEST_ASSERT(inSuite, strcmp(builder.c_str(), "foo") == 0); + } + + { + StringBuilder<7> builder; + + builder.Add("x: ").Add(12345); + NL_TEST_ASSERT(inSuite, !builder.Fit()); + NL_TEST_ASSERT(inSuite, strcmp(builder.c_str(), "x: 123") == 0); + } +} + +const nlTest sTests[] = { + NL_TEST_DEF("TestStringBuilder", TestStringBuilder), // + NL_TEST_DEF("TestIntegerAppend", TestIntegerAppend), // + NL_TEST_DEF("TestOverflow", TestOverflow), // + NL_TEST_SENTINEL() // +}; + +} // namespace + +int TestStringBuilder(void) +{ + nlTestSuite theSuite = { "StringBuilder", sTests, nullptr, nullptr }; + nlTestRunner(&theSuite, nullptr); + return nlTestRunnerStats(&theSuite); +} + +CHIP_REGISTER_TEST_SUITE(TestStringBuilder) \ No newline at end of file From 728690077373697f0022ebcc9e71d5c7ed40c77b Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Wed, 9 Dec 2020 17:03:15 +0000 Subject: [PATCH 19/19] Restyled by whitespace --- src/lib/support/StringBuilder.h | 2 +- src/lib/support/tests/TestStringBuilder.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/support/StringBuilder.h b/src/lib/support/StringBuilder.h index b25bc946f68192..bab9f2de5a300d 100644 --- a/src/lib/support/StringBuilder.h +++ b/src/lib/support/StringBuilder.h @@ -83,4 +83,4 @@ class StringBuilder : public StringBuilderBase char mBuffer[kSize]; }; -} // namespace chip \ No newline at end of file +} // namespace chip diff --git a/src/lib/support/tests/TestStringBuilder.cpp b/src/lib/support/tests/TestStringBuilder.cpp index afc97a87729fac..5fa0a95492f535 100644 --- a/src/lib/support/tests/TestStringBuilder.cpp +++ b/src/lib/support/tests/TestStringBuilder.cpp @@ -94,4 +94,4 @@ int TestStringBuilder(void) return nlTestRunnerStats(&theSuite); } -CHIP_REGISTER_TEST_SUITE(TestStringBuilder) \ No newline at end of file +CHIP_REGISTER_TEST_SUITE(TestStringBuilder)