From c50510142ee43ee0dec6d40322e957f76e4e8c87 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Fri, 1 Sep 2023 16:38:01 -0700 Subject: [PATCH] [mdns] update 'TxtEntry' to handle boolean attribute This commit updates `TxtEntry` along with `EncodeTxtData()` and `DecodeTxtData()` to support boolean attributes which are encode as `key` without `=`. It also updates `AdvertisingProxy::MakeTxtList()` to use the `DecodeTxtData()`. --- src/border_agent/border_agent.cpp | 7 ++--- src/mdns/mdns.cpp | 41 ++++++++++++++++++----------- src/mdns/mdns.hpp | 37 +++++++++++++++++++------- src/sdp_proxy/advertising_proxy.cpp | 10 +------ src/trel_dnssd/trel_dnssd.cpp | 7 ++++- 5 files changed, 64 insertions(+), 38 deletions(-) diff --git a/src/border_agent/border_agent.cpp b/src/border_agent/border_agent.cpp index 065421f7ebe..a1a30c0ef78 100644 --- a/src/border_agent/border_agent.cpp +++ b/src/border_agent/border_agent.cpp @@ -343,10 +343,11 @@ void AppendVendorTxtEntries(const std::map> &a for (auto &addedEntry : aTxtList) { - if (addedEntry.mName == key) + if (addedEntry.mKey == key) { - addedEntry.mValue = value; - found = true; + addedEntry.mValue = value; + addedEntry.mIsBooleanAttribute = false; + found = true; break; } } diff --git a/src/mdns/mdns.cpp b/src/mdns/mdns.cpp index c2c692c461b..8306270e77e 100644 --- a/src/mdns/mdns.cpp +++ b/src/mdns/mdns.cpp @@ -99,18 +99,25 @@ otbrError Publisher::EncodeTxtData(const TxtList &aTxtList, std::vector { otbrError error = OTBR_ERROR_NONE; - for (const auto &txtEntry : aTxtList) + for (const TxtEntry &txtEntry : aTxtList) { - const auto &name = txtEntry.mName; - const auto &value = txtEntry.mValue; - const size_t entryLength = name.length() + 1 + value.size(); + size_t entryLength = txtEntry.mKey.length(); + + if (!txtEntry.mIsBooleanAttribute) + { + entryLength += txtEntry.mValue.size() + sizeof(uint8_t); // for `=` char. + } VerifyOrExit(entryLength <= kMaxTextEntrySize, error = OTBR_ERROR_INVALID_ARGS); aTxtData.push_back(static_cast(entryLength)); - aTxtData.insert(aTxtData.end(), name.begin(), name.end()); - aTxtData.push_back('='); - aTxtData.insert(aTxtData.end(), value.begin(), value.end()); + aTxtData.insert(aTxtData.end(), txtEntry.mKey.begin(), txtEntry.mKey.end()); + + if (!txtEntry.mIsBooleanAttribute) + { + aTxtData.push_back('='); + aTxtData.insert(aTxtData.end(), txtEntry.mValue.begin(), txtEntry.mValue.end()); + } } exit: @@ -127,24 +134,28 @@ otbrError Publisher::DecodeTxtData(Publisher::TxtList &aTxtList, const uint8_t * uint16_t keyStart = r + 1; uint16_t entryEnd = keyStart + entrySize; uint16_t keyEnd = keyStart; - uint16_t valStart; + + VerifyOrExit(entryEnd <= aTxtLength, error = OTBR_ERROR_PARSE); while (keyEnd < entryEnd && aTxtData[keyEnd] != '=') { keyEnd++; } - valStart = keyEnd; - if (valStart < entryEnd && aTxtData[valStart] == '=') + if (keyEnd == entryEnd) { - valStart++; + // No `=`, treat as a boolean attribute. + aTxtList.emplace_back(reinterpret_cast(&aTxtData[keyStart]), keyEnd - keyStart); } + else + { + uint16_t valStart = keyEnd + 1; // To skip over `=` - aTxtList.emplace_back(reinterpret_cast(&aTxtData[keyStart]), keyEnd - keyStart, - &aTxtData[valStart], entryEnd - valStart); + aTxtList.emplace_back(reinterpret_cast(&aTxtData[keyStart]), keyEnd - keyStart, + &aTxtData[valStart], entryEnd - valStart); + } r += entrySize + 1; - VerifyOrExit(r <= aTxtLength, error = OTBR_ERROR_PARSE); } exit: @@ -260,7 +271,7 @@ Publisher::SubTypeList Publisher::SortSubTypeList(SubTypeList aSubTypeList) Publisher::TxtList Publisher::SortTxtList(TxtList aTxtList) { std::sort(aTxtList.begin(), aTxtList.end(), - [](const TxtEntry &aLhs, const TxtEntry &aRhs) { return aLhs.mName < aRhs.mName; }); + [](const TxtEntry &aLhs, const TxtEntry &aRhs) { return aLhs.mKey < aRhs.mKey; }); return aTxtList; } diff --git a/src/mdns/mdns.hpp b/src/mdns/mdns.hpp index 0159009d11b..21a3c8eaf75 100644 --- a/src/mdns/mdns.hpp +++ b/src/mdns/mdns.hpp @@ -70,31 +70,48 @@ class Publisher : private NonCopyable { public: /** - * This structure represents a name/value pair of the TXT record. + * This structure represents a key/value pair of the TXT record. * */ struct TxtEntry { - std::string mName; ///< The name of the TXT entry. - std::vector mValue; ///< The value of the TXT entry. + std::string mKey; ///< The key of the TXT entry. + std::vector mValue; ///< The value of the TXT entry. Can be empty. + bool mIsBooleanAttribute; ///< This entry is boolean attribute (encoded as `key` without `=`). - TxtEntry(const char *aName, const char *aValue) - : TxtEntry(aName, reinterpret_cast(aValue), strlen(aValue)) + TxtEntry(const char *aKey, const char *aValue) + : TxtEntry(aKey, reinterpret_cast(aValue), strlen(aValue)) { } - TxtEntry(const char *aName, const uint8_t *aValue, size_t aValueLength) - : TxtEntry(aName, strlen(aName), aValue, aValueLength) + TxtEntry(const char *aKey, const uint8_t *aValue, size_t aValueLength) + : TxtEntry(aKey, strlen(aKey), aValue, aValueLength) { } - TxtEntry(const char *aName, size_t aNameLength, const uint8_t *aValue, size_t aValueLength) - : mName(aName, aNameLength) + TxtEntry(const char *aKey, size_t aKeyLength, const uint8_t *aValue, size_t aValueLength) + : mKey(aKey, aKeyLength) , mValue(aValue, aValue + aValueLength) + , mIsBooleanAttribute(false) { } - bool operator==(const TxtEntry &aOther) const { return mName == aOther.mName && mValue == aOther.mValue; } + TxtEntry(const char *aKey) + : TxtEntry(aKey, strlen(aKey)) + { + } + + TxtEntry(const char *aKey, size_t aKeyLength) + : mKey(aKey, aKeyLength) + , mIsBooleanAttribute(true) + { + } + + bool operator==(const TxtEntry &aOther) const + { + return (mKey == aOther.mKey) && (mValue == aOther.mValue) && + (mIsBooleanAttribute == aOther.mIsBooleanAttribute); + } }; typedef std::vector TxtList; diff --git a/src/sdp_proxy/advertising_proxy.cpp b/src/sdp_proxy/advertising_proxy.cpp index 817786c0ede..9f6ce494ad5 100644 --- a/src/sdp_proxy/advertising_proxy.cpp +++ b/src/sdp_proxy/advertising_proxy.cpp @@ -342,18 +342,10 @@ Mdns::Publisher::TxtList AdvertisingProxy::MakeTxtList(const otSrpServerService { const uint8_t *txtData; uint16_t txtDataLength = 0; - otDnsTxtEntryIterator iterator; - otDnsTxtEntry txtEntry; Mdns::Publisher::TxtList txtList; txtData = otSrpServerServiceGetTxtData(aSrpService, &txtDataLength); - - otDnsInitTxtEntryIterator(&iterator, txtData, txtDataLength); - - while (otDnsGetNextTxtEntry(&iterator, &txtEntry) == OT_ERROR_NONE) - { - txtList.emplace_back(txtEntry.mKey, txtEntry.mValue, txtEntry.mValueLength); - } + Mdns::Publisher::DecodeTxtData(txtList, txtData, txtDataLength); return txtList; } diff --git a/src/trel_dnssd/trel_dnssd.cpp b/src/trel_dnssd/trel_dnssd.cpp index 11794fcb911..37ec8c5809b 100644 --- a/src/trel_dnssd/trel_dnssd.cpp +++ b/src/trel_dnssd/trel_dnssd.cpp @@ -495,7 +495,12 @@ void TrelDnssd::Peer::ReadExtAddrFromTxtData(void) for (const auto &txtEntry : txtEntries) { - if (StringUtils::EqualCaseInsensitive(txtEntry.mName, kTxtRecordExtAddressKey)) + if (txtEntry.mIsBooleanAttribute) + { + continue; + } + + if (StringUtils::EqualCaseInsensitive(txtEntry.mKey, kTxtRecordExtAddressKey)) { VerifyOrExit(txtEntry.mValue.size() == sizeof(mExtAddr));