LCOV - code coverage report
Current view: top level - lib/dnssd/minimal_mdns/responders - QueryResponder.h (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 69 70 98.6 %
Date: 2024-02-15 08:20:41 Functions: 24 25 96.0 %

          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        1531 :     void Clear()
      48             :     {
      49        1531 :         responder                 = nullptr;
      50        1531 :         reportService             = false;
      51        1531 :         reportNowAsAdditional     = false;
      52        1531 :         alsoReportAdditionalQName = false;
      53        1531 :     }
      54             : };
      55             : 
      56             : } // namespace Internal
      57             : 
      58             : /// Allows building query responder configuration
      59             : class QueryResponderSettings
      60             : {
      61             : public:
      62         100 :     QueryResponderSettings() : mInfo(nullptr) {}
      63         215 :     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          77 :     QueryResponderSettings & SetReportInServiceListing(bool reportService)
      68             :     {
      69          77 :         if (IsValid())
      70             :         {
      71          77 :             mInfo->reportService = reportService;
      72             :         }
      73          77 :         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         117 :     QueryResponderSettings & SetReportAdditional(const FullQName & qname)
      82             :     {
      83         117 :         if (IsValid())
      84             :         {
      85         117 :             mInfo->alsoReportAdditionalQName = true;
      86         117 :             mInfo->additionalQName           = qname;
      87             :         }
      88         117 :         return *this;
      89             :     }
      90             : 
      91         351 :     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         560 :     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         411 :     QueryResponderRecordFilter & SetIncludeAdditionalRepliesOnly(bool includeAdditionalRepliesOnly)
     110             :     {
     111         411 :         mIncludeAdditionalRepliesOnly = includeAdditionalRepliesOnly;
     112         411 :         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         298 :     QueryResponderRecordFilter & SetReplyFilter(ReplyFilter * replyFilter)
     118             :     {
     119         298 :         mReplyFilter = replyFilter;
     120         298 :         return *this;
     121             :     }
     122             : 
     123             :     /// Filter out anything that was multicast past ms.
     124             :     /// If ms is 0, no filtering is done
     125         114 :     QueryResponderRecordFilter & SetIncludeOnlyMulticastBeforeMS(chip::System::Clock::Timestamp time)
     126             :     {
     127         114 :         mIncludeOnlyMulticastBefore = time;
     128         114 :         return *this;
     129             :     }
     130             : 
     131       10163 :     bool Accept(Internal::QueryResponderInfo * record) const
     132             :     {
     133       10163 :         if (record->responder == nullptr)
     134             :         {
     135        5031 :             return false;
     136             :         }
     137             : 
     138        5132 :         if (mIncludeAdditionalRepliesOnly && !record->reportNowAsAdditional)
     139             :         {
     140        2143 :             return false;
     141             :         }
     142             : 
     143        4155 :         if ((mIncludeOnlyMulticastBefore > chip::System::Clock::kZero) &&
     144        1166 :             (record->lastMulticastTime >= mIncludeOnlyMulticastBefore))
     145             :         {
     146           0 :             return false;
     147             :         }
     148             : 
     149        4950 :         if ((mReplyFilter != nullptr) &&
     150        1961 :             !mReplyFilter->Accept(record->responder->GetQType(), record->responder->GetQClass(), record->responder->GetQName()))
     151             :         {
     152         805 :             return false;
     153             :         }
     154        2184 :         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        3138 :     QueryResponderIterator() : mCurrent(nullptr), mRemaining(0) {}
     173         964 :     QueryResponderIterator(QueryResponderRecordFilter * recordFilter, Internal::QueryResponderInfo * pos, size_t size) :
     174         964 :         mFilter(recordFilter), mCurrent(pos), mRemaining(size)
     175             :     {
     176         964 :         SkipInvalid();
     177         964 :     }
     178             :     QueryResponderIterator(const QueryResponderIterator & other)             = default;
     179             :     QueryResponderIterator & operator=(const QueryResponderIterator & other) = default;
     180             : 
     181        2174 :     QueryResponderIterator & operator++()
     182             :     {
     183        2174 :         if (mRemaining != 0)
     184             :         {
     185        2174 :             mCurrent++;
     186        2174 :             mRemaining--;
     187             :         }
     188        2174 :         SkipInvalid();
     189        2174 :         return *this;
     190             :     }
     191             : 
     192        2174 :     QueryResponderIterator operator++(int)
     193             :     {
     194        2174 :         QueryResponderIterator tmp(*this);
     195        2174 :         operator++();
     196        2174 :         return tmp;
     197             :     }
     198             : 
     199             :     bool operator==(const QueryResponderIterator & rhs) const { return mCurrent == rhs.mCurrent; }
     200        3138 :     bool operator!=(const QueryResponderIterator & rhs) const { return mCurrent != rhs.mCurrent; }
     201             : 
     202             :     QueryResponderRecord & operator*() { return *mCurrent; }
     203        1858 :     QueryResponderRecord * operator->() { return mCurrent; }
     204             : 
     205        2168 :     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        3138 :     void SkipInvalid()
     212             :     {
     213       11117 :         while ((mRemaining > 0) && !mFilter->Accept(mCurrent))
     214             :         {
     215        7979 :             mRemaining--;
     216        7979 :             mCurrent++;
     217             :         }
     218        3138 :         if (mRemaining == 0)
     219             :         {
     220         954 :             mCurrent = nullptr;
     221             :         }
     222        3138 :     }
     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          11 :     ~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         964 :     QueryResponderIterator begin(QueryResponderRecordFilter * filter)
     259             :     {
     260         964 :         return QueryResponderIterator(filter, mResponderInfos, mResponderInfoSize);
     261             :     }
     262        3138 :     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         108 :     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 1.14