From 1096b060e6a79536d846a489c0fefbf8d1e75e78 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Fri, 9 Oct 2026 22:35:44 -0700 Subject: [PATCH] [mdns] lazily discover `ServiceEntry` compression offsets and host (#13696) This commit replaces the upfront `DiscoverOffsetsAndHost()` call in `ServiceEntry::PrepareProbe()` and `ServiceEntry::PrepareResponseRecords()` with on-demand discovery helpers invoked only when the corresponding names or records are actually appended: - `DiscoverHost()` to find and cache the associated `HostEntry` in `mHostEntry` (cleared in `ClearAppendState()`) and sync host name compression offsets between `ServiceEntry` and `HostEntry`. - `DiscoverServiceTypeCompressOffset()`, `DiscoverSubServiceNameCompressOffsetFor()`, and `DiscoverHostNameCompressOffset()` (using a common `DiscoverCompressOffset()` helper) invoked from the respective `Append*To()` methods. This avoids unnecessary scans over `mHostEntries` and `mServiceEntries` when a `ServiceEntry` does not append records or only appends a subset of records. --- src/core/net/mdns.cpp | 199 +++++++++++++++++++++++++++--------------- src/core/net/mdns.hpp | 14 ++- 2 files changed, 139 insertions(+), 74 deletions(-) diff --git a/src/core/net/mdns.cpp b/src/core/net/mdns.cpp index 8b9023b39..fa406e1ea 100644 --- a/src/core/net/mdns.cpp +++ b/src/core/net/mdns.cpp @@ -2568,6 +2568,7 @@ Core::ServiceEntry::ServiceEntry(void) , mPriority(0) , mWeight(0) , mPort(0) + , mHostEntry(nullptr) , mIsAddedInServiceTypes(false) { } @@ -2894,6 +2895,7 @@ void Core::ServiceEntry::ClearAppendState(void) mServiceTypeOffset.Clear(); mSubServiceTypeOffset.Clear(); mHostNameOffset.Clear(); + mHostEntry = nullptr; for (SubType &subType : mSubTypes) { @@ -2908,12 +2910,8 @@ void Core::ServiceEntry::PrepareProbe(TxMessage &aProbe) do { - HostEntry *hostEntry = nullptr; - aProbe.SaveCurrentState(); - DiscoverOffsetsAndHost(hostEntry); - AppendServiceNameTo(aProbe, kQuestionSection); AppendQuestionTo(aProbe); @@ -2963,11 +2961,8 @@ void Core::ServiceEntry::PrepareResponseRecords(EntryContext &aContext) { bool appendNsec = false; bool appendAdditionalRecordsForPtr = false; - HostEntry *hostEntry = nullptr; TxMessage &response = aContext.mResponseMessage; - DiscoverOffsetsAndHost(hostEntry); - // We determine records to include in Additional Data section // per RFC 6763 section 12: // @@ -3010,11 +3005,7 @@ void Core::ServiceEntry::PrepareResponseRecords(EntryContext &aContext) { mSrvRecord.MarkToAppendInAdditionalData(); mTxtRecord.MarkToAppendInAdditionalData(); - - if (hostEntry != nullptr) - { - hostEntry->MarkToAppendAddrRecordsInAdditionalData(); - } + MarkToAppendHostAddrRecordsInAdditionalData(); } if (mSrvRecord.ShouldAppendTo(aContext)) @@ -3022,9 +3013,9 @@ void Core::ServiceEntry::PrepareResponseRecords(EntryContext &aContext) AppendSrvRecordTo(response, kAnswerSection); appendNsec = true; - if ((mSrvRecord.GetTtl() > 0) && (hostEntry != nullptr)) + if (mSrvRecord.GetTtl() > 0) { - hostEntry->MarkToAppendAddrRecordsInAdditionalData(); + MarkToAppendHostAddrRecordsInAdditionalData(); } } @@ -3052,16 +3043,17 @@ void Core::ServiceEntry::PrepareResponseRecords(EntryContext &aContext) AppendTxtRecordTo(response, kAdditionalDataSection); } - if (hostEntry != nullptr) + if (mHostEntry != nullptr) { - if (hostEntry->mIp6AddrRecord.ShouldAppendInAdditionalDataSection()) + if (mHostEntry->mIp6AddrRecord.ShouldAppendInAdditionalDataSection()) { - hostEntry->AppendIp6AddressRecordsTo(response, kAdditionalDataSection); + mHostEntry->AppendIp6AddressRecordsTo(response, kAdditionalDataSection); } - if ((hostEntry->mIp4AddrRecord != nullptr) && hostEntry->mIp4AddrRecord->ShouldAppendInAdditionalDataSection()) + if ((mHostEntry->mIp4AddrRecord != nullptr) && + mHostEntry->mIp4AddrRecord->ShouldAppendInAdditionalDataSection()) { - hostEntry->AppendIp4AddressRecordsTo(response, kAdditionalDataSection); + mHostEntry->AppendIp4AddressRecordsTo(response, kAdditionalDataSection); } } @@ -3130,26 +3122,36 @@ exit: return; } -void Core::ServiceEntry::DiscoverOffsetsAndHost(HostEntry *&aHostEntry) +void Core::ServiceEntry::MarkToAppendHostAddrRecordsInAdditionalData(void) { - // Discovers the `HostEntry` associated with this `ServiceEntry` - // and name compression offsets from the previously appended - // entries. + DiscoverHost(); - // TODO: Need to handle name matching host name - - aHostEntry = Get().mHostEntries.FindMatching(mHostName); - - if ((aHostEntry != nullptr) && (aHostEntry->GetState() != GetState())) + if (mHostEntry != nullptr) { - aHostEntry = nullptr; + mHostEntry->MarkToAppendAddrRecordsInAdditionalData(); + } +} + +void Core::ServiceEntry::DiscoverHost(void) +{ + if (mHostEntry == nullptr) + { + mHostEntry = Get().mHostEntries.FindMatching(mHostName); + + if ((mHostEntry != nullptr) && (mHostEntry->GetState() != GetState())) + { + mHostEntry = nullptr; + } } - if (aHostEntry != nullptr) + if (mHostEntry != nullptr) { - mHostNameOffset.UpdateFrom(aHostEntry->mNameOffset); + mHostNameOffset.UpdateFrom(mHostEntry->mNameOffset); } +} +void Core::ServiceEntry::DiscoverCompressOffset(OffsetDiscoverer aDiscoverer, void *aContext) +{ for (ServiceEntry &other : Get().mServiceEntries) { // We only need to search up to `this` entry in the list, @@ -3170,38 +3172,93 @@ void Core::ServiceEntry::DiscoverOffsetsAndHost(HostEntry *&aHostEntry) continue; } - if (NameMatch(mHostName, other.mHostName)) + if ((this->*aDiscoverer)(other, aContext)) { - mHostNameOffset.UpdateFrom(other.mHostNameOffset); - } - - if (NameMatch(mServiceType, other.mServiceType)) - { - mServiceTypeOffset.UpdateFrom(other.mServiceTypeOffset); - - if (GetState() == kProbing) - { - // No need to search for sub-type service offsets when - // we are still probing. - - continue; - } - - mSubServiceTypeOffset.UpdateFrom(other.mSubServiceTypeOffset); - - for (SubType &subType : mSubTypes) - { - const SubType *otherSubType = other.mSubTypes.FindMatching(subType.mLabel.AsCString()); - - if (otherSubType != nullptr) - { - subType.mSubServiceNameOffset.UpdateFrom(otherSubType->mSubServiceNameOffset); - } - } + break; } } } +void Core::ServiceEntry::DiscoverServiceTypeCompressOffset(void) +{ + if (!mServiceTypeOffset.IsKnown()) + { + DiscoverCompressOffset(&ServiceEntry::DiscoverServiceTypeOffsetFrom); + } +} + +bool Core::ServiceEntry::DiscoverServiceTypeOffsetFrom(const ServiceEntry &aOther, void *aContext) +{ + OT_UNUSED_VARIABLE(aContext); + + if (NameMatch(mServiceType, aOther.mServiceType)) + { + mServiceTypeOffset.UpdateFrom(aOther.mServiceTypeOffset); + mSubServiceTypeOffset.UpdateFrom(aOther.mSubServiceTypeOffset); + } + + return mServiceTypeOffset.IsKnown(); +} + +void Core::ServiceEntry::DiscoverHostNameCompressOffset(void) +{ + VerifyOrExit(!mHostNameOffset.IsKnown()); + + DiscoverHost(); + VerifyOrExit(!mHostNameOffset.IsKnown()); + + DiscoverCompressOffset(&ServiceEntry::DiscoverHostNameOffsetFrom); + + if (mHostEntry != nullptr) + { + mHostEntry->mNameOffset.UpdateFrom(mHostNameOffset); + } + +exit: + return; +} + +bool Core::ServiceEntry::DiscoverHostNameOffsetFrom(const ServiceEntry &aOther, void *aContext) +{ + OT_UNUSED_VARIABLE(aContext); + + if (NameMatch(mHostName, aOther.mHostName)) + { + mHostNameOffset.UpdateFrom(aOther.mHostNameOffset); + } + + return mHostNameOffset.IsKnown(); +} + +void Core::ServiceEntry::DiscoverSubServiceNameCompressOffsetFor(SubType &aSubType) +{ + if (!aSubType.mSubServiceNameOffset.IsKnown()) + { + DiscoverCompressOffset(&ServiceEntry::DiscoverSubServiceNameOffsetFrom, &aSubType); + } +} + +bool Core::ServiceEntry::DiscoverSubServiceNameOffsetFrom(const ServiceEntry &aOther, void *aContext) +{ + SubType *subType = static_cast(aContext); + const SubType *otherSubType; + + VerifyOrExit(NameMatch(mServiceType, aOther.mServiceType)); + + mServiceTypeOffset.UpdateFrom(aOther.mServiceTypeOffset); + mSubServiceTypeOffset.UpdateFrom(aOther.mSubServiceTypeOffset); + + VerifyOrExit(aOther.mSubServiceTypeOffset.IsKnown()); + + otherSubType = aOther.mSubTypes.FindMatching(subType->mLabel.AsCString()); + + VerifyOrExit(otherSubType != nullptr); + subType->mSubServiceNameOffset.UpdateFrom(otherSubType->mSubServiceNameOffset); + +exit: + return subType->mSubServiceNameOffset.IsKnown(); +} + void Core::ServiceEntry::UpdateServiceTypes(void) { // This method updates the `mServiceTypes` list adding or @@ -3411,30 +3468,22 @@ exit: void Core::ServiceEntry::AppendServiceTypeTo(TxMessage &aTxMessage, Section aSection) { + DiscoverServiceTypeCompressOffset(); aTxMessage.AppendServiceType(aSection, mServiceType.AsCString(), mServiceTypeOffset); } -void Core::ServiceEntry::AppendSubServiceTypeTo(TxMessage &aTxMessage, Section aSection) -{ - AppendOutcome outcome; - - outcome = aTxMessage.AppendLabel(aSection, kSubServiceLabel, mSubServiceTypeOffset); - VerifyOrExit(outcome != kAppendedFullNameAsCompressed); - - AppendServiceTypeTo(aTxMessage, aSection); - -exit: - return; -} - void Core::ServiceEntry::AppendSubServiceNameTo(TxMessage &aTxMessage, Section aSection, SubType &aSubType) { AppendOutcome outcome; + DiscoverSubServiceNameCompressOffsetFor(aSubType); outcome = aTxMessage.AppendLabel(aSection, aSubType.mLabel.AsCString(), aSubType.mSubServiceNameOffset); VerifyOrExit(outcome != kAppendedFullNameAsCompressed); - AppendSubServiceTypeTo(aTxMessage, aSection); + outcome = aTxMessage.AppendLabel(aSection, kSubServiceLabel, mSubServiceTypeOffset); + VerifyOrExit(outcome != kAppendedFullNameAsCompressed); + + aTxMessage.AppendServiceType(aSection, mServiceType.AsCString(), mServiceTypeOffset); exit: return; @@ -3444,9 +3493,15 @@ void Core::ServiceEntry::AppendHostNameTo(TxMessage &aTxMessage, Section aSectio { AppendOutcome outcome; + DiscoverHostNameCompressOffset(); outcome = aTxMessage.AppendMultipleLabels(aSection, mHostName.AsCString(), mHostNameOffset); VerifyOrExit(outcome != kAppendedFullNameAsCompressed); + if (mHostEntry != nullptr) + { + mHostEntry->mNameOffset.UpdateFrom(mHostNameOffset); + } + aTxMessage.AppendDomainName(aSection); exit: diff --git a/src/core/net/mdns.hpp b/src/core/net/mdns.hpp index 7c29e613c..cfe79656b 100644 --- a/src/core/net/mdns.hpp +++ b/src/core/net/mdns.hpp @@ -1409,6 +1409,8 @@ private: #endif private: + typedef bool (ServiceEntry::*OffsetDiscoverer)(const ServiceEntry &aOther, void *aContext); + class SubType : public LinkedListEntry, public Heap::Allocatable, private ot::NonCopyable { public: @@ -1431,7 +1433,15 @@ private: void PrepareResponseRecords(EntryContext &aContext); void UpdateRecordsState(const TxMessage &aResponse); void DetermineNextFireTime(void); - void DiscoverOffsetsAndHost(HostEntry *&aHost); + void MarkToAppendHostAddrRecordsInAdditionalData(void); + void DiscoverHost(void); + void DiscoverCompressOffset(OffsetDiscoverer aDiscoverer, void *aContext = nullptr); + void DiscoverServiceTypeCompressOffset(void); + bool DiscoverServiceTypeOffsetFrom(const ServiceEntry &aOther, void *aContext); + void DiscoverHostNameCompressOffset(void); + bool DiscoverHostNameOffsetFrom(const ServiceEntry &aOther, void *aContext); + void DiscoverSubServiceNameCompressOffsetFor(SubType &aSubType); + bool DiscoverSubServiceNameOffsetFrom(const ServiceEntry &aOther, void *aContext); void UpdateServiceTypes(void); void AppendSrvRecordTo(TxMessage &aTxMessage, Section aSection); void AppendTxtRecordTo(TxMessage &aTxMessage, Section aSection); @@ -1440,7 +1450,6 @@ private: void AppendNsecRecordTo(TxMessage &aTxMessage, Section aSection); void AppendServiceNameTo(TxMessage &TxMessage, Section aSection, bool aPerformNameCompression = true); void AppendServiceTypeTo(TxMessage &aTxMessage, Section aSection); - void AppendSubServiceTypeTo(TxMessage &aTxMessage, Section aSection); void AppendSubServiceNameTo(TxMessage &aTxMessage, Section aSection, SubType &aSubType); void AppendHostNameTo(TxMessage &aTxMessage, Section aSection); @@ -1464,6 +1473,7 @@ private: CompressOffset mServiceTypeOffset; CompressOffset mSubServiceTypeOffset; CompressOffset mHostNameOffset; + HostEntry *mHostEntry; bool mIsAddedInServiceTypes; };