aboutsummaryrefslogtreecommitdiff
path: root/src/trel_dnssd
diff options
context:
space:
mode:
Diffstat (limited to 'src/trel_dnssd')
-rw-r--r--src/trel_dnssd/CMakeLists.txt37
-rw-r--r--src/trel_dnssd/trel_dnssd.cpp522
-rw-r--r--src/trel_dnssd/trel_dnssd.hpp196
3 files changed, 755 insertions, 0 deletions
diff --git a/src/trel_dnssd/CMakeLists.txt b/src/trel_dnssd/CMakeLists.txt
new file mode 100644
index 00000000..b0c4a93b
--- /dev/null
+++ b/src/trel_dnssd/CMakeLists.txt
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2021, The OpenThread Authors.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the copyright holder nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+add_library(otbr-trel-dnssd
+ trel_dnssd.cpp
+ trel_dnssd.hpp
+)
+
+target_link_libraries(otbr-trel-dnssd PRIVATE
+ $<$<BOOL:${OTBR_MDNS}>:otbr-mdns>
+ otbr-common
+)
diff --git a/src/trel_dnssd/trel_dnssd.cpp b/src/trel_dnssd/trel_dnssd.cpp
new file mode 100644
index 00000000..daeb3e9b
--- /dev/null
+++ b/src/trel_dnssd/trel_dnssd.cpp
@@ -0,0 +1,522 @@
+/*
+ * Copyright (c) 2021, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * This file includes implementation of TREL DNS-SD over mDNS.
+ */
+
+#if OTBR_ENABLE_TREL
+
+#define OTBR_LOG_TAG "TrelDns"
+
+#include "trel_dnssd/trel_dnssd.hpp"
+
+#include <inttypes.h>
+#include <net/if.h>
+
+#include <openthread/instance.h>
+#include <openthread/link.h>
+#include <openthread/platform/trel.h>
+
+#include "common/code_utils.hpp"
+#include "utils/hex.hpp"
+#include "utils/string_utils.hpp"
+
+static const char kTrelServiceName[] = "_trel._udp";
+
+static otbr::TrelDnssd::TrelDnssd *sTrelDnssd = nullptr;
+
+void trelDnssdInitialize(const char *aTrelNetif)
+{
+ sTrelDnssd->Initialize(aTrelNetif);
+}
+
+void trelDnssdStartBrowse(void)
+{
+ sTrelDnssd->StartBrowse();
+}
+
+void trelDnssdStopBrowse(void)
+{
+ sTrelDnssd->StopBrowse();
+}
+
+void trelDnssdRegisterService(uint16_t aPort, const uint8_t *aTxtData, uint8_t aTxtLength)
+{
+ sTrelDnssd->RegisterService(aPort, aTxtData, aTxtLength);
+}
+
+void trelDnssdRemoveService(void)
+{
+ sTrelDnssd->UnregisterService();
+}
+
+namespace otbr {
+
+namespace TrelDnssd {
+
+TrelDnssd::TrelDnssd(Ncp::ControllerOpenThread &aNcp, Mdns::Publisher &aPublisher)
+ : mPublisher(aPublisher)
+ , mNcp(aNcp)
+{
+ sTrelDnssd = this;
+}
+
+void TrelDnssd::Initialize(std::string aTrelNetif)
+{
+ mTrelNetif = std::move(aTrelNetif);
+
+ if (IsInitialized())
+ {
+ otbrLogDebug("Initialized on netif \"%s\"", mTrelNetif.c_str());
+ CheckTrelNetifReady();
+ }
+ else
+ {
+ otbrLogDebug("Not initialized");
+ }
+}
+
+void TrelDnssd::StartBrowse(void)
+{
+ VerifyOrExit(IsInitialized());
+
+ otbrLogDebug("Start browsing %s services ...", kTrelServiceName);
+
+ assert(mSubscriberId == 0);
+ mSubscriberId = mPublisher.AddSubscriptionCallbacks(
+ [this](const std::string &aType, const Mdns::Publisher::DiscoveredInstanceInfo &aInstanceInfo) {
+ OnTrelServiceInstanceResolved(aType, aInstanceInfo);
+ },
+ /* aHostCallback */ nullptr);
+
+ if (IsReady())
+ {
+ mPublisher.SubscribeService(kTrelServiceName, /* aInstanceName */ "");
+ }
+
+exit:
+ return;
+}
+
+void TrelDnssd::StopBrowse(void)
+{
+ VerifyOrExit(IsInitialized());
+
+ otbrLogDebug("Stop browsing %s service.", kTrelServiceName);
+ assert(mSubscriberId > 0);
+
+ mPublisher.RemoveSubscriptionCallbacks(mSubscriberId);
+ mSubscriberId = 0;
+
+ if (IsReady())
+ {
+ mPublisher.UnsubscribeService(kTrelServiceName, "");
+ }
+
+exit:
+ return;
+}
+
+void TrelDnssd::RegisterService(uint16_t aPort, const uint8_t *aTxtData, uint8_t aTxtLength)
+{
+ assert(aPort > 0);
+ assert(aTxtData != nullptr);
+
+ VerifyOrExit(IsInitialized());
+
+ otbrLogDebug("Register %s service: port=%u, TXT=%d bytes", kTrelServiceName, aPort, aTxtLength);
+ otbrDump(OTBR_LOG_DEBUG, OTBR_LOG_TAG, "TXT", aTxtData, aTxtLength);
+
+ if (mRegisterInfo.IsValid() && IsReady())
+ {
+ UnpublishTrelService();
+ }
+
+ mRegisterInfo.Assign(aPort, aTxtData, aTxtLength);
+
+ if (IsReady())
+ {
+ PublishTrelService();
+ }
+
+exit:
+ return;
+}
+
+void TrelDnssd::UnregisterService(void)
+{
+ VerifyOrExit(IsInitialized());
+
+ otbrLogDebug("Remove %s service", kTrelServiceName);
+ assert(mRegisterInfo.IsValid());
+
+ if (IsReady())
+ {
+ UnpublishTrelService();
+ }
+
+ mRegisterInfo.Clear();
+
+exit:
+ return;
+}
+
+void TrelDnssd::OnMdnsPublisherReady(void)
+{
+ VerifyOrExit(IsInitialized());
+
+ otbrLogDebug("mDNS Publisher is Ready");
+ mMdnsPublisherReady = true;
+ RemoveAllPeers();
+
+ if (mRegisterInfo.IsPublished())
+ {
+ mRegisterInfo.mInstanceName = "";
+ }
+
+ OnBecomeReady();
+
+exit:
+ return;
+}
+
+void TrelDnssd::OnTrelServiceInstanceResolved(const std::string & aType,
+ const Mdns::Publisher::DiscoveredInstanceInfo &aInstanceInfo)
+{
+ VerifyOrExit(StringUtils::EqualCaseInsensitive(aType, kTrelServiceName));
+ VerifyOrExit(aInstanceInfo.mNetifIndex == mTrelNetifIndex);
+
+ if (aInstanceInfo.mRemoved)
+ {
+ OnTrelServiceInstanceRemoved(aInstanceInfo.mName);
+ }
+ else
+ {
+ OnTrelServiceInstanceAdded(aInstanceInfo);
+ }
+
+exit:
+ return;
+}
+
+std::string TrelDnssd::GetTrelInstanceName(void)
+{
+ const otExtAddress *extaddr = otLinkGetExtendedAddress(mNcp.GetInstance());
+ std::string name;
+ char nameBuf[sizeof(otExtAddress) * 2 + 1];
+
+ Utils::Bytes2Hex(extaddr->m8, sizeof(otExtAddress), nameBuf);
+ name = StringUtils::ToLowercase(nameBuf);
+
+ assert(name.length() == sizeof(otExtAddress) * 2);
+
+ otbrLogDebug("Using instance name %s", name.c_str());
+ return name;
+}
+
+void TrelDnssd::PublishTrelService(void)
+{
+ assert(mRegisterInfo.IsValid());
+ assert(!mRegisterInfo.IsPublished());
+ assert(mTrelNetifIndex > 0);
+
+ mRegisterInfo.mInstanceName = GetTrelInstanceName();
+ mPublisher.PublishService(/* aHostName */ "", mRegisterInfo.mInstanceName, kTrelServiceName,
+ Mdns::Publisher::SubTypeList{}, mRegisterInfo.mPort, mRegisterInfo.mTxtEntries,
+ [](otbrError aError) { HandlePublishTrelServiceError(aError); });
+}
+
+void TrelDnssd::HandlePublishTrelServiceError(otbrError aError)
+{
+ if (aError != OTBR_ERROR_NONE)
+ {
+ otbrLogErr("Failed to publish TREL service: %s. TREL won't be working.", otbrErrorString(aError));
+ }
+}
+
+void TrelDnssd::UnpublishTrelService(void)
+{
+ assert(mRegisterInfo.IsValid());
+ assert(mRegisterInfo.IsPublished());
+
+ mPublisher.UnpublishService(mRegisterInfo.mInstanceName, kTrelServiceName,
+ [](otbrError aError) { HandleUnpublishTrelServiceError(aError); });
+ mRegisterInfo.mInstanceName = "";
+}
+
+void TrelDnssd::HandleUnpublishTrelServiceError(otbrError aError)
+{
+ if (aError != OTBR_ERROR_NONE)
+ {
+ otbrLogInfo("Failed to unpublish TREL service: %s", otbrErrorString(aError));
+ }
+}
+
+void TrelDnssd::OnTrelServiceInstanceAdded(const Mdns::Publisher::DiscoveredInstanceInfo &aInstanceInfo)
+{
+ std::string instanceName = StringUtils::ToLowercase(aInstanceInfo.mName);
+ otPlatTrelPeerInfo peerInfo;
+
+ // Remove any existing TREL service instance before adding
+ OnTrelServiceInstanceRemoved(instanceName);
+
+ otbrLogDebug("Peer discovered: %s hostname %s addresses %zu port %d priority %d "
+ "weight %d",
+ aInstanceInfo.mName.c_str(), aInstanceInfo.mHostName.c_str(), aInstanceInfo.mAddresses.size(),
+ aInstanceInfo.mPort, aInstanceInfo.mPriority, aInstanceInfo.mWeight);
+
+ for (const auto &addr : aInstanceInfo.mAddresses)
+ {
+ otbrLogDebug("Peer address: %s", addr.ToString().c_str());
+ }
+
+ if (aInstanceInfo.mAddresses.empty())
+ {
+ otbrLogWarning("Peer %s does not have any IPv6 address, ignored", aInstanceInfo.mName.c_str());
+ ExitNow();
+ }
+
+ peerInfo.mRemoved = false;
+ memcpy(&peerInfo.mSockAddr.mAddress, &aInstanceInfo.mAddresses[0], sizeof(peerInfo.mSockAddr.mAddress));
+ peerInfo.mSockAddr.mPort = aInstanceInfo.mPort;
+ peerInfo.mTxtData = aInstanceInfo.mTxtData.data();
+ peerInfo.mTxtLength = aInstanceInfo.mTxtData.size();
+
+ {
+ Peer peer(aInstanceInfo.mTxtData, peerInfo.mSockAddr);
+
+ VerifyOrExit(peer.mValid, otbrLogWarning("Peer %s is invalid", aInstanceInfo.mName.c_str()));
+
+ otPlatTrelHandleDiscoveredPeerInfo(mNcp.GetInstance(), &peerInfo);
+
+ mPeers.emplace(instanceName, peer);
+ CheckPeersNumLimit();
+ }
+
+exit:
+ return;
+}
+
+void TrelDnssd::OnTrelServiceInstanceRemoved(const std::string &aInstanceName)
+{
+ std::string instanceName = StringUtils::ToLowercase(aInstanceName);
+ auto it = mPeers.find(instanceName);
+
+ VerifyOrExit(it != mPeers.end());
+
+ otbrLogDebug("Peer removed: %s", instanceName.c_str());
+
+ // Remove the peer only when all instances are removed because one peer can have multiple instances if expired
+ // instances were not properly removed by mDNS.
+ if (CountDuplicatePeers(it->second) == 0)
+ {
+ NotifyRemovePeer(it->second);
+ }
+
+ mPeers.erase(it);
+
+exit:
+ return;
+}
+
+void TrelDnssd::CheckPeersNumLimit(void)
+{
+ const PeerMap::value_type *oldestPeer = nullptr;
+
+ VerifyOrExit(mPeers.size() >= kPeerCacheSize);
+
+ for (const auto &entry : mPeers)
+ {
+ if (oldestPeer == nullptr || entry.second.mDiscoverTime < oldestPeer->second.mDiscoverTime)
+ {
+ oldestPeer = &entry;
+ }
+ }
+
+ OnTrelServiceInstanceRemoved(oldestPeer->first);
+
+exit:
+ return;
+}
+
+void TrelDnssd::NotifyRemovePeer(const Peer &aPeer)
+{
+ otPlatTrelPeerInfo peerInfo;
+
+ peerInfo.mRemoved = true;
+ peerInfo.mTxtData = aPeer.mTxtData.data();
+ peerInfo.mTxtLength = aPeer.mTxtData.size();
+ peerInfo.mSockAddr = aPeer.mSockAddr;
+
+ otPlatTrelHandleDiscoveredPeerInfo(mNcp.GetInstance(), &peerInfo);
+}
+
+void TrelDnssd::RemoveAllPeers(void)
+{
+ for (const auto &entry : mPeers)
+ {
+ NotifyRemovePeer(entry.second);
+ }
+
+ mPeers.clear();
+}
+
+void TrelDnssd::CheckTrelNetifReady(void)
+{
+ assert(IsInitialized());
+
+ if (mTrelNetifIndex == 0)
+ {
+ mTrelNetifIndex = if_nametoindex(mTrelNetif.c_str());
+
+ if (mTrelNetifIndex != 0)
+ {
+ otbrLogDebug("Netif %s is ready: index = %" PRIu32, mTrelNetif.c_str(), mTrelNetifIndex);
+ OnBecomeReady();
+ }
+ else
+ {
+ uint16_t delay = kCheckNetifReadyIntervalMs;
+
+ otbrLogWarning("Netif %s is not ready (%s), will retry after %d seconds", mTrelNetif.c_str(),
+ strerror(errno), delay / 1000);
+ mTaskRunner.Post(Milliseconds(delay), [this]() { CheckTrelNetifReady(); });
+ }
+ }
+}
+
+bool TrelDnssd::IsReady(void) const
+{
+ assert(IsInitialized());
+
+ return mTrelNetifIndex > 0 && mMdnsPublisherReady;
+}
+
+void TrelDnssd::OnBecomeReady(void)
+{
+ if (IsReady())
+ {
+ otbrLogInfo("TREL DNS-SD Is Now Ready: Netif=%s(%" PRIu32 "), SubscriberId=%" PRIu64 ", Register=%s!",
+ mTrelNetif.c_str(), mTrelNetifIndex, mSubscriberId, mRegisterInfo.mInstanceName.c_str());
+
+ if (mSubscriberId > 0)
+ {
+ mPublisher.SubscribeService(kTrelServiceName, /* aInstanceName */ "");
+ }
+
+ if (mRegisterInfo.IsValid())
+ {
+ PublishTrelService();
+ }
+ }
+}
+
+uint16_t TrelDnssd::CountDuplicatePeers(const TrelDnssd::Peer &aPeer)
+{
+ uint16_t count = 0;
+
+ for (const auto &entry : mPeers)
+ {
+ if (&entry.second == &aPeer)
+ {
+ continue;
+ }
+
+ if (!memcmp(&entry.second.mSockAddr, &aPeer.mSockAddr, sizeof(otSockAddr)) &&
+ !memcmp(&entry.second.mExtAddr, &aPeer.mExtAddr, sizeof(otExtAddress)))
+ {
+ count++;
+ }
+ }
+
+ return count;
+}
+
+void TrelDnssd::RegisterInfo::Assign(uint16_t aPort, const uint8_t *aTxtData, uint8_t aTxtLength)
+{
+ otbrError error;
+
+ OTBR_UNUSED_VARIABLE(error);
+
+ assert(!IsPublished());
+ assert(aPort > 0);
+
+ mPort = aPort;
+ mTxtEntries.clear();
+
+ error = Mdns::Publisher::DecodeTxtData(mTxtEntries, aTxtData, aTxtLength);
+ assert(error == OTBR_ERROR_NONE);
+}
+
+void TrelDnssd::RegisterInfo::Clear(void)
+{
+ assert(!IsPublished());
+
+ mPort = 0;
+ mTxtEntries.clear();
+}
+
+const char TrelDnssd::Peer::kTxtRecordExtAddressKey[] = "xa";
+
+void TrelDnssd::Peer::ReadExtAddrFromTxtData(void)
+{
+ std::vector<Mdns::Publisher::TxtEntry> txtEntries;
+
+ memset(&mExtAddr, 0, sizeof(mExtAddr));
+
+ SuccessOrExit(Mdns::Publisher::DecodeTxtData(txtEntries, mTxtData.data(), mTxtData.size()));
+
+ for (const auto &txtEntry : txtEntries)
+ {
+ if (StringUtils::EqualCaseInsensitive(txtEntry.mName, kTxtRecordExtAddressKey))
+ {
+ VerifyOrExit(txtEntry.mValue.size() == sizeof(mExtAddr));
+
+ memcpy(mExtAddr.m8, txtEntry.mValue.data(), sizeof(mExtAddr));
+ mValid = true;
+ break;
+ }
+ }
+
+exit:
+
+ if (!mValid)
+ {
+ otbrLogInfo("Failed to dissect ExtAddr from peer TXT data");
+ }
+
+ return;
+}
+
+} // namespace TrelDnssd
+
+} // namespace otbr
+
+#endif // OTBR_ENABLE_TREL
diff --git a/src/trel_dnssd/trel_dnssd.hpp b/src/trel_dnssd/trel_dnssd.hpp
new file mode 100644
index 00000000..cf6564dc
--- /dev/null
+++ b/src/trel_dnssd/trel_dnssd.hpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2021, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * This file includes definitions for TREL DNS-SD over mDNS.
+ */
+
+#ifndef OTBR_AGENT_TREL_DNSSD_HPP_
+#define OTBR_AGENT_TREL_DNSSD_HPP_
+
+#if OTBR_ENABLE_TREL
+
+#include <assert.h>
+#include <utility>
+
+#include <openthread/instance.h>
+
+#include "common/types.hpp"
+#include "mdns/mdns.hpp"
+#include "ncp/ncp_openthread.hpp"
+
+namespace otbr {
+
+namespace TrelDnssd {
+
+/**
+ * @addtogroup border-router-trel-dnssd
+ *
+ * @brief
+ * This module includes definition for TREL DNS-SD over mDNS.
+ *
+ * @{
+ */
+
+class TrelDnssd
+{
+public:
+ /**
+ * This constructor initializes the TrelDnssd instance.
+ *
+ * @param[in] aNcp A reference to the OpenThread Controller instance.
+ * @param[in] aPublisher A reference to the mDNS Publisher.
+ *
+ */
+ explicit TrelDnssd(Ncp::ControllerOpenThread &aNcp, Mdns::Publisher &aPublisher);
+
+ /**
+ * This method initializes the TrelDnssd instance.
+ *
+ * @param[in] aTrelNetif The network interface for discovering TREL peers.
+ *
+ */
+ void Initialize(std::string aTrelNetif);
+
+ /**
+ * This method starts browsing for TREL peers.
+ *
+ */
+ void StartBrowse(void);
+
+ /**
+ * This method stops browsing for TREL peers.
+ *
+ */
+ void StopBrowse(void);
+
+ /**
+ * This method registers the TREL service to DNS-SD.
+ *
+ * @param[in] aPort The UDP port of TREL service.
+ * @param[in] aTxtData The TXT data of TREL service.
+ * @param[in] aTxtLength The TXT length of TREL service.
+ *
+ */
+ void RegisterService(uint16_t aPort, const uint8_t *aTxtData, uint8_t aTxtLength);
+
+ /**
+ * This method removes the TREL service from DNS-SD.
+ *
+ */
+ void UnregisterService(void);
+
+ /**
+ * This method notifies that mDNS Publisher is ready.
+ *
+ */
+ void OnMdnsPublisherReady(void);
+
+private:
+ static constexpr size_t kPeerCacheSize = 256;
+ static constexpr uint16_t kCheckNetifReadyIntervalMs = 5000;
+
+ struct RegisterInfo
+ {
+ uint16_t mPort = 0;
+ std::vector<Mdns::Publisher::TxtEntry> mTxtEntries;
+ std::string mInstanceName;
+
+ bool IsValid(void) const { return mPort > 0; }
+ bool IsPublished(void) const { return !mInstanceName.empty(); }
+ void Assign(uint16_t aPort, const uint8_t *aTxtData, uint8_t aTxtLength);
+ void Clear(void);
+ };
+
+ using Clock = std::chrono::system_clock;
+
+ struct Peer
+ {
+ static const char kTxtRecordExtAddressKey[];
+
+ explicit Peer(std::vector<uint8_t> aTxtData, const otSockAddr &aSockAddr)
+ : mDiscoverTime(Clock::now())
+ , mTxtData(std::move(aTxtData))
+ , mSockAddr(aSockAddr)
+ {
+ ReadExtAddrFromTxtData();
+ }
+
+ void ReadExtAddrFromTxtData(void);
+
+ Clock::time_point mDiscoverTime;
+ std::vector<uint8_t> mTxtData;
+ otSockAddr mSockAddr;
+ otExtAddress mExtAddr;
+ bool mValid = false;
+ };
+
+ using PeerMap = std::map<std::string, Peer>;
+
+ bool IsInitialized(void) const { return !mTrelNetif.empty(); }
+ bool IsReady(void) const;
+ void OnBecomeReady(void);
+ void CheckTrelNetifReady(void);
+ std::string GetTrelInstanceName(void);
+ void PublishTrelService(void);
+ void UnpublishTrelService(void);
+ static void HandlePublishTrelServiceError(otbrError aError);
+ static void HandleUnpublishTrelServiceError(otbrError aError);
+ void OnTrelServiceInstanceResolved(const std::string & aType,
+ const Mdns::Publisher::DiscoveredInstanceInfo &aInstanceInfo);
+ void OnTrelServiceInstanceAdded(const Mdns::Publisher::DiscoveredInstanceInfo &aInstanceInfo);
+ void OnTrelServiceInstanceRemoved(const std::string &aInstanceName);
+
+ void NotifyRemovePeer(const Peer &aPeer);
+ void CheckPeersNumLimit(void);
+ void RemoveAllPeers(void);
+ uint16_t CountDuplicatePeers(const Peer &aPeer);
+
+ Mdns::Publisher & mPublisher;
+ Ncp::ControllerOpenThread &mNcp;
+ TaskRunner mTaskRunner;
+ std::string mTrelNetif;
+ uint32_t mTrelNetifIndex = 0;
+ uint64_t mSubscriberId = 0;
+ RegisterInfo mRegisterInfo;
+ PeerMap mPeers;
+ bool mMdnsPublisherReady = false;
+};
+
+/**
+ * @}
+ */
+
+} // namespace TrelDnssd
+
+} // namespace otbr
+
+#endif // OTBR_ENABLE_TREL
+
+#endif // OTBR_AGENT_TREL_DNSSD_HPP_