Matter SDK Coverage Report
Current view: top level - lib/dnssd/minimal_mdns/responders - QueryResponder.h (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 98.6 % 70 69
Test Date: 2025-01-17 19:00:11 Functions: 96.0 % 25 24

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2020 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              : #pragma once
      19              : 
      20              : #include "RecordResponder.h"
      21              : #include "ReplyFilter.h"
      22              : #include "Responder.h"
      23              : 
      24              : #include <system/SystemClock.h>
      25              : 
      26              : namespace mdns {
      27              : namespace Minimal {
      28              : 
      29              : /// Represents available data (replies) for mDNS queries.
      30              : struct QueryResponderRecord
      31              : {
      32              :     Responder * responder                            = nullptr; // what response/data is available
      33              :     bool reportService                               = false;   // report as a service when listing dnssd services
      34              :     chip::System::Clock::Timestamp lastMulticastTime = chip::System::Clock::kZero; // last time this record was multicast
      35              : };
      36              : 
      37              : namespace Internal {
      38              : 
      39              : /// Internal information for query responder records.
      40              : struct QueryResponderInfo : public QueryResponderRecord
      41              : {
      42              :     bool reportNowAsAdditional; // report as additional data required
      43              : 
      44              :     bool alsoReportAdditionalQName = false; // report more data when this record is listed
      45              :     FullQName additionalQName;              // if alsoReportAdditionalQName is set, send this extra data
      46              : 
      47         1510 :     void Clear()
      48              :     {
      49         1510 :         responder                 = nullptr;
      50         1510 :         reportService             = false;
      51         1510 :         reportNowAsAdditional     = false;
      52         1510 :         alsoReportAdditionalQName = false;
      53         1510 :     }
      54              : };
      55              : 
      56              : } // namespace Internal
      57              : 
      58              : /// Allows building query responder configuration
      59              : class QueryResponderSettings
      60              : {
      61              : public:
      62          100 :     QueryResponderSettings() : mInfo(nullptr) {}
      63          206 :     QueryResponderSettings(Internal::QueryResponderInfo * info) : mInfo(info) {}
      64              :     QueryResponderSettings(const QueryResponderSettings & other) = default;
      65              : 
      66              :     /// This record should be part of dns-sd service listing requests
      67           72 :     QueryResponderSettings & SetReportInServiceListing(bool reportService)
      68              :     {
      69           72 :         if (IsValid())
      70              :         {
      71           72 :             mInfo->reportService = reportService;
      72              :         }
      73           72 :         return *this;
      74              :     }
      75              : 
      76              :     /// When this record is send back, additional records should also be provided.
      77              :     ///
      78              :     /// This is useful to avoid chattyness by sending back referenced records
      79              :     /// (e.g. when sending a PTR record, send the corresponding SRV and when sending
      80              :     ///  SRV, send back the corresponding A/AAAA records).
      81          110 :     QueryResponderSettings & SetReportAdditional(const FullQName & qname)
      82              :     {
      83          110 :         if (IsValid())
      84              :         {
      85          110 :             mInfo->alsoReportAdditionalQName = true;
      86          110 :             mInfo->additionalQName           = qname;
      87              :         }
      88          110 :         return *this;
      89              :     }
      90              : 
      91          330 :     bool IsValid() const { return mInfo != nullptr; }
      92              : 
      93              : private:
      94              :     Internal::QueryResponderInfo * mInfo;
      95              : };
      96              : 
      97              : /// Determines what query records should be included in a response.
      98              : ///
      99              : /// Provides an 'Accept' method to determine if a reply is to be sent or not.
     100              : class QueryResponderRecordFilter
     101              : {
     102              : public:
     103              :     /// Default contstructor accepts everything that is not null
     104          520 :     QueryResponderRecordFilter() {}
     105              :     QueryResponderRecordFilter(const QueryResponderRecordFilter & other)             = default;
     106              :     QueryResponderRecordFilter & operator=(const QueryResponderRecordFilter & other) = default;
     107              : 
     108              :     /// Set if to include only items marked as 'additional reply' or everything.
     109          385 :     QueryResponderRecordFilter & SetIncludeAdditionalRepliesOnly(bool includeAdditionalRepliesOnly)
     110              :     {
     111          385 :         mIncludeAdditionalRepliesOnly = includeAdditionalRepliesOnly;
     112          385 :         return *this;
     113              :     }
     114              : 
     115              :     /// Filter out anything rejected by the given reply filter.
     116              :     /// If replyFilter is nullptr, no such filtering is applied.
     117          270 :     QueryResponderRecordFilter & SetReplyFilter(ReplyFilter * replyFilter)
     118              :     {
     119          270 :         mReplyFilter = replyFilter;
     120          270 :         return *this;
     121              :     }
     122              : 
     123              :     /// Filter out anything that was multicast past ms.
     124              :     /// If ms is 0, no filtering is done
     125          100 :     QueryResponderRecordFilter & SetIncludeOnlyMulticastBeforeMS(chip::System::Clock::Timestamp time)
     126              :     {
     127          100 :         mIncludeOnlyMulticastBefore = time;
     128          100 :         return *this;
     129              :     }
     130              : 
     131         9339 :     bool Accept(Internal::QueryResponderInfo * record) const
     132              :     {
     133         9339 :         if (record->responder == nullptr)
     134              :         {
     135         4499 :             return false;
     136              :         }
     137              : 
     138         4840 :         if (mIncludeAdditionalRepliesOnly && !record->reportNowAsAdditional)
     139              :         {
     140         2007 :             return false;
     141              :         }
     142              : 
     143         3917 :         if ((mIncludeOnlyMulticastBefore > chip::System::Clock::kZero) &&
     144         1084 :             (record->lastMulticastTime >= mIncludeOnlyMulticastBefore))
     145              :         {
     146            0 :             return false;
     147              :         }
     148              : 
     149         4686 :         if ((mReplyFilter != nullptr) &&
     150         1853 :             !mReplyFilter->Accept(record->responder->GetQType(), record->responder->GetQClass(), record->responder->GetQName()))
     151              :         {
     152          781 :             return false;
     153              :         }
     154         2052 :         return true;
     155              :     }
     156              : 
     157              : private:
     158              :     bool mIncludeAdditionalRepliesOnly                         = false;
     159              :     ReplyFilter * mReplyFilter                                 = nullptr;
     160              :     chip::System::Clock::Timestamp mIncludeOnlyMulticastBefore = chip::System::Clock::kZero;
     161              : };
     162              : 
     163              : /// Iterates over an array of QueryResponderRecord items, providing only 'valid' ones, where
     164              : /// valid is based on the provided filter.
     165              : class QueryResponderIterator
     166              : {
     167              : public:
     168              :     using value_type = QueryResponderRecord;
     169              :     using pointer    = QueryResponderRecord *;
     170              :     using reference  = QueryResponderRecord &;
     171              : 
     172         2936 :     QueryResponderIterator() : mCurrent(nullptr), mRemaining(0) {}
     173          894 :     QueryResponderIterator(QueryResponderRecordFilter * recordFilter, Internal::QueryResponderInfo * pos, size_t size) :
     174          894 :         mFilter(recordFilter), mCurrent(pos), mRemaining(size)
     175              :     {
     176          894 :         SkipInvalid();
     177          894 :     }
     178              :     QueryResponderIterator(const QueryResponderIterator & other)             = default;
     179              :     QueryResponderIterator & operator=(const QueryResponderIterator & other) = default;
     180              : 
     181         2042 :     QueryResponderIterator & operator++()
     182              :     {
     183         2042 :         if (mRemaining != 0)
     184              :         {
     185         2042 :             mCurrent++;
     186         2042 :             mRemaining--;
     187              :         }
     188         2042 :         SkipInvalid();
     189         2042 :         return *this;
     190              :     }
     191              : 
     192         2042 :     QueryResponderIterator operator++(int)
     193              :     {
     194         2042 :         QueryResponderIterator tmp(*this);
     195         2042 :         operator++();
     196         2042 :         return tmp;
     197              :     }
     198              : 
     199              :     bool operator==(const QueryResponderIterator & rhs) const { return mCurrent == rhs.mCurrent; }
     200         2936 :     bool operator!=(const QueryResponderIterator & rhs) const { return mCurrent != rhs.mCurrent; }
     201              : 
     202              :     QueryResponderRecord & operator*() { return *mCurrent; }
     203         1716 :     QueryResponderRecord * operator->() { return mCurrent; }
     204              : 
     205         2044 :     Internal::QueryResponderInfo * GetInternal() { return mCurrent; }
     206              :     const Internal::QueryResponderInfo * GetInternal() const { return mCurrent; }
     207              : 
     208              : private:
     209              :     /// Skips invalid/not useful values.
     210              :     /// ensures that if mRemaining is 0, mCurrent is nullptr;
     211         2936 :     void SkipInvalid()
     212              :     {
     213        10223 :         while ((mRemaining > 0) && !mFilter->Accept(mCurrent))
     214              :         {
     215         7287 :             mRemaining--;
     216         7287 :             mCurrent++;
     217              :         }
     218         2936 :         if (mRemaining == 0)
     219              :         {
     220          884 :             mCurrent = nullptr;
     221              :         }
     222         2936 :     }
     223              : 
     224              :     QueryResponderRecordFilter * mFilter;
     225              :     Internal::QueryResponderInfo * mCurrent;
     226              :     size_t mRemaining;
     227              : };
     228              : 
     229              : /// Responds to mDNS queries.
     230              : ///
     231              : /// In particular:
     232              : ///   - replies data as provided by the underlying responders
     233              : ///   - replies to "_services._dns-sd._udp.local."
     234              : ///
     235              : /// Maintains a stateful list of 'additional replies' that can be marked/unmarked
     236              : /// for query processing
     237              : class QueryResponderBase : public Responder // "_services._dns-sd._udp.local"
     238              : {
     239              : public:
     240              :     /// Builds a new responder with the given storage for the response infos
     241              :     QueryResponderBase(Internal::QueryResponderInfo * infos, size_t infoSizes);
     242           13 :     ~QueryResponderBase() override {}
     243              : 
     244              :     /// Setup initial settings (clears all infos and sets up dns-sd query replies)
     245              :     void Init();
     246              : 
     247              :     /// Add a new responder to be processed
     248              :     ///
     249              :     /// Return valid QueryResponderSettings on add success.
     250              :     QueryResponderSettings AddResponder(RecordResponder * responder);
     251              : 
     252              :     /// Implementation of the responder delegate.
     253              :     ///
     254              :     /// Adds responses for all known _dns-sd services.
     255              :     void AddAllResponses(const chip::Inet::IPPacketInfo * source, ResponderDelegate * delegate,
     256              :                          const ResponseConfiguration & configuration) override;
     257              : 
     258          894 :     QueryResponderIterator begin(QueryResponderRecordFilter * filter)
     259              :     {
     260          894 :         return QueryResponderIterator(filter, mResponderInfos, mResponderInfoSize);
     261              :     }
     262         2936 :     QueryResponderIterator end() { return QueryResponderIterator(); }
     263              : 
     264              :     /// Clear any items marked as 'additional'.
     265              :     void ResetAdditionals();
     266              : 
     267              :     /// Marks queries matching this qname as 'to be additionally reported'
     268              :     /// @return the number of items marked new as 'additional data'.
     269              :     size_t MarkAdditional(const FullQName & qname);
     270              : 
     271              :     /// Flag any additional responses required for the given iterator
     272              :     void MarkAdditionalRepliesFor(QueryResponderIterator it);
     273              : 
     274              :     /// Resets the internal broadcast throttle setting to allow re-broadcasting
     275              :     /// of all packets without a timedelay.
     276              :     void ClearBroadcastThrottle();
     277              : 
     278              : private:
     279              :     Internal::QueryResponderInfo * mResponderInfos;
     280              :     size_t mResponderInfoSize;
     281              : };
     282              : 
     283              : template <size_t kSize>
     284              : class QueryResponder : public QueryResponderBase
     285              : {
     286              : public:
     287          134 :     QueryResponder() : QueryResponderBase(mData, kSize) { Init(); }
     288              : 
     289              : private:
     290              :     Internal::QueryResponderInfo mData[kSize];
     291              : };
     292              : 
     293              : } // namespace Minimal
     294              : } // namespace mdns
        

Generated by: LCOV version 2.0-1