From 1151148c171c625af004a69bbcfe4f857c32dabe Mon Sep 17 00:00:00 2001 From: Jiacheng Guo Date: Fri, 30 Oct 2020 04:14:16 +0800 Subject: [PATCH] Implement and publish mDNS on esp32 (#3452) * esp32 mdns impl * fix review comments * use format in spec --- .../esp32/main/wifi-echo.cpp | 7 + .../server/esp32/main/DeviceCallbacks.cpp | 10 +- .../server/esp32/main/EchoServer.cpp | 4 +- .../wifi-echo/server/esp32/main/Globals.cpp | 25 +++ .../esp32/main/RendezvousDeviceDelegate.cpp | 3 +- .../server/esp32/main/include/Globals.h | 31 ++++ .../wifi-echo/server/esp32/main/wifi-echo.cpp | 17 +- src/lib/BUILD.gn | 5 + src/lib/protocols/mdns/BUILD.gn | 32 ++++ src/lib/protocols/mdns/Publisher.cpp | 173 ++++++++++++++++++ src/lib/protocols/mdns/Publisher.h | 74 ++++++++ src/lib/protocols/mdns/{ => platform}/Mdns.h | 18 +- src/lib/support/logging/CHIPLogging.cpp | 1 + src/lib/support/logging/CHIPLogging.h | 1 + src/platform/BUILD.gn | 3 + src/platform/ESP32/MdnsImpl.cpp | 126 +++++++++++++ src/platform/Linux/MdnsImpl.cpp | 16 ++ src/platform/Linux/MdnsImpl.h | 3 +- src/platform/device.gni | 3 +- src/platform/tests/TestMdns.cpp | 2 +- 20 files changed, 531 insertions(+), 23 deletions(-) create mode 100644 examples/wifi-echo/server/esp32/main/Globals.cpp create mode 100644 examples/wifi-echo/server/esp32/main/include/Globals.h create mode 100644 src/lib/protocols/mdns/BUILD.gn create mode 100644 src/lib/protocols/mdns/Publisher.cpp create mode 100644 src/lib/protocols/mdns/Publisher.h rename src/lib/protocols/mdns/{ => platform}/Mdns.h (93%) create mode 100644 src/platform/ESP32/MdnsImpl.cpp diff --git a/examples/temperature-measurement-app/esp32/main/wifi-echo.cpp b/examples/temperature-measurement-app/esp32/main/wifi-echo.cpp index 8a75154682101e..be7dfea06f6e6e 100644 --- a/examples/temperature-measurement-app/esp32/main/wifi-echo.cpp +++ b/examples/temperature-measurement-app/esp32/main/wifi-echo.cpp @@ -55,6 +55,13 @@ const char * TAG = "wifi-echo-demo"; static DeviceCallbacks EchoCallbacks; RendezvousDeviceDelegate * rendezvousDelegate = nullptr; +namespace chip { +namespace DeviceLayer { +namespace Internal { +const uint64_t TestDeviceId = kLocalNodeId; // For chip::DeviceLayer::GetDeviceId +} // namespace Internal +} // namespace DeviceLayer +} // namespace chip namespace { diff --git a/examples/wifi-echo/server/esp32/main/DeviceCallbacks.cpp b/examples/wifi-echo/server/esp32/main/DeviceCallbacks.cpp index 391f2b5a4d6fcd..b7abd49c508c61 100644 --- a/examples/wifi-echo/server/esp32/main/DeviceCallbacks.cpp +++ b/examples/wifi-echo/server/esp32/main/DeviceCallbacks.cpp @@ -24,10 +24,13 @@ **/ #include "DeviceCallbacks.h" +#include "CHIPDeviceManager.h" +#include "Globals.h" #include "LEDWidget.h" #include "WiFiWidget.h" #include "esp_heap_caps.h" #include "esp_log.h" +#include #include extern "C" { @@ -41,11 +44,6 @@ using namespace ::chip::Inet; using namespace ::chip::System; using namespace ::chip::DeviceLayer; -// In wifi-echo.cpp -extern LEDWidget statusLED1; -extern LEDWidget statusLED2; -extern WiFiWidget wifiLED; - uint32_t identifyTimerCount; constexpr uint32_t kIdentifyTimerDelayMS = 250; @@ -96,6 +94,7 @@ void DeviceCallbacks::OnInternetConnectivityChange(const ChipDeviceEvent * event { ESP_LOGI(TAG, "Server ready at: %s:%d", event->InternetConnectivityChange.address, CHIP_PORT); wifiLED.Set(true); + publisher.StartPublishDevice(); } else if (event->InternetConnectivityChange.IPv4 == kConnectivity_Lost) { @@ -105,6 +104,7 @@ void DeviceCallbacks::OnInternetConnectivityChange(const ChipDeviceEvent * event if (event->InternetConnectivityChange.IPv6 == kConnectivity_Established) { ESP_LOGI(TAG, "IPv6 Server ready..."); + publisher.StartPublishDevice(); } else if (event->InternetConnectivityChange.IPv6 == kConnectivity_Lost) { diff --git a/examples/wifi-echo/server/esp32/main/EchoServer.cpp b/examples/wifi-echo/server/esp32/main/EchoServer.cpp index 1529f2b52b997a..24c61422054fab 100644 --- a/examples/wifi-echo/server/esp32/main/EchoServer.cpp +++ b/examples/wifi-echo/server/esp32/main/EchoServer.cpp @@ -46,6 +46,7 @@ #include #include "DataModelHandler.h" +#include "Globals.h" #include "LEDWidget.h" static const char * TAG = "echo_server"; @@ -54,9 +55,6 @@ using namespace ::chip; using namespace ::chip::Inet; using namespace ::chip::Transport; -extern const NodeId kLocalNodeId = 12344321; -extern LEDWidget statusLED1; // In wifi-echo.cpp - namespace { /** diff --git a/examples/wifi-echo/server/esp32/main/Globals.cpp b/examples/wifi-echo/server/esp32/main/Globals.cpp new file mode 100644 index 00000000000000..5f18629ac810a6 --- /dev/null +++ b/examples/wifi-echo/server/esp32/main/Globals.cpp @@ -0,0 +1,25 @@ +/* + * + * 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 "Globals.h" + +LEDWidget statusLED1; +LEDWidget statusLED2; +BluetoothWidget bluetoothLED; +WiFiWidget wifiLED; +chip::Protocols::Mdns::Publisher publisher; +const chip::NodeId kLocalNodeId = 12344321; diff --git a/examples/wifi-echo/server/esp32/main/RendezvousDeviceDelegate.cpp b/examples/wifi-echo/server/esp32/main/RendezvousDeviceDelegate.cpp index d50c8b6bdd64b5..5060b57595c12d 100644 --- a/examples/wifi-echo/server/esp32/main/RendezvousDeviceDelegate.cpp +++ b/examples/wifi-echo/server/esp32/main/RendezvousDeviceDelegate.cpp @@ -18,6 +18,7 @@ #include "RendezvousDeviceDelegate.h" #include "BluetoothWidget.h" +#include "Globals.h" #include "esp_log.h" #include #include @@ -29,8 +30,6 @@ using namespace ::chip; using namespace ::chip::Inet; using namespace ::chip::System; -extern BluetoothWidget bluetoothLED; -extern NodeId kLocalNodeId; extern void PairingComplete(SecurePairingSession * pairing); static const char * TAG = "rendezvous-devicedelegate"; diff --git a/examples/wifi-echo/server/esp32/main/include/Globals.h b/examples/wifi-echo/server/esp32/main/include/Globals.h new file mode 100644 index 00000000000000..3e781966e8fa40 --- /dev/null +++ b/examples/wifi-echo/server/esp32/main/include/Globals.h @@ -0,0 +1,31 @@ +/* + * + * 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 "BluetoothWidget.h" +#include "LEDWidget.h" +#include "WiFiWidget.h" +#include "lib/protocols/mdns/Publisher.h" +#include "transport/raw/MessageHeader.h" + +extern LEDWidget statusLED1; +extern LEDWidget statusLED2; +extern BluetoothWidget bluetoothLED; +extern WiFiWidget wifiLED; +extern chip::Protocols::Mdns::Publisher publisher; +extern const chip::NodeId kLocalNodeId; diff --git a/examples/wifi-echo/server/esp32/main/wifi-echo.cpp b/examples/wifi-echo/server/esp32/main/wifi-echo.cpp index 0456b2148d4531..2ac7767ee80690 100644 --- a/examples/wifi-echo/server/esp32/main/wifi-echo.cpp +++ b/examples/wifi-echo/server/esp32/main/wifi-echo.cpp @@ -21,6 +21,7 @@ #include "DataModelHandler.h" #include "DeviceCallbacks.h" #include "Display.h" +#include "Globals.h" #include "LEDWidget.h" #include "ListScreen.h" #include "QRCodeScreen.h" @@ -44,6 +45,7 @@ #include #include +#include #include #include #include @@ -83,11 +85,6 @@ extern void startServer(); // Used to indicate that an IP address has been added to the QRCode #define EXAMPLE_VENDOR_TAG_IP 1 -LEDWidget statusLED1; -LEDWidget statusLED2; -BluetoothWidget bluetoothLED; -WiFiWidget wifiLED; - extern void PairingComplete(SecurePairingSession * pairing); const char * TAG = "wifi-echo-demo"; @@ -95,6 +92,14 @@ const char * TAG = "wifi-echo-demo"; static DeviceCallbacks EchoCallbacks; RendezvousDeviceDelegate * rendezvousDelegate = nullptr; +namespace chip { +namespace DeviceLayer { +namespace Internal { +const uint64_t TestDeviceId = kLocalNodeId; // For chip::DeviceLayer::GetDeviceId +} // namespace Internal +} // namespace DeviceLayer +} // namespace chip + namespace { #if CONFIG_DEVICE_TYPE_M5STACK @@ -523,6 +528,8 @@ extern "C" void app_main() } SetupPretendDevices(); + publisher.Init(); + publisher.StopPublishDevice(); statusLED1.Init(STATUS_LED_GPIO_NUM); // Our second LED doesn't map to any physical LEDs so far, just to virtual diff --git a/src/lib/BUILD.gn b/src/lib/BUILD.gn index ab025e505cd12f..362a9754bf1788 100644 --- a/src/lib/BUILD.gn +++ b/src/lib/BUILD.gn @@ -13,6 +13,7 @@ # limitations under the License. import("//build_overrides/chip.gni") +import("${chip_root}/src/platform/device.gni") config("includes") { include_dirs = [ "." ] @@ -34,6 +35,10 @@ static_library("lib") { "${chip_root}/src/transport", ] + if (chip_enable_mdns) { + public_deps += [ "${chip_root}/src/lib/protocols/mdns" ] + } + cflags = [ "-Wconversion" ] output_name = "libCHIP" diff --git a/src/lib/protocols/mdns/BUILD.gn b/src/lib/protocols/mdns/BUILD.gn new file mode 100644 index 00000000000000..3785e68dc5b0e3 --- /dev/null +++ b/src/lib/protocols/mdns/BUILD.gn @@ -0,0 +1,32 @@ +# 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. + +import("//build_overrides/chip.gni") + +source_set("platform_header") { + sources = [ "platform/Mdns.h" ] +} + +static_library("mdns") { + public_deps = [ + ":platform_header", + "${chip_root}/src/lib/support", + "${chip_root}/src/platform", + ] + + sources = [ + "Publisher.cpp", + "Publisher.h", + ] +} diff --git a/src/lib/protocols/mdns/Publisher.cpp b/src/lib/protocols/mdns/Publisher.cpp new file mode 100644 index 00000000000000..69b57fc7f1331d --- /dev/null +++ b/src/lib/protocols/mdns/Publisher.cpp @@ -0,0 +1,173 @@ +/* + * + * 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 "Publisher.h" + +#include + +#include "lib/protocols/mdns/platform/Mdns.h" +#include "lib/support/logging/CHIPLogging.h" +#include "platform/CHIPDeviceBuildConfig.h" +#include "platform/CHIPDeviceLayer.h" +#include "support/CodeUtils.h" +#include "support/ErrorStr.h" +#include "support/RandUtils.h" + +namespace chip { +namespace Protocols { +namespace Mdns { + +CHIP_ERROR Publisher::Init() +{ + CHIP_ERROR error; + + mUnprovisionedInstanceName = GetRandU64(); + SuccessOrExit(error = ChipMdnsInit(HandleMdnsInit, HandleMdnsError, this)); + SuccessOrExit(error = SetupHostname()); +exit: + return error; +} + +void Publisher::HandleMdnsInit(void * context, CHIP_ERROR initError) +{ + Publisher * publisher = static_cast(context); + + if (initError == CHIP_NO_ERROR) + { + publisher->mInitialized = true; + } + else + { + ChipLogError(Discovery, "mDNS initialization failed with %s", chip::ErrorStr(initError)); + } +} + +void Publisher::HandleMdnsError(void * context, CHIP_ERROR initError) +{ + ChipLogError(Discovery, "mDNS error: %s", chip::ErrorStr(initError)); +} + +CHIP_ERROR Publisher::StartPublishDevice(chip::Inet::InterfaceId interface) +{ + CHIP_ERROR error; + + // TODO: after multi-admin is decided we may need to publish both _chipc._udp and _chip._tcp service + if (chip::DeviceLayer::ConfigurationMgr().IsFullyProvisioned() != mIsPublishingProvisionedDevice) + { + SuccessOrExit(error = StopPublishDevice()); + // Set hostname again in case the mac address changes when shifting from soft-AP to station + SuccessOrExit(error = SetupHostname()); + } + mIsPublishingProvisionedDevice = chip::DeviceLayer::ConfigurationMgr().IsFullyProvisioned(); + + if (mIsPublishingProvisionedDevice) + { + error = PublishProvisionedDevice(interface); + } + else + { + error = PublishUnprovisionedDevice(interface); + } +exit: + return error; +} + +CHIP_ERROR Publisher::SetupHostname() +{ + uint8_t mac[6]; // 6 byte wifi mac + char hostname[13]; // Hostname will be the hex representation of mac. + CHIP_ERROR error; + + SuccessOrExit(error = chip::DeviceLayer::ConfigurationMgr().GetPrimaryWiFiMACAddress(mac)); + for (size_t i = 0; i < sizeof(mac); i++) + { + snprintf(&hostname[i * 2], sizeof(hostname) - i * 2, "%02X", mac[i]); + } + SuccessOrExit(error = ChipMdnsSetHostname(hostname)); + +exit: + return error; +} + +CHIP_ERROR Publisher::PublishUnprovisionedDevice(chip::Inet::InterfaceId interface) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + MdnsService service; + uint16_t discriminator; + uint16_t vendorID; + uint16_t productID; + char discriminatorBuf[5]; // hex representation of 16-bit discriminator + char vendorProductBuf[10]; // "FFFF+FFFF" + // TODO: The text entry will be updated in the spec, update accordingly. + TextEntry entries[2] = { + { "D", nullptr, 0 }, + { "VP", nullptr, 0 }, + }; + + VerifyOrExit(mInitialized, error = CHIP_ERROR_INCORRECT_STATE); + ChipLogProgress(Discovery, "setup mdns service"); + SuccessOrExit(error = chip::DeviceLayer::ConfigurationMgr().GetSetupDiscriminator(discriminator)); + snprintf(service.mName, sizeof(service.mName), "%016" PRIx64, mUnprovisionedInstanceName); + strncpy(service.mType, "_chipc", sizeof(service.mType)); + service.mProtocol = MdnsServiceProtocol::kMdnsProtocolUdp; + SuccessOrExit(error = chip::DeviceLayer::ConfigurationMgr().GetVendorId(vendorID)); + SuccessOrExit(error = chip::DeviceLayer::ConfigurationMgr().GetProductId(productID)); + snprintf(discriminatorBuf, sizeof(discriminatorBuf), "%04X", discriminator); + snprintf(vendorProductBuf, sizeof(vendorProductBuf), "%04X+%04X", vendorID, productID); + entries[0].mData = reinterpret_cast(discriminatorBuf); + entries[0].mDataSize = strnlen(discriminatorBuf, sizeof(discriminatorBuf)); + entries[1].mData = reinterpret_cast(vendorProductBuf); + entries[1].mDataSize = strnlen(discriminatorBuf, sizeof(vendorProductBuf)); + service.mTextEntryies = entries; + service.mTextEntrySize = sizeof(entries) / sizeof(TextEntry); + service.mPort = CHIP_PORT; + + error = ChipMdnsPublishService(&service); + +exit: + return error; +} + +CHIP_ERROR Publisher::PublishProvisionedDevice(chip::Inet::InterfaceId interface) +{ + uint64_t deviceId; + uint64_t fabricId; + MdnsService service; + CHIP_ERROR error = CHIP_NO_ERROR; + + // TODO: There may be multilple device/fabrid ids after multi-admin. + SuccessOrExit(error = chip::DeviceLayer::ConfigurationMgr().GetFabricId(fabricId)); + SuccessOrExit(error = chip::DeviceLayer::ConfigurationMgr().GetDeviceId(deviceId)); + snprintf(service.mName, sizeof(service.mName), "%" PRIX64 "-%" PRIX64, deviceId, fabricId); + strncpy(service.mType, "_chip", sizeof(service.mType)); + service.mProtocol = MdnsServiceProtocol::kMdnsProtocolTcp; + service.mPort = CHIP_PORT; + service.mTextEntryies = nullptr; + service.mTextEntrySize = 0; + error = ChipMdnsPublishService(&service); +exit: + return error; +} + +CHIP_ERROR Publisher::StopPublishDevice() +{ + return ChipMdnsStopPublish(); +} + +} // namespace Mdns +} // namespace Protocols +} // namespace chip diff --git a/src/lib/protocols/mdns/Publisher.h b/src/lib/protocols/mdns/Publisher.h new file mode 100644 index 00000000000000..af9cd530f2d45d --- /dev/null +++ b/src/lib/protocols/mdns/Publisher.h @@ -0,0 +1,74 @@ +/* + * + * 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 "core/CHIPError.h" +#include "inet/InetInterface.h" + +namespace chip { +namespace Protocols { +namespace Mdns { + +class Publisher +{ +public: + Publisher() = default; + + /** + * This method initializes the publisher. + * + */ + CHIP_ERROR Init(); + + /** + * This method publishes the device on mDNS. + * + * This function will fetch device name and other information and publish them + * via mDNS. If device meta data has changed, you can call this function again + * to update the information. + * + * @param[in] interface The interface to send mDNS multicast. + * + */ + CHIP_ERROR StartPublishDevice(chip::Inet::InterfaceId interface = INET_NULL_INTERFACEID); + + /** + * This function stops publishing the device on mDNS. + * + */ + CHIP_ERROR StopPublishDevice(); + +private: + Publisher(const Publisher &) = delete; + Publisher & operator=(const Publisher &) = delete; + + CHIP_ERROR PublishUnprovisionedDevice(chip::Inet::InterfaceId interface); + CHIP_ERROR PublishProvisionedDevice(chip::Inet::InterfaceId interface); + CHIP_ERROR SetupHostname(); + + static void HandleMdnsInit(void * context, CHIP_ERROR initError); + static void HandleMdnsError(void * context, CHIP_ERROR initError); + + uint64_t mUnprovisionedInstanceName; + bool mInitialized = false; + bool mIsPublishingProvisionedDevice = false; +}; + +} // namespace Mdns +} // namespace Protocols +} // namespace chip diff --git a/src/lib/protocols/mdns/Mdns.h b/src/lib/protocols/mdns/platform/Mdns.h similarity index 93% rename from src/lib/protocols/mdns/Mdns.h rename to src/lib/protocols/mdns/platform/Mdns.h index 6ec29c77148569..13533a87477cce 100644 --- a/src/lib/protocols/mdns/Mdns.h +++ b/src/lib/protocols/mdns/platform/Mdns.h @@ -36,7 +36,7 @@ namespace chip { namespace Protocols { namespace Mdns { -static constexpr uint8_t kMdnsNameMaxSize = 32; +static constexpr uint8_t kMdnsNameMaxSize = 33; static constexpr uint8_t kMdnsTypeMaxSize = 32; static constexpr uint16_t kMdnsTextMaxSize = 64; @@ -69,8 +69,8 @@ struct MdnsService /** * The callback function for mDNS resolve. * - * The callback function SHALL NOT take the ownership of the result->mService.mTextEntries - * memory. + * The callback function SHALL NOT take the ownership of the service pointer or + * any pointer inside this structure. * * @param[in] context The context passed to ChipMdnsBrowse or ChipMdnsResolve. * @param[in] result The mdns resolve result, can be nullptr if error happens. @@ -82,8 +82,8 @@ using MdnsResolveCallback = void (*)(void * context, MdnsService * result, CHIP_ /** * The callback function for mDNS browse. * - * The callback function SHALL NOT take the ownership of the service->mTextEntries - * memory. + * The callback function SHALL NOT take the ownership of the service pointer or + * any pointer inside this structure. * * @param[in] context The context passed to ChipMdnsBrowse or ChipMdnsResolve. * @param[in] services The service list, can be nullptr. @@ -108,6 +108,14 @@ using MdnsAsnycReturnCallback = void (*)(void * context, CHIP_ERROR error); */ CHIP_ERROR ChipMdnsInit(MdnsAsnycReturnCallback initCallback, MdnsAsnycReturnCallback errorCallback, void * context); +/** + * This function sets the host name for services. + * + * @param[in] hostname The hostname. + * + */ +CHIP_ERROR ChipMdnsSetHostname(const char * hostname); + /** * This function publishes an service via mDNS. * diff --git a/src/lib/support/logging/CHIPLogging.cpp b/src/lib/support/logging/CHIPLogging.cpp index 031f66ec638c15..a5f77e3cbdb20d 100644 --- a/src/lib/support/logging/CHIPLogging.cpp +++ b/src/lib/support/logging/CHIPLogging.cpp @@ -89,6 +89,7 @@ static const char ModuleNames[] = "-\0\0" // None "DL\0" // DeviceLayer "SPL" // SetupPayload "SVR" // AppServer + "DIS" // Discovery ; #define ModuleNamesCount ((sizeof(ModuleNames) - 1) / ChipLoggingModuleNameLen) diff --git a/src/lib/support/logging/CHIPLogging.h b/src/lib/support/logging/CHIPLogging.h index 7068c8561dc59d..75c8cac2fec70b 100644 --- a/src/lib/support/logging/CHIPLogging.h +++ b/src/lib/support/logging/CHIPLogging.h @@ -110,6 +110,7 @@ enum LogModule kLogModule_DeviceLayer, kLogModule_SetupPayload, kLogModule_AppServer, + kLogModule_Discovery, kLogModule_Max }; diff --git a/src/platform/BUILD.gn b/src/platform/BUILD.gn index 1ce9289dae3633..1f203b946041af 100644 --- a/src/platform/BUILD.gn +++ b/src/platform/BUILD.gn @@ -276,6 +276,7 @@ if (chip_device_platform != "none" && chip_device_platform != "external") { "ESP32/ESP32Utils.h", "ESP32/Logging.cpp", "ESP32/LwIPCoreLock.cpp", + "ESP32/MdnsImpl.cpp", "ESP32/NetworkProvisioningServerImpl.h", "ESP32/PlatformManagerImpl.cpp", "ESP32/PlatformManagerImpl.h", @@ -352,6 +353,8 @@ if (chip_device_platform != "none" && chip_device_platform != "external") { "Linux/MdnsImpl.h", ] + public_deps += [ "${chip_root}/src/lib/protocols/mdns:platform_header" ] + public_configs += [ ":avahi_client_config" ] } diff --git a/src/platform/ESP32/MdnsImpl.cpp b/src/platform/ESP32/MdnsImpl.cpp new file mode 100644 index 00000000000000..f2365df94885ad --- /dev/null +++ b/src/platform/ESP32/MdnsImpl.cpp @@ -0,0 +1,126 @@ +/* + * + * 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 "lib/protocols/mdns/platform/Mdns.h" + +#include +#include +#include +#include + +#include "platform/CHIPDeviceLayer.h" +#include "support/CHIPMem.h" +#include "support/CodeUtils.h" +#include "support/logging/CHIPLogging.h" + +namespace { + +static constexpr uint32_t kTimeoutMilli = 3000; +static constexpr size_t kMaxResults = 20; + +} // namespace + +namespace chip { +namespace Protocols { +namespace Mdns { + +CHIP_ERROR ChipMdnsInit(MdnsAsnycReturnCallback initCallback, MdnsAsnycReturnCallback errorCallback, void * context) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + esp_err_t espError; + + espError = mdns_init(); + VerifyOrExit(espError == ESP_OK, error = CHIP_ERROR_INTERNAL); + +exit: + if (espError != ESP_OK) + { + ChipLogError(DeviceLayer, "esp mdns internal error: %s", esp_err_to_name(espError)); + } + initCallback(context, error); + + return error; +} + +static const char * GetProtocolString(MdnsServiceProtocol protocol) +{ + return protocol == MdnsServiceProtocol::kMdnsProtocolTcp ? "_tcp" : "_udp"; +} + +CHIP_ERROR ChipMdnsSetHostname(const char * hostname) +{ + return mdns_hostname_set(hostname) == ESP_OK ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; +} + +CHIP_ERROR ChipMdnsPublishService(const MdnsService * service) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + mdns_txt_item_t * items = nullptr; + esp_err_t espError; + + VerifyOrExit(service->mTextEntrySize <= UINT8_MAX, error = CHIP_ERROR_INVALID_ARGUMENT); + if (service->mTextEntryies) + { + items = static_cast(chip::Platform::MemoryCalloc(service->mTextEntrySize, sizeof(mdns_txt_item_t))); + VerifyOrExit(items != nullptr, error = CHIP_ERROR_NO_MEMORY); + for (size_t i = 0; i < service->mTextEntrySize; i++) + { + items[i].key = service->mTextEntryies[i].mKey; + // Unfortunately ESP mdns stack doesn't support arbitrary binary data + items[i].value = reinterpret_cast(service->mTextEntryies[i].mData); + } + } + + espError = mdns_service_add(service->mName, service->mType, GetProtocolString(service->mProtocol), service->mPort, items, + service->mTextEntrySize); + // The mdns_service_add will return error if we try to add an existing service + if (espError != ESP_OK && espError != ESP_ERR_NO_MEM) + { + espError = mdns_service_txt_set(service->mType, GetProtocolString(service->mProtocol), items, + static_cast(service->mTextEntrySize)); + } + VerifyOrExit(espError == ESP_OK, error = CHIP_ERROR_INTERNAL); + +exit: + if (items != nullptr) + { + chip::Platform::MemoryFree(items); + } + + return error; +} + +CHIP_ERROR ChipMdnsStopPublish() +{ + return mdns_service_remove_all() == ESP_OK ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL; +} + +CHIP_ERROR ChipMdnsBrowse(const char * /*type*/, MdnsServiceProtocol /*protocol*/, chip::Inet::InterfaceId /*interface*/, + MdnsBrowseCallback /*callback*/, void * /*context*/) +{ + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +CHIP_ERROR ChipMdnsResolve(MdnsService * /*service*/, chip::Inet::InterfaceId /*interface*/, MdnsResolveCallback /*callback*/, + void * /*context*/) +{ + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +} // namespace Mdns +} // namespace Protocols +} // namespace chip diff --git a/src/platform/Linux/MdnsImpl.cpp b/src/platform/Linux/MdnsImpl.cpp index 0d0c144f2ac1c1..498fdff8a790d6 100644 --- a/src/platform/Linux/MdnsImpl.cpp +++ b/src/platform/Linux/MdnsImpl.cpp @@ -306,6 +306,17 @@ CHIP_ERROR MdnsAvahi::Init(MdnsAsnycReturnCallback initCallback, MdnsAsnycReturn return error; } +CHIP_ERROR MdnsAvahi::SetHostname(const char * hostname) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + + VerifyOrExit(mClient != nullptr, error = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(avahi_client_set_host_name(mClient, hostname) == 0, error = CHIP_ERROR_INTERNAL); + +exit: + return error; +} + void MdnsAvahi::HandleClientState(AvahiClient * client, AvahiClientState state, void * context) { static_cast(context)->HandleClientState(client, state); @@ -654,6 +665,11 @@ CHIP_ERROR ChipMdnsInit(MdnsAsnycReturnCallback initCallback, MdnsAsnycReturnCal return MdnsAvahi::GetInstance().Init(initCallback, errorCallback, context); } +CHIP_ERROR ChipMdnsSetHostname(const char * hostname) +{ + return MdnsAvahi::GetInstance().SetHostname(hostname); +} + CHIP_ERROR ChipMdnsPublishService(const MdnsService * service) { return MdnsAvahi::GetInstance().PublishService(*service); diff --git a/src/platform/Linux/MdnsImpl.h b/src/platform/Linux/MdnsImpl.h index fa36cc797fbf91..4311e4dd01115c 100644 --- a/src/platform/Linux/MdnsImpl.h +++ b/src/platform/Linux/MdnsImpl.h @@ -33,7 +33,7 @@ #include #include -#include "lib/protocols/mdns/Mdns.h" +#include "lib/protocols/mdns/platform/Mdns.h" struct AvahiWatch { @@ -102,6 +102,7 @@ class MdnsAvahi MdnsAvahi & operator=(const MdnsAvahi &) = delete; CHIP_ERROR Init(MdnsAsnycReturnCallback initCallback, MdnsAsnycReturnCallback errorCallback, void * context); + CHIP_ERROR SetHostname(const char * hostname); CHIP_ERROR PublishService(const MdnsService & service); CHIP_ERROR StopPublish(); CHIP_ERROR Browse(const char * type, MdnsServiceProtocol protocol, chip::Inet::InterfaceId interface, diff --git a/src/platform/device.gni b/src/platform/device.gni index 28e5702ace8f67..adfb781337908c 100644 --- a/src/platform/device.gni +++ b/src/platform/device.gni @@ -43,7 +43,8 @@ declare_args() { chip_enable_ble = chip_device_platform == "linux" || chip_device_platform == "darwin" - chip_enable_mdns = chip_device_platform == "linux" + chip_enable_mdns = + chip_device_platform == "linux" || chip_device_platform == "esp32" } _chip_device_layer = "none" diff --git a/src/platform/tests/TestMdns.cpp b/src/platform/tests/TestMdns.cpp index 5e710c9af07ab3..5bf57d8dbb067a 100644 --- a/src/platform/tests/TestMdns.cpp +++ b/src/platform/tests/TestMdns.cpp @@ -4,7 +4,7 @@ #include -#include "lib/protocols/mdns/Mdns.h" +#include "lib/protocols/mdns/platform/Mdns.h" #include "platform/CHIPDeviceLayer.h" #include "support/CHIPMem.h"