LCOV - code coverage report
Current view: top level - app - ReadClient.h (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 16 36 44.4 %
Date: 2024-02-15 08:20:41 Functions: 12 28 42.9 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2021 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 client for a CHIP Interaction Data model
      22             :  *
      23             :  */
      24             : 
      25             : #pragma once
      26             : #include "system/SystemClock.h"
      27             : #include <app/AppConfig.h>
      28             : #include <app/AttributePathParams.h>
      29             : #include <app/ConcreteAttributePath.h>
      30             : #include <app/EventHeader.h>
      31             : #include <app/EventPathParams.h>
      32             : #include <app/MessageDef/ReadRequestMessage.h>
      33             : #include <app/MessageDef/StatusIB.h>
      34             : #include <app/MessageDef/StatusResponseMessage.h>
      35             : #include <app/MessageDef/SubscribeRequestMessage.h>
      36             : #include <app/MessageDef/SubscribeResponseMessage.h>
      37             : #include <app/OperationalSessionSetup.h>
      38             : #include <app/ReadPrepareParams.h>
      39             : #include <app/data-model/Decode.h>
      40             : #include <lib/core/CHIPCallback.h>
      41             : #include <lib/core/CHIPCore.h>
      42             : #include <lib/core/TLVDebug.h>
      43             : #include <lib/support/CodeUtils.h>
      44             : #include <lib/support/DLLUtil.h>
      45             : #include <lib/support/logging/CHIPLogging.h>
      46             : #include <messaging/ExchangeContext.h>
      47             : #include <messaging/ExchangeHolder.h>
      48             : #include <messaging/ExchangeMgr.h>
      49             : #include <messaging/Flags.h>
      50             : #include <protocols/Protocols.h>
      51             : #include <system/SystemPacketBuffer.h>
      52             : 
      53             : #if CHIP_CONFIG_ENABLE_READ_CLIENT
      54             : namespace chip {
      55             : namespace app {
      56             : 
      57             : class InteractionModelEngine;
      58             : 
      59             : /**
      60             :  *  @class ReadClient
      61             :  *
      62             :  *  @brief The read client represents the initiator side of a Read Or Subscribe Interaction (depending on the APIs invoked).
      63             :  *
      64             :  *         When used to manage subscriptions, the client provides functionality to automatically re-subscribe as needed,
      65             :  *         including re-establishing CASE under certain conditions (see Callback::OnResubscriptionNeeded for more info).
      66             :  *         This is the default behavior. A consumer can completely opt-out of this behavior by over-riding
      67             :  *         Callback::OnResubscriptionNeeded and providing an alternative implementation.
      68             :  *
      69             :  */
      70             : class ReadClient : public Messaging::ExchangeDelegate
      71             : {
      72             : public:
      73             :     class Callback
      74             :     {
      75             :     public:
      76           0 :         Callback() = default;
      77             : 
      78             :         // Callbacks are not expected to be copyable or movable.
      79             :         Callback(const Callback &)             = delete;
      80             :         Callback(Callback &&)                  = delete;
      81             :         Callback & operator=(const Callback &) = delete;
      82             :         Callback & operator=(Callback &&)      = delete;
      83             : 
      84           0 :         virtual ~Callback() = default;
      85             : 
      86             :         /**
      87             :          * Used to notify a (maybe empty) report data is received from peer and the subscription and the peer is alive.
      88             :          *
      89             :          * This object MUST continue to exist after this call is completed. The application shall wait until it
      90             :          * receives an OnDone call to destroy the object.
      91             :          *
      92             :          */
      93           0 :         virtual void NotifySubscriptionStillActive(const ReadClient & apReadClient) {}
      94             : 
      95             :         /**
      96             :          * Used to signal the commencement of processing of the first attribute or event report received in a given exchange.
      97             :          *
      98             :          * This object MUST continue to exist after this call is completed. The application shall wait until it
      99             :          * receives an OnDone call to destroy the object.
     100             :          *
     101             :          * Once OnReportBegin has been called, either OnReportEnd or OnError will be called before OnDone.
     102             :          *
     103             :          */
     104           0 :         virtual void OnReportBegin() {}
     105             : 
     106             :         /**
     107             :          * Used to signal the completion of processing of the last attribute or event report in a given exchange.
     108             :          *
     109             :          * This object MUST continue to exist after this call is completed. The application shall wait until it
     110             :          * receives an OnDone call to destroy the object.
     111             :          *
     112             :          */
     113           0 :         virtual void OnReportEnd() {}
     114             : 
     115             :         /**
     116             :          * Used to deliver event data received through the Read and Subscribe interactions
     117             :          *
     118             :          * Only one of the apData and apStatus can be non-null.
     119             :          *
     120             :          * This object MUST continue to exist after this call is completed. The application shall wait until it
     121             :          * receives an OnDone call to destroy the object.
     122             :          *
     123             :          * @param[in] aEventHeader The event header in report response.
     124             :          * @param[in] apData A TLVReader positioned right on the payload of the event.
     125             :          * @param[in] apStatus Event-specific status, containing an InteractionModel::Status code as well as an optional
     126             :          *                     cluster-specific status code.
     127             :          */
     128           0 :         virtual void OnEventData(const EventHeader & aEventHeader, TLV::TLVReader * apData, const StatusIB * apStatus) {}
     129             : 
     130             :         /**
     131             :          * Used to deliver attribute data received through the Read and Subscribe interactions.
     132             :          *
     133             :          * This callback will be called when:
     134             :          *   - Receiving attribute data as response of Read interactions
     135             :          *   - Receiving attribute data as reports of subscriptions
     136             :          *   - Receiving attribute data as initial reports of subscriptions
     137             :          *
     138             :          * This object MUST continue to exist after this call is completed. The application shall wait until it
     139             :          * receives an OnDone call to destroy the object.
     140             :          *
     141             :          * @param[in] aPath        The attribute path field in report response.
     142             :          * @param[in] apData       The attribute data of the given path, will be a nullptr if status is not Success.
     143             :          * @param[in] aStatus      Attribute-specific status, containing an InteractionModel::Status code as well as an
     144             :          *                         optional cluster-specific status code.
     145             :          */
     146           0 :         virtual void OnAttributeData(const ConcreteDataAttributePath & aPath, TLV::TLVReader * apData, const StatusIB & aStatus) {}
     147             : 
     148             :         /**
     149             :          * OnSubscriptionEstablished will be called when a subscription is established for the given subscription transaction.
     150             :          * If using auto resubscription, OnSubscriptionEstablished will be called whenever resubscription is established.
     151             :          *
     152             :          * This object MUST continue to exist after this call is completed. The application shall wait until it
     153             :          * receives an OnDone call to destroy the object.
     154             :          *
     155             :          * @param[in] aSubscriptionId The identifier of the subscription that was established.
     156             :          */
     157           0 :         virtual void OnSubscriptionEstablished(SubscriptionId aSubscriptionId) {}
     158             : 
     159             :         /**
     160             :          * OnResubscriptionNeeded will be called when a subscription that was started with SendAutoResubscribeRequest has terminated
     161             :          * and re-subscription is needed. The termination cause is provided to help inform subsequent re-subscription logic.
     162             :          *
     163             :          * The base implementation automatically re-subscribes at appropriate intervals taking the termination cause into account
     164             :          * (see ReadClient::DefaultResubscribePolicy for more details). If the default implementation doesn't suffice, the logic of
     165             :          * ReadClient::DefaultResubscribePolicy is broken down into its constituent methods that are publicly available for
     166             :          * applications to call and sequence.
     167             :          *
     168             :          * If the peer is LIT ICD, and the timeout is reached, `aTerminationCause` will be
     169             :          * `CHIP_ERROR_LIT_SUBSCRIBE_INACTIVE_TIMEOUT`. In this case, returning `CHIP_NO_ERROR` will still trigger a resubscribe
     170             :          * attempt, while returning `CHIP_ERROR_LIT_SUBSCRIBE_INACTIVE_TIMEOUT` will put the subscription in the
     171             :          * `InactiveICDSubscription` state.  In the latter case, OnResubscriptionNeeded will be called again when
     172             :          * `OnActiveModeNotification` is called.
     173             :          *
     174             :          * If the method is over-ridden, it's the application's responsibility to take the appropriate steps needed to eventually
     175             :          * call-back into the ReadClient object to schedule a re-subscription (by invoking ReadClient::ScheduleResubscription).
     176             :          *
     177             :          * If the application DOES NOT want re-subscription to happen on a particular invocation of this method, returning anything
     178             :          * other than CHIP_NO_ERROR will terminate the interaction and result in OnError, OnDeallocatePaths and OnDone being called
     179             :          * in that sequence.
     180             :          *
     181             :          * This object MUST continue to exist after this call is completed. The
     182             :          * application shall wait until it receives an OnDone call to destroy the object.
     183             :          *
     184             :          * @param[in] aTerminationCause The cause of failure of the subscription that just terminated.
     185             :          */
     186           0 :         virtual CHIP_ERROR OnResubscriptionNeeded(ReadClient * apReadClient, CHIP_ERROR aTerminationCause)
     187             :         {
     188           0 :             return apReadClient->DefaultResubscribePolicy(aTerminationCause);
     189             :         }
     190             : 
     191             :         /**
     192             :          * OnError will be called when an error occurs *after* a successful call to SendRequest(). The following
     193             :          * errors will be delivered through this call in the aError field:
     194             :          *
     195             :          * - CHIP_ERROR_TIMEOUT: A response was not received within the expected response timeout.
     196             :          * - CHIP_ERROR_*TLV*: A malformed, non-compliant response was received from the server.
     197             :          * - CHIP_ERROR encapsulating a StatusIB: If we got a non-path-specific
     198             :          *   status response from the server.  In that case,
     199             :          *   StatusIB::InitFromChipError can be used to extract the status.
     200             :          * - CHIP_ERROR*: All other cases.
     201             :          *
     202             :          * This object MUST continue to exist after this call is completed. The application shall wait until it
     203             :          * receives an OnDone call to destroy the object.
     204             :          *
     205             :          * @param[in] aError       A system error code that conveys the overall error code.
     206             :          */
     207           0 :         virtual void OnError(CHIP_ERROR aError) {}
     208             : 
     209             :         /**
     210             :          * OnDone will be called when ReadClient has finished all work and it is
     211             :          * safe to destroy and free the allocated ReadClient object and any
     212             :          * other objects associated with the Read or Subscribe interaction.
     213             :          *
     214             :          * This function will:
     215             :          *      - Always be called exactly *once* for a given ReadClient instance.
     216             :          *      - Be called even in error circumstances.
     217             :          *      - Only be called after a successful call to SendRequest has been
     218             :          *        made, when the read completes or the subscription is shut down.
     219             :          *
     220             :          * @param[in] apReadClient the ReadClient for the completed interaction.
     221             :          */
     222             :         virtual void OnDone(ReadClient * apReadClient) = 0;
     223             : 
     224             :         /**
     225             :          * This function is invoked when using SendAutoResubscribeRequest, where the ReadClient was configured to auto re-subscribe
     226             :          * and the ReadPrepareParams was moved into this client for management. This will have to be free'ed appropriately by the
     227             :          * application. If SendAutoResubscribeRequest fails, this function will be called before it returns the failure. If
     228             :          * SendAutoResubscribeRequest succeeds, this function will be called immediately before calling OnDone, or
     229             :          * when the ReadClient is destroyed, if that happens before OnDone. If  SendAutoResubscribeRequest is not called,
     230             :          * this function will not be called.
     231             :          */
     232           0 :         virtual void OnDeallocatePaths(ReadPrepareParams && aReadPrepareParams) {}
     233             : 
     234             :         /**
     235             :          * This function is invoked when constructing a read/subscribeRequest that does not have data
     236             :          * version filters specified, to give the callback a chance to provide some.
     237             :          *
     238             :          * This function is expected to encode as many complete data version filters as will fit into
     239             :          * the buffer, rolling back any partially-encoded filters if it runs out of space, and set the
     240             :          * aEncodedDataVersionList boolean to true if it has successfully encoded at least one data version filter.
     241             :          *
     242             :          * Otherwise aEncodedDataVersionList will be set to false.
     243             :          */
     244           0 :         virtual CHIP_ERROR OnUpdateDataVersionFilterList(DataVersionFilterIBs::Builder & aDataVersionFilterIBsBuilder,
     245             :                                                          const Span<AttributePathParams> & aAttributePaths,
     246             :                                                          bool & aEncodedDataVersionList)
     247             :         {
     248           0 :             aEncodedDataVersionList = false;
     249           0 :             return CHIP_NO_ERROR;
     250             :         }
     251             : 
     252             :         /*
     253             :          * Get highest received event number.
     254             :          * If the application does not want to filter events by event number, it should call ClearValue() on aEventNumber
     255             :          * and return CHIP_NO_ERROR.  An error return from this function will fail the entire read client interaction.
     256             :          */
     257           0 :         virtual CHIP_ERROR GetHighestReceivedEventNumber(Optional<EventNumber> & aEventNumber)
     258             :         {
     259           0 :             aEventNumber.ClearValue();
     260           0 :             return CHIP_NO_ERROR;
     261             :         }
     262             : 
     263             :         /**
     264             :          * OnUnsolicitedMessageFromPublisher will be called for a subscription
     265             :          * ReadClient when any incoming message is received from a matching
     266             :          * node on the fabric.
     267             :          *
     268             :          * This callback will be called:
     269             :          *   - When receiving any unsolicited communication from the node
     270             :          *   - Even for disconnected subscriptions.
     271             :          *
     272             :          * Callee MUST not synchronously destroy ReadClients in this callback.
     273             :          *
     274             :          * @param[in] apReadClient the ReadClient for the subscription.
     275             :          */
     276           0 :         virtual void OnUnsolicitedMessageFromPublisher(ReadClient * apReadClient) {}
     277             : 
     278             :         /**
     279             :          * OnCASESessionEstablished will be called for a subscription ReadClient when
     280             :          * it finishes setting up a CASE session, as part of either automatic
     281             :          * re-subscription or doing an initial subscribe based on ScopedNodeId.
     282             :          *
     283             :          * The callee is allowed to modify the ReadPrepareParams (e.g. to change
     284             :          * things like min/max intervals based on the session parameters).
     285             :          */
     286           0 :         virtual void OnCASESessionEstablished(const SessionHandle & aSession, ReadPrepareParams & aSubscriptionParams) {}
     287             :     };
     288             : 
     289             :     enum class InteractionType : uint8_t
     290             :     {
     291             :         Read,
     292             :         Subscribe,
     293             :     };
     294             : 
     295             :     enum class PeerType : uint8_t
     296             :     {
     297             :         kNormal,
     298             :         kLITICD,
     299             :     };
     300             : 
     301             :     /**
     302             :      *
     303             :      *  Constructor.
     304             :      *
     305             :      *  The callback passed in has to outlive this ReadClient object.
     306             :      *
     307             :      *  This object can outlive the InteractionModelEngine passed in. However, upon shutdown of the engine,
     308             :      *  this object will cease to function correctly since it depends on the engine for a number of critical functions.
     309             :      *
     310             :      *  @param[in]    apImEngine       A valid pointer to the IM engine.
     311             :      *  @param[in]    apExchangeMgr    A pointer to the ExchangeManager object. Allowed to be null
     312             :      *                                 if the version of SendAutoResubscribeRequest that takes a
     313             :      *                                 ScopedNodeId is used.
     314             :      *  @param[in]    apCallback       Callback set by application.
     315             :      *  @param[in]    aInteractionType Type of interaction (read or subscribe)
     316             :      *
     317             :      *  @retval #CHIP_ERROR_INCORRECT_STATE incorrect state if it is already initialized
     318             :      *  @retval #CHIP_NO_ERROR On success.
     319             :      *
     320             :      */
     321             :     ReadClient(InteractionModelEngine * apImEngine, Messaging::ExchangeManager * apExchangeMgr, Callback & apCallback,
     322             :                InteractionType aInteractionType);
     323             : 
     324             :     /**
     325             :      * Destructor.
     326             :      *
     327             :      * Will abort the exchange context if a valid one still exists. It will also cancel any
     328             :      * liveness timers that may be active.
     329             :      *
     330             :      * OnDone() will not be called.
     331             :      */
     332             :     ~ReadClient() override;
     333             : 
     334             :     /**
     335             :      *  Send a request.  There can be one request outstanding on a given ReadClient.
     336             :      *  If SendRequest returns success, no more SendRequest calls can happen on this ReadClient
     337             :      *  until the corresponding OnDone call has happened.
     338             :      *
     339             :      *  This will send either a Read Request or a Subscribe Request depending on
     340             :      *  the InteractionType this read client was initialized with.
     341             :      *
     342             :      *  @retval #others fail to send read request
     343             :      *  @retval #CHIP_NO_ERROR On success.
     344             :      */
     345             :     CHIP_ERROR SendRequest(ReadPrepareParams & aReadPrepareParams);
     346             : 
     347             :     /**
     348             :      *  Re-activate an inactive subscription.
     349             :      *
     350             :      *  When subscribing to LIT-ICD and liveness timeout reached and OnResubscriptionNeeded returns
     351             :      * CHIP_ERROR_LIT_SUBSCRIBE_INACTIVE_TIMEOUT, the read client will move to the InactiveICDSubscription state and
     352             :      * resubscription can be triggered via OnActiveModeNotification().
     353             :      *
     354             :      *  If the subscription is not in the `InactiveICDSubscription` state, this function will do nothing. So it is always safe to
     355             :      * call this function when a check-in message is received.
     356             :      */
     357             :     void OnActiveModeNotification();
     358             : 
     359             :     void OnUnsolicitedReportData(Messaging::ExchangeContext * apExchangeContext, System::PacketBufferHandle && aPayload);
     360             : 
     361         195 :     void OnUnsolicitedMessageFromPublisher()
     362             :     {
     363         195 :         TriggerResubscribeIfScheduled("unsolicited message");
     364             : 
     365             :         // Then notify callbacks
     366         195 :         mpCallback.OnUnsolicitedMessageFromPublisher(this);
     367         195 :     }
     368             : 
     369             :     auto GetSubscriptionId() const
     370             :     {
     371             :         using returnType = Optional<decltype(mSubscriptionId)>;
     372             :         return mInteractionType == InteractionType::Subscribe ? returnType(mSubscriptionId) : returnType::Missing();
     373             :     }
     374             : 
     375          41 :     FabricIndex GetFabricIndex() const { return mPeer.GetFabricIndex(); }
     376          71 :     NodeId GetPeerNodeId() const { return mPeer.GetNodeId(); }
     377         645 :     bool IsReadType() { return mInteractionType == InteractionType::Read; }
     378        5000 :     bool IsSubscriptionType() const { return mInteractionType == InteractionType::Subscribe; };
     379             : 
     380             :     /*
     381             :      * Retrieve the reporting intervals associated with an active subscription. This should only be called if we're of subscription
     382             :      * interaction type and after a subscription has been established.
     383             :      */
     384             :     CHIP_ERROR GetReportingIntervals(uint16_t & aMinIntervalFloorSeconds, uint16_t & aMaxIntervalCeilingSeconds) const
     385             :     {
     386             :         VerifyOrReturnError(IsSubscriptionType(), CHIP_ERROR_INCORRECT_STATE);
     387             :         VerifyOrReturnError(IsSubscriptionActive(), CHIP_ERROR_INCORRECT_STATE);
     388             : 
     389             :         aMinIntervalFloorSeconds   = mMinIntervalFloorSeconds;
     390             :         aMaxIntervalCeilingSeconds = mMaxInterval;
     391             : 
     392             :         return CHIP_NO_ERROR;
     393             :     }
     394             : 
     395         161 :     ReadClient * GetNextClient() { return mpNext; }
     396         154 :     void SetNextClient(ReadClient * apClient) { mpNext = apClient; }
     397             : 
     398             :     /**
     399             :      *  Like SendSubscribeRequest, but the ReadClient will automatically attempt to re-establish the subscription if
     400             :      *  we decide that the subscription has dropped.  The exact behavior of the re-establishment can be controlled
     401             :      *  by setting mResubscribePolicy in the ReadPrepareParams.  If not set, a default behavior with exponential backoff will be
     402             :      *  used.
     403             :      *
     404             :      *  The application has to know to
     405             :      *  a) allocate a ReadPrepareParams object that will have fields mpEventPathParamsList and mpAttributePathParamsList and
     406             :      *  mpDataVersionFilterList with lifetimes as long as the ReadClient itself and b) free those up later in the call to
     407             :      *  OnDeallocatePaths. Note: At a given time in the system, you can either have a single subscription with re-sub enabled that
     408             :      *  has mKeepSubscriptions = false, OR, multiple subs with re-sub enabled with mKeepSubscriptions = true. You shall not
     409             :      *  have a mix of both simultaneously. If SendAutoResubscribeRequest is called at all, it guarantees that it will call
     410             :      *  OnDeallocatePaths (either befor returning error, or when OnDone is called). SendAutoResubscribeRequest is the only case
     411             :      *  that calls OnDeallocatePaths, since that's the only case when the consumer moved a ReadParams into the client.
     412             :      *
     413             :      */
     414             :     CHIP_ERROR SendAutoResubscribeRequest(ReadPrepareParams && aReadPrepareParams);
     415             : 
     416             :     /**
     417             :      * Like SendAutoResubscribeRequest above, but without a session being
     418             :      * available in the ReadPrepareParams.  When this is used, the ReadClient is
     419             :      * responsible for setting up the CASE session itself.
     420             :      *
     421             :      * When using this version of SendAutoResubscribeRequest, any session to
     422             :      * which ReadPrepareParams has a reference will be ignored.
     423             :      */
     424             :     CHIP_ERROR SendAutoResubscribeRequest(const ScopedNodeId & aPublisherId, ReadPrepareParams && aReadPrepareParams);
     425             : 
     426             :     /**
     427             :      *   This provides a standard re-subscription policy implementation that given a termination cause, does the following:
     428             :      *   - Calculates the time till next subscription with fibonacci back-off (implemented by ComputeTimeTillNextSubscription()).
     429             :      *   - Schedules the next subscription attempt at the computed interval from the previous step. Operational discovery and
     430             :      *     CASE establishment will be attempted if aTerminationCause was CHIP_ERROR_TIMEOUT. In all other cases, it will attempt
     431             :      *     to re-use a previously established session.
     432             :      */
     433             :     CHIP_ERROR DefaultResubscribePolicy(CHIP_ERROR aTerminationCause);
     434             : 
     435             :     /**
     436             :      * Computes the time, in milliseconds, until the next re-subscription over
     437             :      * an ever increasing window following a fibonacci sequence with the current retry count
     438             :      * used as input to the fibonacci algorithm.
     439             :      *
     440             :      * CHIP_RESUBSCRIBE_MAX_FIBONACCI_STEP_INDEX is the maximum value the retry count can tick up to.
     441             :      *
     442             :      */
     443             :     uint32_t ComputeTimeTillNextSubscription();
     444             : 
     445             :     /**
     446             :      * Schedules a re-subscription aTimeTillNextResubscriptionMs into the future.
     447             :      *
     448             :      * If an application wants to set up CASE on their own, they should call ComputeTimeTillNextSubscription() to compute the next
     449             :      * interval at which they should attempt CASE and attempt CASE at that time. On successful CASE establishment, this method
     450             :      * should be called with the new SessionHandle provided through 'aNewSessionHandle', 'aTimeTillNextResubscriptionMs' set to 0
     451             :      * (i.e async, but as soon as possible) and 'aReestablishCASE' set to false.
     452             :      *
     453             :      * Otherwise, if aReestablishCASE is true, operational discovery and CASE will be attempted at that time before
     454             :      * the actual IM interaction is initiated.
     455             :      *
     456             :      * aReestablishCASE SHALL NOT be set to true if a valid SessionHandle is provided through newSessionHandle.
     457             :      */
     458             :     CHIP_ERROR ScheduleResubscription(uint32_t aTimeTillNextResubscriptionMs, Optional<SessionHandle> aNewSessionHandle,
     459             :                                       bool aReestablishCASE);
     460             : 
     461             :     // Like SendSubscribeRequest, but allows sending certain forms of invalid
     462             :     // subscribe requests that servers are expected to reject, for testing
     463             :     // purposes.  Should only be called from tests.
     464             : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
     465             :     CHIP_ERROR SendSubscribeRequestWithoutValidation(const ReadPrepareParams & aReadPrepareParams)
     466             :     {
     467             :         return SendSubscribeRequestImpl(aReadPrepareParams);
     468             :     }
     469             : #endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST
     470             : 
     471             :     /**
     472             :      * Override the interval at which liveness of the subscription is assessed.
     473             :      * By default, this is set set to the max interval of the subscription + ACK timeout of the underlying session.
     474             :      *
     475             :      * This can be only be called once a subscription has been established and is active. Once called, this will cancel any existing
     476             :      * liveness timers and schedule a new one.
     477             :      *
     478             :      * This can be called from the Callback::OnSubscriptionEstablished callback.
     479             :      *
     480             :      */
     481             :     void OverrideLivenessTimeout(System::Clock::Timeout aLivenessTimeout);
     482             : 
     483             :     /**
     484             :      * If the ReadClient currently has a resubscription attempt scheduled,
     485             :      * trigger that attempt right now.  This is generally useful when a consumer
     486             :      * has some sort of indication that the server side is currently up and
     487             :      * communicating, so right now is a good time to try to resubscribe.
     488             :      *
     489             :      * The reason string is used for logging if a resubscribe is triggered.
     490             :      */
     491             :     void TriggerResubscribeIfScheduled(const char * reason);
     492             : 
     493             :     /**
     494             :      * Returns the timeout after which we consider the subscription to have
     495             :      * dropped, if we have received no messages within that amount of time.
     496             :      *
     497             :      * Returns NullOptional if a subscription has not yet been established (and
     498             :      * hence the MaxInterval is not yet known), or if the subscription session
     499             :      * is gone and hence the relevant MRP parameters can no longer be determined.
     500             :      */
     501             :     Optional<System::Clock::Timeout> GetSubscriptionTimeout();
     502             : 
     503             : private:
     504             :     friend class TestReadInteraction;
     505             :     friend class InteractionModelEngine;
     506             : 
     507             :     enum class ClientState : uint8_t
     508             :     {
     509             :         Idle,                      ///< The client has been initialized and is ready for a SendRequest
     510             :         AwaitingInitialReport,     ///< The client is waiting for initial report
     511             :         AwaitingSubscribeResponse, ///< The client is waiting for subscribe response
     512             :         SubscriptionActive,        ///< The client is maintaining subscription
     513             :         InactiveICDSubscription,   ///< The client is waiting to resubscribe for LIT device
     514             :     };
     515             : 
     516             :     enum class ReportType
     517             :     {
     518             :         // kUnsolicited reports are the first message in an exchange.
     519             :         kUnsolicited,
     520             :         // kContinuingTransaction reports are responses to a message we sent.
     521             :         kContinuingTransaction
     522             :     };
     523             : 
     524         538 :     bool IsMatchingSubscriptionId(SubscriptionId aSubscriptionId)
     525             :     {
     526         538 :         return aSubscriptionId == mSubscriptionId && mInteractionType == InteractionType::Subscribe;
     527             :     }
     528             : 
     529             :     CHIP_ERROR OnMessageReceived(Messaging::ExchangeContext * apExchangeContext, const PayloadHeader & aPayloadHeader,
     530             :                                  System::PacketBufferHandle && aPayload) override;
     531             :     void OnResponseTimeout(Messaging::ExchangeContext * apExchangeContext) override;
     532             : 
     533             :     /**
     534             :      *  Updates the type (LIT ICD or not) of the peer.
     535             :      *
     536             :      *  When the subscription is active, this function will just set the flag. When the subscription is an InactiveICDSubscription,
     537             :      * setting the peer type to SIT or normal devices will also trigger a resubscription attempt.
     538             :      *
     539             :      */
     540             :     void OnPeerTypeChange(PeerType aType);
     541             : 
     542             :     /**
     543             :      *  Check if current read client is being used
     544             :      *
     545             :      */
     546        1827 :     bool IsIdle() const { return mState == ClientState::Idle; }
     547        1972 :     bool IsInactiveICDSubscription() const { return mState == ClientState::InactiveICDSubscription; }
     548        1149 :     bool IsSubscriptionActive() const { return mState == ClientState::SubscriptionActive; }
     549         345 :     bool IsAwaitingInitialReport() const { return mState == ClientState::AwaitingInitialReport; }
     550             :     bool IsAwaitingSubscribeResponse() const { return mState == ClientState::AwaitingSubscribeResponse; }
     551             : 
     552             :     CHIP_ERROR GenerateEventPaths(EventPathIBs::Builder & aEventPathsBuilder, const Span<EventPathParams> & aEventPaths);
     553             :     CHIP_ERROR GenerateAttributePaths(AttributePathIBs::Builder & aAttributePathIBsBuilder,
     554             :                                       const Span<AttributePathParams> & aAttributePaths);
     555             : 
     556             :     CHIP_ERROR GenerateDataVersionFilterList(DataVersionFilterIBs::Builder & aDataVersionFilterIBsBuilder,
     557             :                                              const Span<AttributePathParams> & aAttributePaths,
     558             :                                              const Span<DataVersionFilter> & aDataVersionFilters, bool & aEncodedDataVersionList);
     559             :     CHIP_ERROR BuildDataVersionFilterList(DataVersionFilterIBs::Builder & aDataVersionFilterIBsBuilder,
     560             :                                           const Span<AttributePathParams> & aAttributePaths,
     561             :                                           const Span<DataVersionFilter> & aDataVersionFilters, bool & aEncodedDataVersionList);
     562             :     CHIP_ERROR ReadICDOperatingModeFromAttributeDataIB(TLV::TLVReader && aReader, PeerType & aType);
     563             :     CHIP_ERROR ProcessAttributeReportIBs(TLV::TLVReader & aAttributeDataIBsReader);
     564             :     CHIP_ERROR ProcessEventReportIBs(TLV::TLVReader & aEventReportIBsReader);
     565             : 
     566             :     static void OnLivenessTimeoutCallback(System::Layer * apSystemLayer, void * apAppState);
     567             :     CHIP_ERROR ProcessSubscribeResponse(System::PacketBufferHandle && aPayload);
     568             :     CHIP_ERROR RefreshLivenessCheckTimer();
     569             :     CHIP_ERROR ComputeLivenessCheckTimerTimeout(System::Clock::Timeout * aTimeout);
     570             :     void CancelLivenessCheckTimer();
     571             :     void CancelResubscribeTimer();
     572             :     void TriggerResubscriptionForLivenessTimeout(CHIP_ERROR aReason);
     573             :     void MoveToState(const ClientState aTargetState);
     574             :     CHIP_ERROR ProcessAttributePath(AttributePathIB::Parser & aAttributePath, ConcreteDataAttributePath & aClusterInfo);
     575             :     CHIP_ERROR ProcessReportData(System::PacketBufferHandle && aPayload, ReportType aReportType);
     576             :     const char * GetStateStr() const;
     577             : 
     578             :     /*
     579             :      * Checks if we should re-subscribe based on the specified re-subscription policy. If we should, re-subscription is scheduled
     580             :      * aNextResubscribeIntervalMsec is updated accordingly, and true is returned.
     581             :      *
     582             :      * If we should not resubscribe, false is returned.
     583             :      *
     584             :      *  @param[out]    aNextResubscribeIntervalMsec    How long we will wait before trying to auto-resubscribe.
     585             :      */
     586             :     bool ResubscribeIfNeeded(uint32_t & aNextResubscribeIntervalMsec);
     587             : 
     588             :     // Specialized request-sending functions.
     589             :     CHIP_ERROR SendReadRequest(ReadPrepareParams & aReadPrepareParams);
     590             :     // SendSubscribeRequest performs som validation on aSubscribePrepareParams
     591             :     // and then calls SendSubscribeRequestImpl.
     592             :     CHIP_ERROR SendSubscribeRequest(const ReadPrepareParams & aSubscribePrepareParams);
     593             :     CHIP_ERROR SendSubscribeRequestImpl(const ReadPrepareParams & aSubscribePrepareParams);
     594             :     void UpdateDataVersionFilters(const ConcreteDataAttributePath & aPath);
     595             :     static void OnResubscribeTimerCallback(System::Layer * apSystemLayer, void * apAppState);
     596             :     // Called to ensure OnReportBegin is called before calling OnEventData or OnAttributeData
     597             :     void NoteReportingData();
     598             : 
     599             :     /*
     600             :      * Called internally to signal the completion of all work on this object, gracefully close the
     601             :      * exchange and finally, signal to the application that it's
     602             :      * safe to release this object.
     603             :      *
     604             :      * If aError != CHIP_NO_ERROR, this will trigger re-subscriptions if allowResubscription is true
     605             :      * AND if this ReadClient instance is tracking a subscription AND the applications decides to do so
     606             :      * in their implementation of Callback::OnResubscriptionNeeded().
     607             :      */
     608             :     void Close(CHIP_ERROR aError, bool allowResubscription = true);
     609             : 
     610             :     void StopResubscription();
     611             :     void ClearActiveSubscriptionState();
     612             : 
     613             :     static void HandleDeviceConnected(void * context, Messaging::ExchangeManager & exchangeMgr,
     614             :                                       const SessionHandle & sessionHandle);
     615             :     static void HandleDeviceConnectionFailure(void * context, const ScopedNodeId & peerId, CHIP_ERROR error);
     616             : 
     617             :     CHIP_ERROR GetMinEventNumber(const ReadPrepareParams & aReadPrepareParams, Optional<EventNumber> & aEventMin);
     618             : 
     619             :     /**
     620             :      * Start setting up a CASE session to our peer, if we can locate a
     621             :      * CASESessionManager.  Returns error if we did not even manage to kick off
     622             :      * a CASE attempt.
     623             :      */
     624             :     CHIP_ERROR EstablishSessionToPeer();
     625             : 
     626             :     Messaging::ExchangeManager * mpExchangeMgr = nullptr;
     627             :     Messaging::ExchangeHolder mExchange;
     628             :     Callback & mpCallback;
     629             :     ClientState mState    = ClientState::Idle;
     630             :     bool mIsReporting     = false;
     631             :     bool mIsInitialReport = true;
     632             :     // boolean to check if client is waiting for the first priming report
     633             :     bool mWaitingForFirstPrimingReport = true;
     634             :     bool mPendingMoreChunks            = false;
     635             :     uint16_t mMinIntervalFloorSeconds  = 0;
     636             :     uint16_t mMaxInterval              = 0;
     637             :     SubscriptionId mSubscriptionId     = 0;
     638             :     ScopedNodeId mPeer;
     639             :     InteractionType mInteractionType = InteractionType::Read;
     640             :     Timestamp mEventTimestamp;
     641             : 
     642             :     bool mForceCaseOnNextResub      = true;
     643             :     bool mIsResubscriptionScheduled = false;
     644             : 
     645             :     chip::Callback::Callback<OnDeviceConnected> mOnConnectedCallback;
     646             :     chip::Callback::Callback<OnDeviceConnectionFailure> mOnConnectionFailureCallback;
     647             : 
     648             :     ReadClient * mpNext                 = nullptr;
     649             :     InteractionModelEngine * mpImEngine = nullptr;
     650             : 
     651             :     //
     652             :     // This stores the params associated with the interaction in a specific set of cases:
     653             :     //      1. Stores all parameters when used with subscriptions initiated using SendAutoResubscribeRequest.
     654             :     //      2. Stores just the SessionHolder when used with any subscriptions.
     655             :     //
     656             :     ReadPrepareParams mReadPrepareParams;
     657             :     uint32_t mNumRetries = 0;
     658             : 
     659             :     System::Clock::Timeout mLivenessTimeoutOverride = System::Clock::kZero;
     660             : 
     661             :     bool mIsPeerLIT = false;
     662             : 
     663             :     // End Of Container (0x18) uses one byte.
     664             :     static constexpr uint16_t kReservedSizeForEndOfContainer = 1;
     665             :     // Reserved size for the uint8_t InteractionModelRevision flag, which takes up 1 byte for the control tag and 1 byte for the
     666             :     // context tag, 1 byte for value
     667             :     static constexpr uint16_t kReservedSizeForIMRevision = 1 + 1 + 1;
     668             :     // Reserved buffer for TLV level overhead (the overhead for data version filter IBs EndOfContainer, IM reversion end
     669             :     // of RequestMessage (another end of container)).
     670             :     static constexpr uint16_t kReservedSizeForTLVEncodingOverhead =
     671             :         kReservedSizeForEndOfContainer + kReservedSizeForIMRevision + kReservedSizeForEndOfContainer;
     672             : };
     673             : 
     674             : };     // namespace app
     675             : };     // namespace chip
     676             : #endif // CHIP_CONFIG_ENABLE_READ_CLIENT

Generated by: LCOV version 1.14