Matter SDK Coverage Report
Current view: top level - lib/dnssd - Advertiser_ImplMinimalMdns.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 82.7 % 376 311
Test Date: 2025-01-17 19:00:11 Functions: 90.0 % 30 27

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2020-2022 Project CHIP Authors
       4              :  *
       5              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       6              :  *    you may not use this file except in compliance with the License.
       7              :  *    You may obtain a copy of the License at
       8              :  *
       9              :  *        http://www.apache.org/licenses/LICENSE-2.0
      10              :  *
      11              :  *    Unless required by applicable law or agreed to in writing, software
      12              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      13              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14              :  *    See the License for the specific language governing permissions and
      15              :  *    limitations under the License.
      16              :  */
      17              : 
      18              : #include "Advertiser.h"
      19              : 
      20              : #include <inttypes.h>
      21              : #include <stdio.h>
      22              : 
      23              : #include "MinimalMdnsServer.h"
      24              : #include "ServiceNaming.h"
      25              : 
      26              : #include <app/icd/server/ICDServerConfig.h>
      27              : #include <crypto/RandUtils.h>
      28              : #include <lib/dnssd/Advertiser_ImplMinimalMdnsAllocator.h>
      29              : #include <lib/dnssd/minimal_mdns/AddressPolicy.h>
      30              : #include <lib/dnssd/minimal_mdns/ResponseSender.h>
      31              : #include <lib/dnssd/minimal_mdns/Server.h>
      32              : #include <lib/dnssd/minimal_mdns/core/FlatAllocatedQName.h>
      33              : #include <lib/dnssd/minimal_mdns/responders/IP.h>
      34              : #include <lib/dnssd/minimal_mdns/responders/Ptr.h>
      35              : #include <lib/dnssd/minimal_mdns/responders/QueryResponder.h>
      36              : #include <lib/dnssd/minimal_mdns/responders/Srv.h>
      37              : #include <lib/dnssd/minimal_mdns/responders/Txt.h>
      38              : #include <lib/support/BytesToHex.h>
      39              : #include <lib/support/CHIPMem.h>
      40              : #include <lib/support/IntrusiveList.h>
      41              : #include <lib/support/StringBuilder.h>
      42              : 
      43              : // Enable detailed mDNS logging for received queries
      44              : #undef DETAIL_LOGGING
      45              : // #define DETAIL_LOGGING
      46              : 
      47              : namespace chip {
      48              : namespace Dnssd {
      49              : namespace {
      50              : 
      51              : using chip::Platform::UniquePtr;
      52              : using namespace mdns::Minimal;
      53              : 
      54              : #ifdef DETAIL_LOGGING
      55              : const char * ToString(QClass qClass)
      56              : {
      57              :     switch (qClass)
      58              :     {
      59              :     case QClass::IN:
      60              :         return "IN";
      61              :     default:
      62              :         return "???";
      63              :     }
      64              : }
      65              : 
      66              : const char * ToString(QType qType)
      67              : {
      68              :     switch (qType)
      69              :     {
      70              :     case QType::ANY:
      71              :         return "ANY";
      72              :     case QType::A:
      73              :         return "A";
      74              :     case QType::AAAA:
      75              :         return "AAAA";
      76              :     case QType::TXT:
      77              :         return "TXT";
      78              :     case QType::SRV:
      79              :         return "SRV";
      80              :     case QType::PTR:
      81              :         return "PTR";
      82              :     default:
      83              :         return "???";
      84              :     }
      85              : }
      86              : 
      87              : void LogQuery(const QueryData & data)
      88              : {
      89              :     StringBuilder<128> logString;
      90              : 
      91              :     logString.Add("QUERY ").Add(ToString(data.GetClass())).Add("/").Add(ToString(data.GetType())).Add(": ");
      92              : 
      93              :     SerializedQNameIterator name = data.GetName();
      94              :     while (name.Next())
      95              :     {
      96              :         logString.Add(name.Value()).Add(".");
      97              :     }
      98              : 
      99              :     ChipLogDetail(Discovery, "%s", logString.c_str());
     100              : }
     101              : #else
     102           24 : void LogQuery(const QueryData & data) {}
     103              : #endif
     104              : 
     105              : // Max number of records for operational = PTR, SRV, TXT, A, AAAA, I subtype.
     106              : constexpr size_t kMaxOperationalRecords = 6;
     107              : 
     108              : /// Represents an allocated operational responder.
     109              : ///
     110              : /// Wraps a QueryResponderAllocator.
     111              : class OperationalQueryAllocator : public chip::IntrusiveListNodeBase<>
     112              : {
     113              : public:
     114              :     using Allocator = QueryResponderAllocator<kMaxOperationalRecords>;
     115              : 
     116              :     /// Prefer to use `::New` for allocations instead of this direct call
     117            7 :     explicit OperationalQueryAllocator(Allocator * allocator) : mAllocator(allocator) {}
     118            7 :     ~OperationalQueryAllocator()
     119              :     {
     120            7 :         chip::Platform::Delete(mAllocator);
     121            7 :         mAllocator = nullptr;
     122            7 :     }
     123              : 
     124          125 :     Allocator * GetAllocator() { return mAllocator; }
     125              :     const Allocator * GetAllocator() const { return mAllocator; }
     126              : 
     127              :     /// Allocate a new entry for this type.
     128              :     ///
     129              :     /// May return null on allocation failures.
     130            7 :     static OperationalQueryAllocator * New()
     131              :     {
     132            7 :         Allocator * allocator = chip::Platform::New<Allocator>();
     133              : 
     134            7 :         if (allocator == nullptr)
     135              :         {
     136            0 :             return nullptr;
     137              :         }
     138              : 
     139            7 :         OperationalQueryAllocator * result = chip::Platform::New<OperationalQueryAllocator>(allocator);
     140            7 :         if (result == nullptr)
     141              :         {
     142            0 :             chip::Platform::Delete(allocator);
     143            0 :             return nullptr;
     144              :         }
     145              : 
     146            7 :         return result;
     147              :     }
     148              : 
     149              : private:
     150              :     Allocator * mAllocator = nullptr;
     151              : };
     152              : 
     153              : enum BroadcastAdvertiseType
     154              : {
     155              :     kStarted,     // Advertise at startup of all records added, as required by RFC 6762.
     156              :     kRemovingAll, // sent a TTL 0 for all records, as records are removed
     157              : };
     158              : 
     159              : class AdvertiserMinMdns : public ServiceAdvertiser,
     160              :                           public MdnsPacketDelegate, // receive query packets
     161              :                           public ParserDelegate      // parses queries
     162              : {
     163              : public:
     164            3 :     AdvertiserMinMdns() : mResponseSender(&GlobalMinimalMdnsServer::Server())
     165              :     {
     166            3 :         GlobalMinimalMdnsServer::Instance().SetQueryDelegate(this);
     167              : 
     168            3 :         CHIP_ERROR err = mResponseSender.AddQueryResponder(mQueryResponderAllocatorCommissionable.GetQueryResponder());
     169              : 
     170            3 :         if (err != CHIP_NO_ERROR)
     171              :         {
     172            0 :             ChipLogError(Discovery, "Failed to set up commissionable responder: %" CHIP_ERROR_FORMAT, err.Format());
     173              :         }
     174              : 
     175            3 :         err = mResponseSender.AddQueryResponder(mQueryResponderAllocatorCommissioner.GetQueryResponder());
     176            3 :         if (err != CHIP_NO_ERROR)
     177              :         {
     178            0 :             ChipLogError(Discovery, "Failed to set up commissioner responder: %" CHIP_ERROR_FORMAT, err.Format());
     179              :         }
     180            3 :     }
     181            3 :     ~AdvertiserMinMdns() override { ClearServices(); }
     182              : 
     183              :     // Service advertiser
     184              :     CHIP_ERROR Init(chip::Inet::EndPointManager<chip::Inet::UDPEndPoint> * udpEndPointManager) override;
     185            0 :     bool IsInitialized() override { return mIsInitialized; }
     186              :     void Shutdown() override;
     187              :     CHIP_ERROR RemoveServices() override;
     188              :     CHIP_ERROR Advertise(const OperationalAdvertisingParameters & params) override;
     189              :     CHIP_ERROR Advertise(const CommissionAdvertisingParameters & params) override;
     190              :     CHIP_ERROR FinalizeServiceUpdate() override;
     191              :     CHIP_ERROR GetCommissionableInstanceName(char * instanceName, size_t maxLength) const override;
     192              :     CHIP_ERROR UpdateCommissionableInstanceName() override;
     193              : 
     194              :     // MdnsPacketDelegate
     195              :     void OnMdnsPacketData(const BytesRange & data, const chip::Inet::IPPacketInfo * info) override;
     196              : 
     197              :     // ParserDelegate
     198           24 :     void OnHeader(ConstHeaderRef & header) override { mMessageId = header.GetMessageId(); }
     199            0 :     void OnResource(ResourceType type, const ResourceData & data) override {}
     200              :     void OnQuery(const QueryData & data) override;
     201              : 
     202              : private:
     203              :     /// Advertise available records configured within the server.
     204              :     ///
     205              :     /// Establishes a type of 'Advertise all currently configured items'
     206              :     /// for a specific purpose (e.g. boot time advertises everything, shut-down
     207              :     /// removes all records by advertising a 0 TTL)
     208              :     void AdvertiseRecords(BroadcastAdvertiseType type);
     209              : 
     210              :     FullQName GetCommissioningTxtEntries(const CommissionAdvertisingParameters & params);
     211              :     FullQName GetOperationalTxtEntries(OperationalQueryAllocator::Allocator * allocator,
     212              :                                        const OperationalAdvertisingParameters & params);
     213              : 
     214              :     struct CommonTxtEntryStorage
     215              :     {
     216              :         // +2 for all to account for '=' and terminating nullchar
     217              :         char sessionIdleIntervalBuf[KeySize(TxtFieldKey::kSessionIdleInterval) + ValSize(TxtFieldKey::kSessionIdleInterval) + 2];
     218              :         char sessionActiveIntervalBuf[KeySize(TxtFieldKey::kSessionActiveInterval) + ValSize(TxtFieldKey::kSessionActiveInterval) +
     219              :                                       2];
     220              :         char sessionActiveThresholdBuf[KeySize(TxtFieldKey::kSessionActiveThreshold) +
     221              :                                        ValSize(TxtFieldKey::kSessionActiveThreshold) + 2];
     222              :         char tcpSupportedBuf[KeySize(TxtFieldKey::kTcpSupported) + ValSize(TxtFieldKey::kTcpSupported) + 2];
     223              :         char operatingICDAsLITBuf[KeySize(TxtFieldKey::kLongIdleTimeICD) + ValSize(TxtFieldKey::kLongIdleTimeICD) + 2];
     224              :     };
     225              :     template <class Derived>
     226           19 :     CHIP_ERROR AddCommonTxtEntries(const BaseAdvertisingParams<Derived> & params, CommonTxtEntryStorage & storage,
     227              :                                    char ** txtFields, size_t & numTxtFields)
     228              :     {
     229              : 
     230           19 :         if (const auto & optionalMrp = params.GetLocalMRPConfig(); optionalMrp.has_value())
     231              :         {
     232            5 :             auto mrp = *optionalMrp;
     233              : 
     234              :             // An ICD operating as a LIT shall not advertise its slow polling interval.
     235              :             // Don't include the SII key in the advertisement when operating as so.
     236            5 :             if (params.GetICDModeToAdvertise() != ICDModeAdvertise::kLIT)
     237              :             {
     238            5 :                 if (mrp.mIdleRetransTimeout > kMaxRetryInterval)
     239              :                 {
     240            0 :                     ChipLogProgress(Discovery,
     241              :                                     "MRP retry interval idle value exceeds allowed range of 1 hour, using maximum available");
     242            0 :                     mrp.mIdleRetransTimeout = kMaxRetryInterval;
     243              :                 }
     244            5 :                 size_t writtenCharactersNumber =
     245            5 :                     static_cast<size_t>(snprintf(storage.sessionIdleIntervalBuf, sizeof(storage.sessionIdleIntervalBuf),
     246              :                                                  "SII=%" PRIu32, mrp.mIdleRetransTimeout.count()));
     247            5 :                 VerifyOrReturnError((writtenCharactersNumber > 0) &&
     248              :                                         (writtenCharactersNumber < sizeof(storage.sessionIdleIntervalBuf)),
     249              :                                     CHIP_ERROR_INVALID_STRING_LENGTH);
     250              : 
     251            5 :                 txtFields[numTxtFields++] = storage.sessionIdleIntervalBuf;
     252              :             }
     253              : 
     254              :             {
     255            5 :                 if (mrp.mActiveRetransTimeout > kMaxRetryInterval)
     256              :                 {
     257            2 :                     ChipLogProgress(Discovery,
     258              :                                     "MRP retry interval active value exceeds allowed range of 1 hour, using maximum available");
     259            2 :                     mrp.mActiveRetransTimeout = kMaxRetryInterval;
     260              :                 }
     261            5 :                 size_t writtenCharactersNumber =
     262            5 :                     static_cast<size_t>(snprintf(storage.sessionActiveIntervalBuf, sizeof(storage.sessionActiveIntervalBuf),
     263              :                                                  "SAI=%" PRIu32, mrp.mActiveRetransTimeout.count()));
     264            5 :                 VerifyOrReturnError((writtenCharactersNumber > 0) &&
     265              :                                         (writtenCharactersNumber < sizeof(storage.sessionActiveIntervalBuf)),
     266              :                                     CHIP_ERROR_INVALID_STRING_LENGTH);
     267            5 :                 txtFields[numTxtFields++] = storage.sessionActiveIntervalBuf;
     268              :             }
     269              : 
     270              :             {
     271            5 :                 size_t writtenCharactersNumber =
     272            5 :                     static_cast<size_t>(snprintf(storage.sessionActiveThresholdBuf, sizeof(storage.sessionActiveThresholdBuf),
     273            5 :                                                  "SAT=%u", mrp.mActiveThresholdTime.count()));
     274            5 :                 VerifyOrReturnError((writtenCharactersNumber > 0) &&
     275              :                                         (writtenCharactersNumber < sizeof(storage.sessionActiveThresholdBuf)),
     276              :                                     CHIP_ERROR_INVALID_STRING_LENGTH);
     277            5 :                 txtFields[numTxtFields++] = storage.sessionActiveThresholdBuf;
     278              :             }
     279              :         }
     280              : 
     281           19 :         if (params.GetTCPSupportModes() != TCPModeAdvertise::kNone)
     282              :         {
     283            3 :             size_t writtenCharactersNumber = static_cast<size_t>(snprintf(storage.tcpSupportedBuf, sizeof(storage.tcpSupportedBuf),
     284            3 :                                                                           "T=%d", static_cast<int>(params.GetTCPSupportModes())));
     285            3 :             VerifyOrReturnError((writtenCharactersNumber > 0) && (writtenCharactersNumber < sizeof(storage.tcpSupportedBuf)),
     286              :                                 CHIP_ERROR_INVALID_STRING_LENGTH);
     287            3 :             txtFields[numTxtFields++] = storage.tcpSupportedBuf;
     288              :         }
     289              : 
     290           19 :         if (params.GetICDModeToAdvertise() != ICDModeAdvertise::kNone)
     291              :         {
     292            2 :             size_t writtenCharactersNumber =
     293            2 :                 static_cast<size_t>(snprintf(storage.operatingICDAsLITBuf, sizeof(storage.operatingICDAsLITBuf), "ICD=%d",
     294            2 :                                              (params.GetICDModeToAdvertise() == ICDModeAdvertise::kLIT)));
     295            2 :             VerifyOrReturnError((writtenCharactersNumber > 0) && (writtenCharactersNumber < sizeof(storage.operatingICDAsLITBuf)),
     296              :                                 CHIP_ERROR_INVALID_STRING_LENGTH);
     297            2 :             txtFields[numTxtFields++] = storage.operatingICDAsLITBuf;
     298              :         }
     299           19 :         return CHIP_NO_ERROR;
     300              :     }
     301              : 
     302              :     IntrusiveList<OperationalQueryAllocator> mOperationalResponders;
     303              : 
     304              :     // Max number of records for commissionable = 7 x PTR (base + 6 sub types - _S, _L, _D, _T, _C, _A), SRV, TXT, A, AAAA
     305              :     static constexpr size_t kMaxCommissionRecords = 11;
     306              :     QueryResponderAllocator<kMaxCommissionRecords> mQueryResponderAllocatorCommissionable;
     307              :     QueryResponderAllocator<kMaxCommissionRecords> mQueryResponderAllocatorCommissioner;
     308              : 
     309              :     OperationalQueryAllocator::Allocator * FindOperationalAllocator(const FullQName & qname);
     310              :     OperationalQueryAllocator::Allocator * FindEmptyOperationalAllocator();
     311              : 
     312              :     void ClearServices();
     313              : 
     314              :     ResponseSender mResponseSender;
     315              :     uint8_t mCommissionableInstanceName[sizeof(uint64_t)];
     316              : 
     317              :     bool mIsInitialized = false;
     318              : 
     319              :     // current request handling
     320              :     const chip::Inet::IPPacketInfo * mCurrentSource = nullptr;
     321              :     uint16_t mMessageId                             = 0;
     322              : 
     323              :     const char * mEmptyTextEntries[1] = {
     324              :         "=",
     325              :     };
     326              : };
     327              : 
     328           24 : void AdvertiserMinMdns::OnMdnsPacketData(const BytesRange & data, const chip::Inet::IPPacketInfo * info)
     329              : {
     330              : #ifdef DETAIL_LOGGING
     331              :     char srcAddressString[chip::Inet::IPAddress::kMaxStringLength];
     332              :     VerifyOrDie(info->SrcAddress.ToString(srcAddressString) != nullptr);
     333              :     ChipLogDetail(Discovery, "Received an mDNS query from %s", srcAddressString);
     334              : #endif
     335              : 
     336           24 :     mCurrentSource = info;
     337           24 :     if (!ParsePacket(data, this))
     338              :     {
     339            0 :         ChipLogError(Discovery, "Failed to parse mDNS query");
     340              :     }
     341           24 :     mCurrentSource = nullptr;
     342           24 : }
     343              : 
     344           24 : void AdvertiserMinMdns::OnQuery(const QueryData & data)
     345              : {
     346           24 :     if (mCurrentSource == nullptr)
     347              :     {
     348            0 :         ChipLogError(Discovery, "INTERNAL CONSISTENCY ERROR: missing query source");
     349            0 :         return;
     350              :     }
     351              : 
     352           24 :     LogQuery(data);
     353              : 
     354           24 :     const ResponseConfiguration defaultResponseConfiguration;
     355           24 :     CHIP_ERROR err = mResponseSender.Respond(mMessageId, data, mCurrentSource, defaultResponseConfiguration);
     356           24 :     if (err != CHIP_NO_ERROR)
     357              :     {
     358            0 :         ChipLogError(Discovery, "Failed to reply to query: %" CHIP_ERROR_FORMAT, err.Format());
     359              :     }
     360              : }
     361              : 
     362           13 : CHIP_ERROR AdvertiserMinMdns::Init(chip::Inet::EndPointManager<chip::Inet::UDPEndPoint> * udpEndPointManager)
     363              : {
     364              :     // TODO: Per API documentation, Init() should be a no-op if mIsInitialized
     365              :     // is true.  But we don't handle updates to our set of interfaces right now,
     366              :     // so rely on the logic in this function to shut down and restart the
     367              :     // GlobalMinimalMdnsServer to handle that.
     368           13 :     GlobalMinimalMdnsServer::Server().ShutdownEndpoints();
     369              : 
     370           13 :     if (!mIsInitialized)
     371              :     {
     372            2 :         UpdateCommissionableInstanceName();
     373              :     }
     374              : 
     375              :     // Re-set the server in the response sender in case this has been swapped in the
     376              :     // GlobalMinimalMdnsServer (used for testing).
     377           13 :     mResponseSender.SetServer(&GlobalMinimalMdnsServer::Server());
     378              : 
     379           13 :     ReturnErrorOnFailure(GlobalMinimalMdnsServer::Instance().StartServer(udpEndPointManager, kMdnsPort));
     380              : 
     381           13 :     ChipLogProgress(Discovery, "CHIP minimal mDNS started advertising.");
     382              : 
     383           13 :     AdvertiseRecords(BroadcastAdvertiseType::kStarted);
     384              : 
     385           13 :     mIsInitialized = true;
     386              : 
     387           13 :     return CHIP_NO_ERROR;
     388              : }
     389              : 
     390            3 : void AdvertiserMinMdns::Shutdown()
     391              : {
     392            3 :     VerifyOrReturn(mIsInitialized);
     393              : 
     394            2 :     AdvertiseRecords(BroadcastAdvertiseType::kRemovingAll);
     395              : 
     396            2 :     GlobalMinimalMdnsServer::Server().Shutdown();
     397            2 :     mIsInitialized = false;
     398              : }
     399              : 
     400           17 : CHIP_ERROR AdvertiserMinMdns::RemoveServices()
     401              : {
     402           17 :     VerifyOrReturnError(mIsInitialized, CHIP_ERROR_INCORRECT_STATE);
     403              : 
     404              :     // Send a "goodbye" packet for each RR being removed, as defined in RFC 6762.
     405              :     // This allows mDNS clients to remove stale cached records which may not be re-added with
     406              :     // subsequent Advertise() calls. In the case the same records are re-added, this extra
     407              :     // is not harmful though suboptimal, so this is a subject to improvement in the future.
     408           16 :     AdvertiseRecords(BroadcastAdvertiseType::kRemovingAll);
     409           16 :     ClearServices();
     410              : 
     411           16 :     return CHIP_NO_ERROR;
     412              : }
     413              : 
     414           19 : void AdvertiserMinMdns::ClearServices()
     415              : {
     416           26 :     while (mOperationalResponders.begin() != mOperationalResponders.end())
     417              :     {
     418            7 :         auto it = mOperationalResponders.begin();
     419              : 
     420              :         // Need to free the memory once it is out of the list
     421            7 :         OperationalQueryAllocator * ptr = &*it;
     422              : 
     423              :         // Mark as unused
     424            7 :         ptr->GetAllocator()->Clear();
     425              : 
     426            7 :         CHIP_ERROR err = mResponseSender.RemoveQueryResponder(ptr->GetAllocator()->GetQueryResponder());
     427            7 :         if (err != CHIP_NO_ERROR)
     428              :         {
     429            0 :             ChipLogError(Discovery, "Failed to remove query responder: %" CHIP_ERROR_FORMAT, err.Format());
     430              :         }
     431              : 
     432            7 :         mOperationalResponders.Remove(ptr);
     433              : 
     434              :         // Finally release the memory
     435            7 :         chip::Platform::Delete(ptr);
     436              :     }
     437              : 
     438           19 :     mQueryResponderAllocatorCommissionable.Clear();
     439           19 :     mQueryResponderAllocatorCommissioner.Clear();
     440           19 : }
     441              : 
     442            8 : OperationalQueryAllocator::Allocator * AdvertiserMinMdns::FindOperationalAllocator(const FullQName & qname)
     443              : {
     444           19 :     for (auto & it : mOperationalResponders)
     445              :     {
     446           12 :         if (it.GetAllocator()->GetResponder(QType::SRV, qname) != nullptr)
     447              :         {
     448            1 :             return it.GetAllocator();
     449              :         }
     450              :     }
     451              : 
     452            7 :     return nullptr;
     453              : }
     454              : 
     455            7 : OperationalQueryAllocator::Allocator * AdvertiserMinMdns::FindEmptyOperationalAllocator()
     456              : {
     457            7 :     OperationalQueryAllocator * result = OperationalQueryAllocator::New();
     458              : 
     459            7 :     if (result == nullptr)
     460              :     {
     461            0 :         return nullptr;
     462              :     }
     463              : 
     464            7 :     CHIP_ERROR err = mResponseSender.AddQueryResponder(result->GetAllocator()->GetQueryResponder());
     465              : 
     466            7 :     if (err != CHIP_NO_ERROR)
     467              :     {
     468            0 :         ChipLogError(Discovery, "Failed to register query responder: %" CHIP_ERROR_FORMAT, err.Format());
     469            0 :         Platform::Delete(result);
     470            0 :         return nullptr;
     471              :     }
     472              : 
     473            7 :     mOperationalResponders.PushBack(result);
     474            7 :     return result->GetAllocator();
     475              : }
     476              : 
     477            8 : CHIP_ERROR AdvertiserMinMdns::Advertise(const OperationalAdvertisingParameters & params)
     478              : {
     479            8 :     VerifyOrReturnError(mIsInitialized, CHIP_ERROR_INCORRECT_STATE);
     480              : 
     481            8 :     char nameBuffer[Operational::kInstanceNameMaxLength + 1] = "";
     482              : 
     483              :     // need to set server name
     484            8 :     ReturnErrorOnFailure(MakeInstanceName(nameBuffer, sizeof(nameBuffer), params.GetPeerId()));
     485              : 
     486            8 :     QNamePart nameCheckParts[]  = { nameBuffer, kOperationalServiceName, kOperationalProtocol, kLocalDomain };
     487            8 :     FullQName nameCheck         = FullQName(nameCheckParts);
     488            8 :     auto * operationalAllocator = FindOperationalAllocator(nameCheck);
     489            8 :     if (operationalAllocator != nullptr)
     490              :     {
     491            1 :         operationalAllocator->Clear();
     492              :     }
     493              :     else
     494              :     {
     495            7 :         operationalAllocator = FindEmptyOperationalAllocator();
     496            7 :         if (operationalAllocator == nullptr)
     497              :         {
     498            0 :             ChipLogError(Discovery, "Failed to find an open operational allocator");
     499            0 :             return CHIP_ERROR_NO_MEMORY;
     500              :         }
     501              :     }
     502              : 
     503            8 :     FullQName serviceName = operationalAllocator->AllocateQName(kOperationalServiceName, kOperationalProtocol, kLocalDomain);
     504              :     FullQName instanceName =
     505            8 :         operationalAllocator->AllocateQName(nameBuffer, kOperationalServiceName, kOperationalProtocol, kLocalDomain);
     506              : 
     507            8 :     ReturnErrorOnFailure(MakeHostName(nameBuffer, sizeof(nameBuffer), params.GetMac()));
     508            8 :     FullQName hostName = operationalAllocator->AllocateQName(nameBuffer, kLocalDomain);
     509              : 
     510            8 :     if ((serviceName.nameCount == 0) || (instanceName.nameCount == 0) || (hostName.nameCount == 0))
     511              :     {
     512            0 :         ChipLogError(Discovery, "Failed to allocate QNames.");
     513            0 :         return CHIP_ERROR_NO_MEMORY;
     514              :     }
     515              : 
     516           16 :     if (!operationalAllocator->AddResponder<PtrResponder>(serviceName, instanceName)
     517            8 :              .SetReportAdditional(instanceName)
     518            8 :              .SetReportInServiceListing(true)
     519            8 :              .IsValid())
     520              :     {
     521            0 :         ChipLogError(Discovery, "Failed to add service PTR record mDNS responder");
     522            0 :         return CHIP_ERROR_NO_MEMORY;
     523              :     }
     524              : 
     525              :     // We are the sole owner of our instanceName, so records keyed on the
     526              :     // instanceName should have the cache-flush bit set.
     527            8 :     SrvResourceRecord srvRecord(instanceName, hostName, params.GetPort());
     528            8 :     srvRecord.SetCacheFlush(true);
     529            8 :     if (!operationalAllocator->AddResponder<SrvResponder>(srvRecord).SetReportAdditional(hostName).IsValid())
     530              :     {
     531            0 :         ChipLogError(Discovery, "Failed to add SRV record mDNS responder");
     532            0 :         return CHIP_ERROR_NO_MEMORY;
     533              :     }
     534              : 
     535            8 :     TxtResourceRecord txtRecord(instanceName, GetOperationalTxtEntries(operationalAllocator, params));
     536            8 :     txtRecord.SetCacheFlush(true);
     537            8 :     if (!operationalAllocator->AddResponder<TxtResponder>(txtRecord).SetReportAdditional(hostName).IsValid())
     538              :     {
     539            0 :         ChipLogError(Discovery, "Failed to add TXT record mDNS responder");
     540            0 :         return CHIP_ERROR_NO_MEMORY;
     541              :     }
     542              : 
     543            8 :     if (!operationalAllocator->AddResponder<IPv6Responder>(hostName).IsValid())
     544              :     {
     545            0 :         ChipLogError(Discovery, "Failed to add IPv6 mDNS responder");
     546            0 :         return CHIP_ERROR_NO_MEMORY;
     547              :     }
     548              : 
     549            8 :     if (params.IsIPv4Enabled())
     550              :     {
     551            8 :         if (!operationalAllocator->AddResponder<IPv4Responder>(hostName).IsValid())
     552              :         {
     553            0 :             ChipLogError(Discovery, "Failed to add IPv4 mDNS responder");
     554            0 :             return CHIP_ERROR_NO_MEMORY;
     555              :         }
     556              :     }
     557            8 :     MakeServiceSubtype(nameBuffer, sizeof(nameBuffer),
     558            8 :                        DiscoveryFilter(DiscoveryFilterType::kCompressedFabricId, params.GetPeerId().GetCompressedFabricId()));
     559            8 :     FullQName compressedFabricIdSubtype = operationalAllocator->AllocateQName(
     560              :         nameBuffer, kSubtypeServiceNamePart, kOperationalServiceName, kOperationalProtocol, kLocalDomain);
     561            8 :     VerifyOrReturnError(compressedFabricIdSubtype.nameCount != 0, CHIP_ERROR_NO_MEMORY);
     562              : 
     563           16 :     if (!operationalAllocator->AddResponder<PtrResponder>(compressedFabricIdSubtype, instanceName)
     564            8 :              .SetReportAdditional(instanceName)
     565            8 :              .SetReportInServiceListing(true)
     566            8 :              .IsValid())
     567              :     {
     568            0 :         ChipLogError(Discovery, "Failed to add device type PTR record mDNS responder");
     569            0 :         return CHIP_ERROR_NO_MEMORY;
     570              :     }
     571              : 
     572            8 :     ChipLogProgress(Discovery, "CHIP minimal mDNS configured as 'Operational device'; instance name: %s.", instanceName.names[0]);
     573              : 
     574            8 :     AdvertiseRecords(BroadcastAdvertiseType::kStarted);
     575              : 
     576            8 :     ChipLogProgress(Discovery, "mDNS service published: %s.%s", StringOrNullMarker(instanceName.names[1]),
     577              :                     StringOrNullMarker(instanceName.names[2]));
     578              : 
     579            8 :     return CHIP_NO_ERROR;
     580            8 : }
     581              : 
     582           19 : CHIP_ERROR AdvertiserMinMdns::FinalizeServiceUpdate()
     583              : {
     584           19 :     VerifyOrReturnError(mIsInitialized, CHIP_ERROR_INCORRECT_STATE);
     585           19 :     return CHIP_NO_ERROR;
     586              : }
     587              : 
     588           12 : CHIP_ERROR AdvertiserMinMdns::GetCommissionableInstanceName(char * instanceName, size_t maxLength) const
     589              : {
     590           12 :     if (maxLength < (Commission::kInstanceNameMaxLength + 1))
     591              :     {
     592            0 :         return CHIP_ERROR_NO_MEMORY;
     593              :     }
     594              : 
     595           12 :     return chip::Encoding::BytesToUppercaseHexString(&mCommissionableInstanceName[0], sizeof(mCommissionableInstanceName),
     596           12 :                                                      instanceName, maxLength);
     597              : }
     598              : 
     599            8 : CHIP_ERROR AdvertiserMinMdns::UpdateCommissionableInstanceName()
     600              : {
     601            8 :     uint64_t random_instance_name = chip::Crypto::GetRandU64();
     602              :     static_assert(sizeof(mCommissionableInstanceName) == sizeof(random_instance_name), "Not copying the right amount of data");
     603            8 :     memcpy(&mCommissionableInstanceName[0], &random_instance_name, sizeof(mCommissionableInstanceName));
     604            8 :     return CHIP_NO_ERROR;
     605              : }
     606              : 
     607           11 : CHIP_ERROR AdvertiserMinMdns::Advertise(const CommissionAdvertisingParameters & params)
     608              : {
     609           11 :     VerifyOrReturnError(mIsInitialized, CHIP_ERROR_INCORRECT_STATE);
     610              : 
     611           11 :     if (params.GetCommissionAdvertiseMode() == CommssionAdvertiseMode::kCommissionableNode)
     612              :     {
     613           11 :         mQueryResponderAllocatorCommissionable.Clear();
     614              :     }
     615              :     else
     616              :     {
     617            0 :         mQueryResponderAllocatorCommissioner.Clear();
     618              :     }
     619              : 
     620              :     // TODO: need to detect colisions here
     621           11 :     char nameBuffer[64] = "";
     622           11 :     ReturnErrorOnFailure(GetCommissionableInstanceName(nameBuffer, sizeof(nameBuffer)));
     623              : 
     624              :     QueryResponderAllocator<kMaxCommissionRecords> * allocator =
     625           11 :         params.GetCommissionAdvertiseMode() == CommssionAdvertiseMode::kCommissionableNode ? &mQueryResponderAllocatorCommissionable
     626           11 :                                                                                            : &mQueryResponderAllocatorCommissioner;
     627           11 :     const char * serviceType = params.GetCommissionAdvertiseMode() == CommssionAdvertiseMode::kCommissionableNode
     628              :         ? kCommissionableServiceName
     629           11 :         : kCommissionerServiceName;
     630              : 
     631           11 :     FullQName serviceName  = allocator->AllocateQName(serviceType, kCommissionProtocol, kLocalDomain);
     632           11 :     FullQName instanceName = allocator->AllocateQName(nameBuffer, serviceType, kCommissionProtocol, kLocalDomain);
     633              : 
     634           11 :     ReturnErrorOnFailure(MakeHostName(nameBuffer, sizeof(nameBuffer), params.GetMac()));
     635           11 :     FullQName hostName = allocator->AllocateQName(nameBuffer, kLocalDomain);
     636              : 
     637           11 :     if ((serviceName.nameCount == 0) || (instanceName.nameCount == 0) || (hostName.nameCount == 0))
     638              :     {
     639            0 :         ChipLogError(Discovery, "Failed to allocate QNames.");
     640            0 :         return CHIP_ERROR_NO_MEMORY;
     641              :     }
     642              : 
     643           22 :     if (!allocator->AddResponder<PtrResponder>(serviceName, instanceName)
     644           11 :              .SetReportAdditional(instanceName)
     645           11 :              .SetReportInServiceListing(true)
     646           11 :              .IsValid())
     647              :     {
     648            0 :         ChipLogError(Discovery, "Failed to add service PTR record mDNS responder");
     649            0 :         return CHIP_ERROR_NO_MEMORY;
     650              :     }
     651              : 
     652           11 :     SrvResourceRecord srvRecord(instanceName, hostName, params.GetPort());
     653           11 :     srvRecord.SetCacheFlush(true);
     654           11 :     if (!allocator->AddResponder<SrvResponder>(srvRecord).SetReportAdditional(hostName).IsValid())
     655              :     {
     656            0 :         ChipLogError(Discovery, "Failed to add SRV record mDNS responder");
     657            0 :         return CHIP_ERROR_NO_MEMORY;
     658              :     }
     659           11 :     if (!allocator->AddResponder<IPv6Responder>(hostName).IsValid())
     660              :     {
     661            0 :         ChipLogError(Discovery, "Failed to add IPv6 mDNS responder");
     662            0 :         return CHIP_ERROR_NO_MEMORY;
     663              :     }
     664              : 
     665           11 :     if (params.IsIPv4Enabled())
     666              :     {
     667           11 :         if (!allocator->AddResponder<IPv4Responder>(hostName).IsValid())
     668              :         {
     669            0 :             ChipLogError(Discovery, "Failed to add IPv4 mDNS responder");
     670            0 :             return CHIP_ERROR_NO_MEMORY;
     671              :         }
     672              :     }
     673              : 
     674           11 :     if (const auto & vendorId = params.GetVendorId(); vendorId.has_value())
     675              :     {
     676           10 :         MakeServiceSubtype(nameBuffer, sizeof(nameBuffer), DiscoveryFilter(DiscoveryFilterType::kVendorId, *vendorId));
     677              :         FullQName vendorServiceName =
     678           10 :             allocator->AllocateQName(nameBuffer, kSubtypeServiceNamePart, serviceType, kCommissionProtocol, kLocalDomain);
     679           10 :         VerifyOrReturnError(vendorServiceName.nameCount != 0, CHIP_ERROR_NO_MEMORY);
     680              : 
     681           20 :         if (!allocator->AddResponder<PtrResponder>(vendorServiceName, instanceName)
     682           10 :                  .SetReportAdditional(instanceName)
     683           10 :                  .SetReportInServiceListing(true)
     684           10 :                  .IsValid())
     685              :         {
     686            0 :             ChipLogError(Discovery, "Failed to add vendor PTR record mDNS responder");
     687            0 :             return CHIP_ERROR_NO_MEMORY;
     688              :         }
     689              :     }
     690              : 
     691           11 :     if (const auto & deviceType = params.GetDeviceType(); deviceType.has_value())
     692              :     {
     693            3 :         MakeServiceSubtype(nameBuffer, sizeof(nameBuffer), DiscoveryFilter(DiscoveryFilterType::kDeviceType, *deviceType));
     694              :         FullQName vendorServiceName =
     695            3 :             allocator->AllocateQName(nameBuffer, kSubtypeServiceNamePart, serviceType, kCommissionProtocol, kLocalDomain);
     696            3 :         VerifyOrReturnError(vendorServiceName.nameCount != 0, CHIP_ERROR_NO_MEMORY);
     697              : 
     698            6 :         if (!allocator->AddResponder<PtrResponder>(vendorServiceName, instanceName)
     699            3 :                  .SetReportAdditional(instanceName)
     700            3 :                  .SetReportInServiceListing(true)
     701            3 :                  .IsValid())
     702              :         {
     703            0 :             ChipLogError(Discovery, "Failed to add device type PTR record mDNS responder");
     704            0 :             return CHIP_ERROR_NO_MEMORY;
     705              :         }
     706              :     }
     707              : 
     708              :     // the following sub types only apply to commissionable node advertisements
     709           11 :     if (params.GetCommissionAdvertiseMode() == CommssionAdvertiseMode::kCommissionableNode)
     710              :     {
     711              :         {
     712           11 :             MakeServiceSubtype(nameBuffer, sizeof(nameBuffer),
     713           11 :                                DiscoveryFilter(DiscoveryFilterType::kShortDiscriminator, params.GetShortDiscriminator()));
     714              :             FullQName shortServiceName =
     715           11 :                 allocator->AllocateQName(nameBuffer, kSubtypeServiceNamePart, serviceType, kCommissionProtocol, kLocalDomain);
     716           11 :             VerifyOrReturnError(shortServiceName.nameCount != 0, CHIP_ERROR_NO_MEMORY);
     717              : 
     718           22 :             if (!allocator->AddResponder<PtrResponder>(shortServiceName, instanceName)
     719           11 :                      .SetReportAdditional(instanceName)
     720           11 :                      .SetReportInServiceListing(true)
     721           11 :                      .IsValid())
     722              :             {
     723            0 :                 ChipLogError(Discovery, "Failed to add short discriminator PTR record mDNS responder");
     724            0 :                 return CHIP_ERROR_NO_MEMORY;
     725              :             }
     726              :         }
     727              : 
     728              :         {
     729           11 :             MakeServiceSubtype(nameBuffer, sizeof(nameBuffer),
     730           11 :                                DiscoveryFilter(DiscoveryFilterType::kLongDiscriminator, params.GetLongDiscriminator()));
     731              :             FullQName longServiceName =
     732           11 :                 allocator->AllocateQName(nameBuffer, kSubtypeServiceNamePart, serviceType, kCommissionProtocol, kLocalDomain);
     733           11 :             VerifyOrReturnError(longServiceName.nameCount != 0, CHIP_ERROR_NO_MEMORY);
     734           22 :             if (!allocator->AddResponder<PtrResponder>(longServiceName, instanceName)
     735           11 :                      .SetReportAdditional(instanceName)
     736           11 :                      .SetReportInServiceListing(true)
     737           11 :                      .IsValid())
     738              :             {
     739            0 :                 ChipLogError(Discovery, "Failed to add long discriminator PTR record mDNS responder");
     740            0 :                 return CHIP_ERROR_NO_MEMORY;
     741              :             }
     742              :         }
     743              : 
     744           11 :         if (params.GetCommissioningMode() != CommissioningMode::kDisabled)
     745              :         {
     746           10 :             MakeServiceSubtype(nameBuffer, sizeof(nameBuffer), DiscoveryFilter(DiscoveryFilterType::kCommissioningMode));
     747              :             FullQName longServiceName =
     748           10 :                 allocator->AllocateQName(nameBuffer, kSubtypeServiceNamePart, serviceType, kCommissionProtocol, kLocalDomain);
     749           10 :             VerifyOrReturnError(longServiceName.nameCount != 0, CHIP_ERROR_NO_MEMORY);
     750           20 :             if (!allocator->AddResponder<PtrResponder>(longServiceName, instanceName)
     751           10 :                      .SetReportAdditional(instanceName)
     752           10 :                      .SetReportInServiceListing(true)
     753           10 :                      .IsValid())
     754              :             {
     755            0 :                 ChipLogError(Discovery, "Failed to add commissioning mode PTR record mDNS responder");
     756            0 :                 return CHIP_ERROR_NO_MEMORY;
     757              :             }
     758              :         }
     759              :     }
     760              : 
     761           11 :     TxtResourceRecord txtRecord(instanceName, GetCommissioningTxtEntries(params));
     762           11 :     txtRecord.SetCacheFlush(true);
     763           11 :     if (!allocator->AddResponder<TxtResponder>(txtRecord).SetReportAdditional(hostName).IsValid())
     764              :     {
     765            0 :         ChipLogError(Discovery, "Failed to add TXT record mDNS responder");
     766            0 :         return CHIP_ERROR_NO_MEMORY;
     767              :     }
     768              : 
     769           11 :     if (params.GetCommissionAdvertiseMode() == CommssionAdvertiseMode::kCommissionableNode)
     770              :     {
     771           11 :         ChipLogProgress(Discovery, "CHIP minimal mDNS configured as 'Commissionable node device'; instance name: %s.",
     772              :                         StringOrNullMarker(instanceName.names[0]));
     773              :     }
     774              :     else
     775              :     {
     776            0 :         ChipLogProgress(Discovery, "CHIP minimal mDNS configured as 'Commissioner device'; instance name: %s.",
     777              :                         StringOrNullMarker(instanceName.names[0]));
     778              :     }
     779              : 
     780           11 :     AdvertiseRecords(BroadcastAdvertiseType::kStarted);
     781              : 
     782           11 :     ChipLogProgress(Discovery, "mDNS service published: %s.%s", StringOrNullMarker(instanceName.names[1]),
     783              :                     StringOrNullMarker(instanceName.names[2]));
     784              : 
     785           11 :     return CHIP_NO_ERROR;
     786           11 : }
     787              : 
     788            8 : FullQName AdvertiserMinMdns::GetOperationalTxtEntries(OperationalQueryAllocator::Allocator * allocator,
     789              :                                                       const OperationalAdvertisingParameters & params)
     790              : {
     791              :     char * txtFields[OperationalAdvertisingParameters::kTxtMaxNumber];
     792            8 :     size_t numTxtFields = 0;
     793              : 
     794              :     struct CommonTxtEntryStorage commonStorage;
     795            8 :     AddCommonTxtEntries<OperationalAdvertisingParameters>(params, commonStorage, txtFields, numTxtFields);
     796            8 :     if (numTxtFields == 0)
     797              :     {
     798            5 :         return allocator->AllocateQNameFromArray(mEmptyTextEntries, 1);
     799              :     }
     800              : 
     801            3 :     return allocator->AllocateQNameFromArray(txtFields, numTxtFields);
     802              : }
     803              : 
     804           11 : FullQName AdvertiserMinMdns::GetCommissioningTxtEntries(const CommissionAdvertisingParameters & params)
     805              : {
     806              :     char * txtFields[CommissionAdvertisingParameters::kTxtMaxNumber];
     807           11 :     size_t numTxtFields = 0;
     808              : 
     809              :     QueryResponderAllocator<kMaxCommissionRecords> * allocator =
     810           11 :         params.GetCommissionAdvertiseMode() == CommssionAdvertiseMode::kCommissionableNode ? &mQueryResponderAllocatorCommissionable
     811           11 :                                                                                            : &mQueryResponderAllocatorCommissioner;
     812              : 
     813              :     char txtVidPid[chip::Dnssd::kKeyVendorProductMaxLength + 4];
     814              :     {
     815           11 :         const auto & productId = params.GetProductId();
     816           11 :         const auto & vendorId  = params.GetVendorId();
     817           11 :         if (productId.has_value() && vendorId.has_value())
     818              :         {
     819           10 :             snprintf(txtVidPid, sizeof(txtVidPid), "VP=%d+%d", *vendorId, *productId);
     820           10 :             txtFields[numTxtFields++] = txtVidPid;
     821              :         }
     822            1 :         else if (vendorId.has_value())
     823              :         {
     824            0 :             snprintf(txtVidPid, sizeof(txtVidPid), "VP=%d", *vendorId);
     825            0 :             txtFields[numTxtFields++] = txtVidPid;
     826              :         }
     827              :     }
     828              : 
     829              :     char txtDeviceType[chip::Dnssd::kKeyDeviceTypeMaxLength + 4];
     830           11 :     if (const auto & deviceType = params.GetDeviceType(); deviceType.has_value())
     831              :     {
     832            3 :         snprintf(txtDeviceType, sizeof(txtDeviceType), "DT=%" PRIu32, *deviceType);
     833            3 :         txtFields[numTxtFields++] = txtDeviceType;
     834              :     }
     835              : 
     836              :     char txtDeviceName[chip::Dnssd::kKeyDeviceNameMaxLength + 4];
     837           11 :     if (const auto & deviceName = params.GetDeviceName(); deviceName.has_value())
     838              :     {
     839            3 :         snprintf(txtDeviceName, sizeof(txtDeviceName), "DN=%s", *deviceName);
     840            3 :         txtFields[numTxtFields++] = txtDeviceName;
     841              :     }
     842              :     CommonTxtEntryStorage commonStorage;
     843           11 :     AddCommonTxtEntries<CommissionAdvertisingParameters>(params, commonStorage, txtFields, numTxtFields);
     844              : 
     845              :     // the following sub types only apply to commissionable node advertisements
     846              :     char txtDiscriminator[chip::Dnssd::kKeyLongDiscriminatorMaxLength + 3];
     847              :     char txtCommissioningMode[chip::Dnssd::kKeyCommissioningModeMaxLength + 4];
     848              :     char txtRotatingDeviceId[chip::Dnssd::kKeyRotatingDeviceIdMaxLength + 4];
     849              :     char txtPairingHint[chip::Dnssd::kKeyPairingInstructionMaxLength + 4];
     850              :     char txtPairingInstr[chip::Dnssd::kKeyPairingInstructionMaxLength + 4];
     851              : 
     852              :     // the following sub types only apply to commissioner discovery advertisements
     853              :     char txtCommissionerPasscode[chip::Dnssd::kKeyCommissionerPasscodeMaxLength + 4];
     854              : 
     855           11 :     if (params.GetCommissionAdvertiseMode() == CommssionAdvertiseMode::kCommissionableNode)
     856              :     {
     857              :         // a discriminator always exists
     858           11 :         snprintf(txtDiscriminator, sizeof(txtDiscriminator), "D=%d", params.GetLongDiscriminator());
     859           11 :         txtFields[numTxtFields++] = txtDiscriminator;
     860              : 
     861           11 :         snprintf(txtCommissioningMode, sizeof(txtCommissioningMode), "CM=%d", static_cast<int>(params.GetCommissioningMode()));
     862           11 :         txtFields[numTxtFields++] = txtCommissioningMode;
     863              : 
     864           11 :         if (const auto & rotatingDeviceId = params.GetRotatingDeviceId(); rotatingDeviceId.has_value())
     865              :         {
     866            3 :             snprintf(txtRotatingDeviceId, sizeof(txtRotatingDeviceId), "RI=%s", *rotatingDeviceId);
     867            3 :             txtFields[numTxtFields++] = txtRotatingDeviceId;
     868              :         }
     869              : 
     870           11 :         if (const auto & pairingHint = params.GetPairingHint(); pairingHint.has_value())
     871              :         {
     872           10 :             snprintf(txtPairingHint, sizeof(txtPairingHint), "PH=%d", *pairingHint);
     873           10 :             txtFields[numTxtFields++] = txtPairingHint;
     874              :         }
     875              : 
     876           11 :         if (const auto & pairingInstruction = params.GetPairingInstruction(); pairingInstruction.has_value())
     877              :         {
     878           10 :             snprintf(txtPairingInstr, sizeof(txtPairingInstr), "PI=%s", *pairingInstruction);
     879           10 :             txtFields[numTxtFields++] = txtPairingInstr;
     880              :         }
     881              :     }
     882              :     else
     883              :     {
     884            0 :         if (params.GetCommissionerPasscodeSupported().value_or(false))
     885              :         {
     886            0 :             snprintf(txtCommissionerPasscode, sizeof(txtCommissionerPasscode), "CP=%d", static_cast<int>(1));
     887            0 :             txtFields[numTxtFields++] = txtCommissionerPasscode;
     888              :         }
     889              :     }
     890           11 :     if (numTxtFields == 0)
     891              :     {
     892            0 :         return allocator->AllocateQNameFromArray(mEmptyTextEntries, 1);
     893              :     }
     894              : 
     895           11 :     return allocator->AllocateQNameFromArray(txtFields, numTxtFields);
     896              : }
     897              : 
     898           50 : void AdvertiserMinMdns::AdvertiseRecords(BroadcastAdvertiseType type)
     899              : {
     900           50 :     ResponseConfiguration responseConfiguration;
     901           50 :     if (type == BroadcastAdvertiseType::kRemovingAll)
     902              :     {
     903              :         // make a "remove all records now" broadcast
     904           18 :         responseConfiguration.SetTtlSecondsOverride(0);
     905              :     }
     906              : 
     907           50 :     UniquePtr<ListenIterator> allInterfaces = GetAddressPolicy()->GetListenEndpoints();
     908           50 :     VerifyOrDieWithMsg(allInterfaces != nullptr, Discovery, "Failed to allocate memory for endpoints.");
     909              : 
     910           50 :     chip::Inet::InterfaceId interfaceId;
     911              :     chip::Inet::IPAddressType addressType;
     912              : 
     913          150 :     while (allInterfaces->Next(&interfaceId, &addressType))
     914              :     {
     915          100 :         UniquePtr<IpAddressIterator> allIps = GetAddressPolicy()->GetIpAddressesForEndpoint(interfaceId, addressType);
     916          100 :         VerifyOrDieWithMsg(allIps != nullptr, Discovery, "Failed to allocate memory for ip addresses.");
     917              : 
     918          100 :         chip::Inet::IPPacketInfo packetInfo;
     919              : 
     920          100 :         packetInfo.Clear();
     921              : 
     922              :         // advertising on every interface requires a valid IP address
     923              :         // since we use "BROADCAST" (unicast is false), we do not actually care about
     924              :         // the source IP address value, just that it has the right "type"
     925              :         //
     926              :         // NOTE: cannot use Broadcast address as the source as they have the type kAny.
     927              :         //
     928              :         // TODO: ideally we may want to have a destination that is explicit as "unicast/destIp"
     929              :         //       vs "multicast/addressType". Such a change requires larger code updates.
     930          100 :         packetInfo.SrcAddress  = chip::Inet::IPAddress::Loopback(addressType);
     931          100 :         packetInfo.DestAddress = BroadcastIpAddresses::Get(addressType);
     932          100 :         packetInfo.SrcPort     = kMdnsPort;
     933          100 :         packetInfo.DestPort    = kMdnsPort;
     934          100 :         packetInfo.Interface   = interfaceId;
     935              : 
     936              :         // Advertise all records
     937              :         //
     938              :         // TODO: Consider advertising delta changes.
     939              :         //
     940              :         // Current advertisement does not have a concept of "delta" to only
     941              :         // advertise changes. Current implementation is to always
     942              :         //    1. advertise TTL=0 (clear all caches)
     943              :         //    2. advertise available records (with longer TTL)
     944              :         //
     945              :         // It would be nice if we could selectively advertise what changes, like
     946              :         // send TTL=0 for anything removed/about to be removed (and only those),
     947              :         // then only advertise new items added.
     948              :         //
     949              :         // This optimization likely will take more logic and state storage, so
     950              :         // for now it is not done.
     951          100 :         QueryData queryData(QType::PTR, QClass::IN, false /* unicast */);
     952          100 :         queryData.SetIsAnnounceBroadcast(true);
     953              : 
     954          156 :         for (auto & it : mOperationalResponders)
     955              :         {
     956           56 :             it.GetAllocator()->GetQueryResponder()->ClearBroadcastThrottle();
     957              :         }
     958          100 :         mQueryResponderAllocatorCommissionable.GetQueryResponder()->ClearBroadcastThrottle();
     959          100 :         mQueryResponderAllocatorCommissioner.GetQueryResponder()->ClearBroadcastThrottle();
     960              : 
     961          100 :         CHIP_ERROR err = mResponseSender.Respond(0, queryData, &packetInfo, responseConfiguration);
     962              : 
     963          100 :         if (err != CHIP_NO_ERROR)
     964              :         {
     965           30 :             ChipLogError(Discovery, "Failed to advertise records: %" CHIP_ERROR_FORMAT, err.Format());
     966              :         }
     967          100 :     }
     968              : 
     969              :     // Once all automatic broadcasts are done, allow immediate replies once.
     970           78 :     for (auto & it : mOperationalResponders)
     971              :     {
     972           28 :         it.GetAllocator()->GetQueryResponder()->ClearBroadcastThrottle();
     973              :     }
     974           50 :     mQueryResponderAllocatorCommissionable.GetQueryResponder()->ClearBroadcastThrottle();
     975           50 :     mQueryResponderAllocatorCommissioner.GetQueryResponder()->ClearBroadcastThrottle();
     976           50 : }
     977              : 
     978              : AdvertiserMinMdns gAdvertiser;
     979              : } // namespace
     980              : 
     981              : #if CHIP_DNSSD_DEFAULT_MINIMAL
     982              : 
     983            2 : ServiceAdvertiser & GetDefaultAdvertiser()
     984              : {
     985            2 :     return gAdvertiser;
     986              : }
     987              : 
     988              : #endif // CHIP_DNSSD_DEFAULT_MINIMAL
     989              : 
     990              : } // namespace Dnssd
     991              : } // namespace chip
        

Generated by: LCOV version 2.0-1