LCOV - code coverage report
Current view: top level - app - ReadHandler.h (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 38 40 95.0 %
Date: 2024-02-15 08:20:41 Functions: 28 32 87.5 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2020 Project CHIP Authors
       4             :  *    All rights reserved.
       5             :  *
       6             :  *    Licensed under the Apache License, Version 2.0 (the "License");
       7             :  *    you may not use this file except in compliance with the License.
       8             :  *    You may obtain a copy of the License at
       9             :  *
      10             :  *        http://www.apache.org/licenses/LICENSE-2.0
      11             :  *
      12             :  *    Unless required by applicable law or agreed to in writing, software
      13             :  *    distributed under the License is distributed on an "AS IS" BASIS,
      14             :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15             :  *    See the License for the specific language governing permissions and
      16             :  *    limitations under the License.
      17             :  */
      18             : 
      19             : /**
      20             :  *    @file
      21             :  *     This file defines read handler for a CHIP Interaction Data model
      22             :  *
      23             :  */
      24             : 
      25             : #pragma once
      26             : 
      27             : #include <access/AccessControl.h>
      28             : #include <app/AttributeAccessInterface.h>
      29             : #include <app/AttributePathExpandIterator.h>
      30             : #include <app/AttributePathParams.h>
      31             : #include <app/CASESessionManager.h>
      32             : #include <app/DataVersionFilter.h>
      33             : #include <app/EventManagement.h>
      34             : #include <app/EventPathParams.h>
      35             : #include <app/MessageDef/AttributePathIBs.h>
      36             : #include <app/MessageDef/DataVersionFilterIBs.h>
      37             : #include <app/MessageDef/EventFilterIBs.h>
      38             : #include <app/MessageDef/EventPathIBs.h>
      39             : #include <app/ObjectList.h>
      40             : #include <app/OperationalSessionSetup.h>
      41             : #include <app/SubscriptionResumptionSessionEstablisher.h>
      42             : #include <app/SubscriptionResumptionStorage.h>
      43             : #include <lib/core/CHIPCallback.h>
      44             : #include <lib/core/CHIPCore.h>
      45             : #include <lib/core/TLVDebug.h>
      46             : #include <lib/support/CodeUtils.h>
      47             : #include <lib/support/DLLUtil.h>
      48             : #include <lib/support/logging/CHIPLogging.h>
      49             : #include <messaging/ExchangeHolder.h>
      50             : #include <messaging/ExchangeMgr.h>
      51             : #include <messaging/Flags.h>
      52             : #include <protocols/Protocols.h>
      53             : #include <system/SystemPacketBuffer.h>
      54             : 
      55             : // https://github.com/CHIP-Specifications/connectedhomeip-spec/blob/61a9d19e6af12fdfb0872bcff26d19de6c680a1a/src/Ch02_Architecture.adoc#1122-subscribe-interaction-limits
      56             : inline constexpr uint16_t kSubscriptionMaxIntervalPublisherLimit = 3600; // seconds (60 minutes)
      57             : 
      58             : namespace chip {
      59             : namespace app {
      60             : 
      61             : //
      62             : // Forward declare the Engine (which is in a different namespace) to be able to use
      63             : // it as a friend class below.
      64             : //
      65             : namespace reporting {
      66             : class Engine;
      67             : class TestReportingEngine;
      68             : class ReportScheduler;
      69             : class TestReportScheduler;
      70             : } // namespace reporting
      71             : 
      72             : class InteractionModelEngine;
      73             : 
      74             : /**
      75             :  *  @class ReadHandler
      76             :  *
      77             :  *  @brief The read handler is responsible for processing a read request, asking the attribute/event store
      78             :  *         for the relevant data, and sending a reply.
      79             :  *
      80             :  */
      81             : class ReadHandler : public Messaging::ExchangeDelegate
      82             : {
      83             : public:
      84             :     using SubjectDescriptor = Access::SubjectDescriptor;
      85             : 
      86             :     enum class InteractionType : uint8_t
      87             :     {
      88             :         Read,
      89             :         Subscribe,
      90             :     };
      91             : 
      92             :     /*
      93             :      * A callback used to interact with the application.
      94             :      */
      95             :     class ApplicationCallback
      96             :     {
      97             :     public:
      98             :         virtual ~ApplicationCallback() = default;
      99             : 
     100             :         /*
     101             :          * Called right after a SubscribeRequest has been parsed and processed. This notifies an interested application
     102             :          * of a subscription that is about to be established. It also provides an avenue for altering the parameters of the
     103             :          * subscription (specifically, the min/max negotiated intervals) or even outright rejecting the subscription for
     104             :          * application-specific reasons.
     105             :          *
     106             :          * TODO: Need a new IM status code to convey application-rejected subscribes. Currently, a Failure IM status code is sent
     107             :          * back to the subscriber, which isn't sufficient.
     108             :          *
     109             :          * To reject the subscription, a CHIP_ERROR code that is not equivalent to CHIP_NO_ERROR should be returned.
     110             :          *
     111             :          * More information about the set of paths associated with this subscription can be retrieved by calling the appropriate
     112             :          * Get* methods below.
     113             :          *
     114             :          * aReadHandler:            Reference to the ReadHandler associated with the subscription.
     115             :          * aSecureSession:          A reference to the underlying secure session associated with the subscription.
     116             :          *
     117             :          */
     118             :         virtual CHIP_ERROR OnSubscriptionRequested(ReadHandler & aReadHandler, Transport::SecureSession & aSecureSession)
     119             :         {
     120             :             return CHIP_NO_ERROR;
     121             :         }
     122             : 
     123             :         /*
     124             :          * Called after a subscription has been fully established.
     125             :          */
     126             :         virtual void OnSubscriptionEstablished(ReadHandler & aReadHandler){};
     127             : 
     128             :         /*
     129             :          * Called right before a subscription is about to get terminated. This is only called on subscriptions that were terminated
     130             :          * after they had been fully established (and therefore had called OnSubscriptionEstablished).
     131             :          * OnSubscriptionEstablishment().
     132             :          */
     133             :         virtual void OnSubscriptionTerminated(ReadHandler & aReadHandler){};
     134             :     };
     135             : 
     136             :     /*
     137             :      * A callback used to manage the lifetime of the ReadHandler object.
     138             :      */
     139             :     class ManagementCallback
     140             :     {
     141             :     public:
     142          23 :         virtual ~ManagementCallback() = default;
     143             : 
     144             :         /*
     145             :          * Method that signals to a registered callback that this object
     146             :          * has completed doing useful work and is now safe for release/destruction.
     147             :          */
     148             :         virtual void OnDone(ReadHandler & apReadHandlerObj) = 0;
     149             : 
     150             :         /*
     151             :          * Retrieve the ApplicationCallback (if a valid one exists) from our management entity. This avoids
     152             :          * storing multiple references to the application provided callback and having to subsequently manage lifetime
     153             :          * issues w.r.t the ReadHandler itself.
     154             :          */
     155             :         virtual ApplicationCallback * GetAppCallback() = 0;
     156             : 
     157             :         /*
     158             :          * Retrieve the InteractionalModelEngine that holds this ReadHandler.
     159             :          */
     160             :         virtual InteractionModelEngine * GetInteractionModelEngine() = 0;
     161             :     };
     162             : 
     163             :     // TODO (#27675) : Merge existing callback and observer into one class and have an observer pool in the Readhandler to notify
     164             :     // every
     165             :     /*
     166             :      * Observer class for ReadHandler, meant to allow multiple objects to observe the ReadHandler. Currently only one observer is
     167             :      * supported but all above callbacks should be merged into observer type and an observer pool should be added to allow multiple
     168             :      * objects to observe ReadHandler
     169             :      */
     170             :     class Observer
     171             :     {
     172             :     public:
     173           0 :         virtual ~Observer() = default;
     174             : 
     175             :         /// @brief Callback invoked to notify a subscription was successfully established for the ReadHandler
     176             :         /// @param[in] apReadHandler  ReadHandler that completed its subscription
     177             :         virtual void OnSubscriptionEstablished(ReadHandler * apReadHandler) = 0;
     178             : 
     179             :         /// @brief Callback invoked when a ReadHandler went from a non reportable state to a reportable state. Indicates to the
     180             :         /// observer that a report should be emitted when the min interval allows it.
     181             :         ///
     182             :         /// This will only be invoked for subscribe-type ReadHandler objects, and only after
     183             :         /// OnSubscriptionEstablished has been called.
     184             :         ///
     185             :         /// @param[in] apReadHandler  ReadHandler that became dirty and in HandlerState::CanStartReporting state
     186             :         virtual void OnBecameReportable(ReadHandler * apReadHandler) = 0;
     187             : 
     188             :         /// @brief Callback invoked when the read handler needs to make sure to send a message to the subscriber within the next
     189             :         /// maxInterval time period.
     190             :         /// @param[in] apReadHandler ReadHandler that has generated a report
     191             :         virtual void OnSubscriptionReportSent(ReadHandler * apReadHandler) = 0;
     192             : 
     193             :         /// @brief Callback invoked when a ReadHandler is getting removed so it can be unregistered
     194             :         /// @param[in] apReadHandler  ReadHandler getting destroyed
     195             :         virtual void OnReadHandlerDestroyed(ReadHandler * apReadHandler) = 0;
     196             :     };
     197             : 
     198             :     /*
     199             :      * Destructor - as part of destruction, it will abort the exchange context
     200             :      * if a valid one still exists.
     201             :      *
     202             :      * See Abort() for details on when that might occur.
     203             :      */
     204             :     ~ReadHandler() override;
     205             : 
     206             :     /**
     207             :      *
     208             :      *  Constructor.
     209             :      *
     210             :      *  The callback passed in has to outlive this handler object.
     211             :      *
     212             :      */
     213             :     ReadHandler(ManagementCallback & apCallback, Messaging::ExchangeContext * apExchangeContext, InteractionType aInteractionType,
     214             :                 Observer * observer);
     215             : 
     216             : #if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
     217             :     /**
     218             :      *
     219             :      *  Constructor in preparation for resuming a persisted subscription
     220             :      *
     221             :      *  The callback passed in has to outlive this handler object.
     222             :      *
     223             :      */
     224             :     ReadHandler(ManagementCallback & apCallback, Observer * observer);
     225             : #endif
     226             : 
     227         477 :     const ObjectList<AttributePathParams> * GetAttributePathList() const { return mpAttributePathList; }
     228        2738 :     const ObjectList<EventPathParams> * GetEventPathList() const { return mpEventPathList; }
     229        3494 :     const ObjectList<DataVersionFilter> * GetDataVersionFilterList() const { return mpDataVersionFilterList; }
     230             : 
     231          64 :     void GetReportingIntervals(uint16_t & aMinInterval, uint16_t & aMaxInterval) const
     232             :     {
     233          64 :         aMinInterval = mMinIntervalFloorSeconds;
     234          64 :         aMaxInterval = mMaxInterval;
     235          64 :     }
     236             : 
     237             :     CHIP_ERROR SetMinReportingIntervalForTests(uint16_t aMinInterval)
     238             :     {
     239             :         VerifyOrReturnError(IsIdle(), CHIP_ERROR_INCORRECT_STATE);
     240             :         VerifyOrReturnError(aMinInterval <= mMaxInterval, CHIP_ERROR_INVALID_ARGUMENT);
     241             :         // Ensures the new min interval is higher than the subscriber established one.
     242             :         mMinIntervalFloorSeconds = std::max(mMinIntervalFloorSeconds, aMinInterval);
     243             :         return CHIP_NO_ERROR;
     244             :     }
     245             : 
     246             :     /*
     247             :      * Set the maximum reporting interval for the subscription. This SHALL only be called
     248             :      * from the OnSubscriptionRequested callback above. The restriction is as below
     249             :      * MinIntervalFloor ≤ MaxInterval ≤ MAX(SUBSCRIPTION_MAX_INTERVAL_PUBLISHER_LIMIT, MaxIntervalCeiling)
     250             :      * Where SUBSCRIPTION_MAX_INTERVAL_PUBLISHER_LIMIT is set to 60m in the spec.
     251             :      */
     252             :     CHIP_ERROR SetMaxReportingInterval(uint16_t aMaxInterval)
     253             :     {
     254             :         VerifyOrReturnError(IsIdle(), CHIP_ERROR_INCORRECT_STATE);
     255             :         VerifyOrReturnError(mMinIntervalFloorSeconds <= aMaxInterval, CHIP_ERROR_INVALID_ARGUMENT);
     256             :         VerifyOrReturnError(aMaxInterval <= std::max(GetPublisherSelectedIntervalLimit(), mMaxInterval),
     257             :                             CHIP_ERROR_INVALID_ARGUMENT);
     258             :         mMaxInterval = aMaxInterval;
     259             :         return CHIP_NO_ERROR;
     260             :     }
     261             : 
     262             : #if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
     263             :     /**
     264             :      *
     265             :      *  @brief Initialize a ReadHandler for a resumed subsciption
     266             :      *
     267             :      *  Used after the SubscriptionResumptionSessionEstablisher establishs the CASE session
     268             :      */
     269             :     void OnSubscriptionResumed(const SessionHandle & sessionHandle, SubscriptionResumptionSessionEstablisher & sessionEstablisher);
     270             : #endif
     271             : 
     272             : private:
     273             :     PriorityLevel GetCurrentPriority() const { return mCurrentPriority; }
     274        1835 :     EventNumber & GetEventMin() { return mEventMin; }
     275             : 
     276             :     /**
     277             :      * Returns SUBSCRIPTION_MAX_INTERVAL_PUBLISHER_LIMIT
     278             :      * For an ICD publisher, this SHALL be set to the idle mode duration.
     279             :      * Otherwise, this SHALL be set to 60 minutes.
     280             :      */
     281             :     uint16_t GetPublisherSelectedIntervalLimit();
     282             : 
     283             :     enum class ReadHandlerFlags : uint8_t
     284             :     {
     285             :         // The flag indicating we are in the middle of a series of chunked report messages, this flag will be cleared during
     286             :         // sending last chunked message.
     287             :         ChunkedReport = (1 << 0),
     288             : 
     289             :         // Tracks whether we're in the initial phase of receiving priming
     290             :         // reports, which is always true for reads and true for subscriptions
     291             :         // prior to receiving a subscribe response.
     292             :         PrimingReports     = (1 << 1),
     293             :         ActiveSubscription = (1 << 2),
     294             :         FabricFiltered     = (1 << 3),
     295             :         // For subscriptions, we record the dirty set generation when we started to generate the last report.
     296             :         // The mCurrentReportsBeginGeneration records the generation at the start of the current report.  This only/
     297             :         // has a meaningful value while IsReporting() is true.
     298             :         //
     299             :         // mPreviousReportsBeginGeneration will be set to mCurrentReportsBeginGeneration after we send the last
     300             :         // chunk of the current report.  Anything that was dirty with a generation earlier than
     301             :         // mPreviousReportsBeginGeneration has had its value sent to the client.
     302             :         // when receiving initial request, it needs mark current handler as dirty.
     303             :         // when there is urgent event, it needs mark current handler as dirty.
     304             :         ForceDirty = (1 << 4),
     305             : 
     306             :         // Don't need the response for report data if true
     307             :         SuppressResponse = (1 << 5),
     308             :     };
     309             : 
     310             :     /**
     311             :      *  Process a read/subscribe request.  Parts of the processing may end up being asynchronous, but the ReadHandler
     312             :      *  guarantees that it will call Shutdown on itself when processing is done (including if OnReadInitialRequest
     313             :      *  returns an error).
     314             :      *
     315             :      *  @retval #Others If fails to process read request
     316             :      *  @retval #CHIP_NO_ERROR On success.
     317             :      *
     318             :      */
     319             :     void OnInitialRequest(System::PacketBufferHandle && aPayload);
     320             : 
     321             :     /**
     322             :      *  Send ReportData to initiator
     323             :      *
     324             :      *  @param[in]    aPayload             A payload that has read request data
     325             :      *  @param[in]    aMoreChunks          A flags indicating there will be more chunks expected to be sent for this read request
     326             :      *
     327             :      *  @retval #Others If fails to send report data
     328             :      *  @retval #CHIP_NO_ERROR On success.
     329             :      *
     330             :      *  If an error is returned, the ReadHandler guarantees that it is not in
     331             :      *  a state where it's waiting for a response.
     332             :      */
     333             :     CHIP_ERROR SendReportData(System::PacketBufferHandle && aPayload, bool aMoreChunks);
     334             : 
     335             :     /**
     336             :      *  Returns whether this ReadHandler represents a subscription that was created by the other side of the provided exchange.
     337             :      */
     338             :     bool IsFromSubscriber(Messaging::ExchangeContext & apExchangeContext) const;
     339             : 
     340             :     bool IsIdle() const { return mState == HandlerState::Idle; }
     341             : 
     342             :     /// @brief Returns whether the ReadHandler is in a state where it can send a report and there is data to report.
     343        8016 :     bool ShouldStartReporting() const
     344             :     {
     345             :         // Important: Anything that changes ShouldStartReporting() from false to true
     346             :         // (which can only happen for subscriptions) must call
     347             :         // mObserver->OnBecameReportable(this).
     348        8016 :         return CanStartReporting() && (ShouldReportUnscheduled() || IsDirty());
     349             :     }
     350             :     /// @brief CanStartReporting() is true if the ReadHandler is in a state where it could generate
     351             :     /// a (possibly empty) report if someone asked it to.
     352       15745 :     bool CanStartReporting() const { return mState == HandlerState::CanStartReporting; }
     353             :     /// @brief ShouldReportUnscheduled() is true if the ReadHandler should be asked to generate reports
     354             :     /// without consulting the report scheduler.
     355        7123 :     bool ShouldReportUnscheduled() const
     356             :     {
     357        7123 :         return CanStartReporting() && (IsType(ReadHandler::InteractionType::Read) || IsPriming());
     358             :     }
     359        7044 :     bool IsAwaitingReportResponse() const { return mState == HandlerState::AwaitingReportResponse; }
     360             : 
     361             :     // Resets the path iterator to the beginning of the whole report for generating a series of new reports.
     362             :     void ResetPathIterator();
     363             : 
     364             :     CHIP_ERROR ProcessDataVersionFilterList(DataVersionFilterIBs::Parser & aDataVersionFilterListParser);
     365             : 
     366             :     // if current priority is in the middle, it has valid snapshoted last event number, it check cleaness via comparing
     367             :     // with snapshotted last event number. if current priority  is in the end, no valid
     368             :     // sanpshotted last event, check with latest last event number, re-setup snapshoted checkpoint, and compare again.
     369             :     bool CheckEventClean(EventManagement & aEventManager);
     370             : 
     371       20952 :     bool IsType(InteractionType type) const { return (mInteractionType == type); }
     372        1445 :     bool IsChunkedReport() const { return mFlags.Has(ReadHandlerFlags::ChunkedReport); }
     373             :     // Is reporting indicates whether we are in the middle of a series chunks. As we will set mIsChunkedReport on the first chunk
     374             :     // and clear that flag on the last chunk, we can use mIsChunkedReport to indicate this state.
     375        3637 :     bool IsReporting() const { return mFlags.Has(ReadHandlerFlags::ChunkedReport); }
     376        6903 :     bool IsPriming() const { return mFlags.Has(ReadHandlerFlags::PrimingReports); }
     377           0 :     bool IsActiveSubscription() const { return mFlags.Has(ReadHandlerFlags::ActiveSubscription); }
     378        3697 :     bool IsFabricFiltered() const { return mFlags.Has(ReadHandlerFlags::FabricFiltered); }
     379             :     CHIP_ERROR OnSubscribeRequest(Messaging::ExchangeContext * apExchangeContext, System::PacketBufferHandle && aPayload);
     380         370 :     void GetSubscriptionId(SubscriptionId & aSubscriptionId) const { aSubscriptionId = mSubscriptionId; }
     381        9355 :     AttributePathExpandIterator * GetAttributePathExpandIterator() { return &mAttributePathExpandIterator; }
     382             : 
     383             :     /// @brief Notifies the read handler that a set of attribute paths has been marked dirty. This will schedule a reporting engine
     384             :     /// run if the change to the attribute path makes the ReadHandler reportable.
     385             :     /// @param aAttributeChanged Path to the attribute that was changed.
     386             :     void AttributePathIsDirty(const AttributePathParams & aAttributeChanged);
     387        2818 :     bool IsDirty() const
     388             :     {
     389        2818 :         return (mDirtyGeneration > mPreviousReportsBeginGeneration) || mFlags.Has(ReadHandlerFlags::ForceDirty);
     390             :     }
     391         941 :     void ClearForceDirtyFlag() { ClearStateFlag(ReadHandlerFlags::ForceDirty); }
     392          11 :     NodeId GetInitiatorNodeId() const
     393             :     {
     394          11 :         auto session = GetSession();
     395          11 :         return session == nullptr ? kUndefinedNodeId : session->GetPeerNodeId();
     396             :     }
     397             : 
     398         232 :     FabricIndex GetAccessingFabricIndex() const
     399             :     {
     400         232 :         auto session = GetSession();
     401         232 :         return session == nullptr ? kUndefinedFabricIndex : session->GetFabricIndex();
     402             :     }
     403             : 
     404             :     Transport::SecureSession * GetSession() const;
     405        4622 :     SubjectDescriptor GetSubjectDescriptor() const { return GetSession()->GetSubjectDescriptor(); }
     406             : 
     407          82 :     auto GetTransactionStartGeneration() const { return mTransactionStartGeneration; }
     408             : 
     409             :     /// @brief Forces the read handler into a dirty state, regardless of what's going on with attributes.
     410             :     /// This can lead to scheduling of a reporting run immediately, if the min interval has been reached,
     411             :     /// or after the min interval is reached if it has not yet been reached.
     412             :     void ForceDirtyState();
     413             : 
     414        3697 :     const AttributeValueEncoder::AttributeEncodeState & GetAttributeEncodeState() const { return mAttributeEncoderState; }
     415        3697 :     void SetAttributeEncodeState(const AttributeValueEncoder::AttributeEncodeState & aState) { mAttributeEncoderState = aState; }
     416          20 :     uint32_t GetLastWrittenEventsBytes() const { return mLastWrittenEventsBytes; }
     417             : 
     418             :     // Returns the number of interested paths, including wildcard and concrete paths.
     419        4513 :     size_t GetAttributePathCount() const { return mpAttributePathList == nullptr ? 0 : mpAttributePathList->Count(); };
     420        4513 :     size_t GetEventPathCount() const { return mpEventPathList == nullptr ? 0 : mpEventPathList->Count(); };
     421             :     size_t GetDataVersionFilterCount() const { return mpDataVersionFilterList == nullptr ? 0 : mpDataVersionFilterList->Count(); };
     422             : 
     423             :     CHIP_ERROR SendStatusReport(Protocols::InteractionModel::Status aStatus);
     424             : 
     425             :     friend class TestReadInteraction;
     426             :     friend class chip::app::reporting::TestReportingEngine;
     427             :     friend class chip::app::reporting::TestReportScheduler;
     428             : 
     429             :     //
     430             :     // The engine needs to be able to Abort/Close a ReadHandler instance upon completion of work for a given read/subscribe
     431             :     // interaction. We do not want to make these methods public just to give an adjacent class in the IM access, since public
     432             :     // should really be taking application usage considerations as well. Hence, make it a friend.
     433             :     //
     434             :     friend class chip::app::reporting::Engine;
     435             :     friend class chip::app::InteractionModelEngine;
     436             : 
     437             :     // The report scheduler needs to be able to access StateFlag private functions ShouldStartReporting(), CanStartReporting(),
     438             :     // ForceDirtyState() and IsDirty() to know when to schedule a run so it is declared as a friend class.
     439             :     friend class chip::app::reporting::ReportScheduler;
     440             : 
     441             :     enum class HandlerState : uint8_t
     442             :     {
     443             :         Idle,                   ///< The handler has been initialized and is ready
     444             :         CanStartReporting,      ///< The handler has is now capable of generating reports and may generate one immediately
     445             :                                 ///< or later when other criteria are satisfied (e.g hold-off for min reporting interval).
     446             :         AwaitingReportResponse, ///< The handler has sent the report to the client and is awaiting a status response.
     447             :         AwaitingDestruction,    ///< The object has completed its work and is awaiting destruction by the application.
     448             :     };
     449             : 
     450             :     enum class CloseOptions
     451             :     {
     452             :         kDropPersistedSubscription,
     453             :         kKeepPersistedSubscription
     454             :     };
     455             :     /**
     456             :      * Called internally to signal the completion of all work on this objecta and signal to a registered callback that it's
     457             :      * safe to release this object.
     458             :      *
     459             :      *  @param    options             This specifies whether to drop or keep the subscription
     460             :      *
     461             :      */
     462             :     void Close(CloseOptions options = CloseOptions::kDropPersistedSubscription);
     463             : 
     464             :     CHIP_ERROR SendSubscribeResponse();
     465             :     CHIP_ERROR ProcessSubscribeRequest(System::PacketBufferHandle && aPayload);
     466             :     CHIP_ERROR ProcessReadRequest(System::PacketBufferHandle && aPayload);
     467             :     CHIP_ERROR ProcessAttributePaths(AttributePathIBs::Parser & aAttributePathListParser);
     468             :     CHIP_ERROR ProcessEventPaths(EventPathIBs::Parser & aEventPathsParser);
     469             :     CHIP_ERROR ProcessEventFilters(EventFilterIBs::Parser & aEventFiltersParser);
     470             :     CHIP_ERROR OnStatusResponse(Messaging::ExchangeContext * apExchangeContext, System::PacketBufferHandle && aPayload,
     471             :                                 bool & aSendStatusResponse);
     472             :     CHIP_ERROR OnMessageReceived(Messaging::ExchangeContext * apExchangeContext, const PayloadHeader & aPayloadHeader,
     473             :                                  System::PacketBufferHandle && aPayload) override;
     474             :     void OnResponseTimeout(Messaging::ExchangeContext * apExchangeContext) override;
     475             :     void MoveToState(const HandlerState aTargetState);
     476             : 
     477             :     const char * GetStateStr() const;
     478             : 
     479             :     void PersistSubscription();
     480             : 
     481             :     /// @brief Modifies a state flag in the read handler. If the read handler went from a
     482             :     /// non-reportable state to a reportable state, schedules a reporting engine run.
     483             :     /// @param aFlag Flag to set
     484             :     /// @param aValue Flag new value
     485             :     void SetStateFlag(ReadHandlerFlags aFlag, bool aValue = true);
     486             : 
     487             :     /// @brief This function call SetStateFlag with the flag value set to false, thus possibly emitting a report
     488             :     /// generation.
     489             :     /// @param aFlag Flag to clear
     490             :     void ClearStateFlag(ReadHandlerFlags aFlag);
     491             : 
     492             :     AttributePathExpandIterator mAttributePathExpandIterator = AttributePathExpandIterator(nullptr);
     493             : 
     494             :     // The current generation of the reporting engine dirty set the last time we were notified that a path we're interested in was
     495             :     // marked dirty.
     496             :     //
     497             :     // This allows us to detemine whether any paths we care about might have
     498             :     // been marked dirty after we had already sent reports for them, which would
     499             :     // mean we should report those paths again, by comparing this generation to the
     500             :     // current generation when we started sending the last set reports that we completed.
     501             :     //
     502             :     // This allows us to reset the iterator to the beginning of the current
     503             :     // cluster instead of the beginning of the whole report in AttributePathIsDirty, without
     504             :     // permanently missing dirty any paths.
     505             :     uint64_t mDirtyGeneration = 0;
     506             : 
     507             :     // For subscriptions, we record the timestamp when we started to generate the last report.
     508             :     // The mCurrentReportsBeginGeneration records the timestamp for the current report, which won;t be used for checking if this
     509             :     // ReadHandler is dirty.
     510             :     // mPreviousReportsBeginGeneration will be set to mCurrentReportsBeginGeneration after we sent the last chunk of the current
     511             :     // report.
     512             :     uint64_t mPreviousReportsBeginGeneration = 0;
     513             :     uint64_t mCurrentReportsBeginGeneration  = 0;
     514             :     /*
     515             :      *           (mDirtyGeneration = b > a, this is a dirty read handler)
     516             :      *        +- Start Report -> mCurrentReportsBeginGeneration = c
     517             :      *        |      +- AttributePathIsDirty (Attribute Y) -> mDirtyGeneration = d
     518             :      *        |      |     +- Last Chunk -> mPreviousReportsBeginGeneration = mCurrentReportsBeginGeneration = c
     519             :      *        |      |     |   +- (mDirtyGeneration = d) > (mPreviousReportsBeginGeneration = c), this is a dirty read handler
     520             :      *        |      |     |   |  Attribute X has a dirty generation less than c, Attribute Y has a dirty generation larger than c
     521             :      *        |      |     |   |  So Y will be included in the report but X will not be inclued in this report.
     522             :      * -a--b--c------d-----e---f---> Generation
     523             :      *  |  |
     524             :      *  |  +- AttributePathIsDirty (Attribute X) (mDirtyGeneration = b)
     525             :      *  +- mPreviousReportsBeginGeneration
     526             :      * For read handler, if mDirtyGeneration > mPreviousReportsBeginGeneration, then we regard it as a dirty read handler, and it
     527             :      * should generate report on timeout reached.
     528             :      */
     529             : 
     530             :     // When we don't have enough resources for a new subscription, the oldest subscription might be evicted by interaction model
     531             :     // engine, the "oldest" subscription is the subscription with the smallest generation.
     532             :     uint64_t mTransactionStartGeneration = 0;
     533             : 
     534             :     SubscriptionId mSubscriptionId    = 0;
     535             :     uint16_t mMinIntervalFloorSeconds = 0;
     536             :     uint16_t mMaxInterval             = 0;
     537             : 
     538             :     EventNumber mEventMin = 0;
     539             : 
     540             :     // The last schedule event number snapshoted in the beginning when preparing to fill new events to reports
     541             :     EventNumber mLastScheduledEventNumber = 0;
     542             : 
     543             :     // TODO: We should shutdown the transaction when the session expires.
     544             :     SessionHolder mSessionHandle;
     545             : 
     546             :     Messaging::ExchangeHolder mExchangeCtx;
     547             : #if CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
     548             :     // TODO: this should be replaced by a pointer to the InteractionModelEngine that created the ReadHandler
     549             :     // once InteractionModelEngine is no longer a singleton (see issue 23625)
     550             :     Messaging::ExchangeManager * mExchangeMgr = nullptr;
     551             : #endif // CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
     552             : 
     553             :     ObjectList<AttributePathParams> * mpAttributePathList   = nullptr;
     554             :     ObjectList<EventPathParams> * mpEventPathList           = nullptr;
     555             :     ObjectList<DataVersionFilter> * mpDataVersionFilterList = nullptr;
     556             : 
     557             :     ManagementCallback & mManagementCallback;
     558             : 
     559             :     uint32_t mLastWrittenEventsBytes = 0;
     560             : 
     561             :     // The detailed encoding state for a single attribute, used by list chunking feature.
     562             :     // The size of AttributeEncoderState is 2 bytes for now.
     563             :     AttributeValueEncoder::AttributeEncodeState mAttributeEncoderState;
     564             : 
     565             :     // Current Handler state
     566             :     HandlerState mState            = HandlerState::Idle;
     567             :     PriorityLevel mCurrentPriority = PriorityLevel::Invalid;
     568             :     BitFlags<ReadHandlerFlags> mFlags;
     569             :     InteractionType mInteractionType = InteractionType::Read;
     570             : 
     571             :     // TODO (#27675): Merge all observers into one and that one will dispatch the callbacks to the right place.
     572             :     Observer * mObserver = nullptr;
     573             : };
     574             : } // namespace app
     575             : } // namespace chip

Generated by: LCOV version 1.14