LCOV - code coverage report
Current view: top level - app - InteractionModelEngine.h (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 24 25 96.0 %
Date: 2024-02-15 08:20:41 Functions: 13 14 92.9 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2020-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 objects for a CHIP Interaction Data model Engine which handle unsolicited IM message, and
      22             :  *      manage different kinds of IM client and handlers.
      23             :  *
      24             :  */
      25             : 
      26             : #pragma once
      27             : 
      28             : #include <access/AccessControl.h>
      29             : #include <app/AppConfig.h>
      30             : #include <app/AttributePathParams.h>
      31             : #include <app/CommandHandler.h>
      32             : #include <app/CommandHandlerInterface.h>
      33             : #include <app/CommandSender.h>
      34             : #include <app/ConcreteAttributePath.h>
      35             : #include <app/ConcreteCommandPath.h>
      36             : #include <app/ConcreteEventPath.h>
      37             : #include <app/DataVersionFilter.h>
      38             : #include <app/EventPathParams.h>
      39             : #include <app/MessageDef/AttributeReportIBs.h>
      40             : #include <app/MessageDef/ReportDataMessage.h>
      41             : #include <app/ObjectList.h>
      42             : #include <app/ReadClient.h>
      43             : #include <app/ReadHandler.h>
      44             : #include <app/StatusResponse.h>
      45             : #include <app/SubscriptionResumptionSessionEstablisher.h>
      46             : #include <app/SubscriptionsInfoProvider.h>
      47             : #include <app/TimedHandler.h>
      48             : #include <app/WriteClient.h>
      49             : #include <app/WriteHandler.h>
      50             : #include <app/reporting/Engine.h>
      51             : #include <app/reporting/ReportScheduler.h>
      52             : #include <app/util/attribute-metadata.h>
      53             : #include <app/util/basic-types.h>
      54             : #include <lib/core/CHIPCore.h>
      55             : #include <lib/support/CodeUtils.h>
      56             : #include <lib/support/DLLUtil.h>
      57             : #include <lib/support/Pool.h>
      58             : #include <lib/support/logging/CHIPLogging.h>
      59             : #include <messaging/ExchangeContext.h>
      60             : #include <messaging/ExchangeMgr.h>
      61             : #include <messaging/Flags.h>
      62             : #include <protocols/Protocols.h>
      63             : #include <protocols/interaction_model/Constants.h>
      64             : #include <system/SystemPacketBuffer.h>
      65             : 
      66             : #include <app/CASESessionManager.h>
      67             : 
      68             : namespace chip {
      69             : namespace app {
      70             : 
      71             : /**
      72             :  * @class InteractionModelEngine
      73             :  *
      74             :  * @brief This is a singleton hosting all CHIP unsolicited message processing and managing interaction model related clients and
      75             :  * handlers
      76             :  *
      77             :  */
      78             : class InteractionModelEngine : public Messaging::UnsolicitedMessageHandler,
      79             :                                public Messaging::ExchangeDelegate,
      80             :                                public CommandHandler::Callback,
      81             :                                public ReadHandler::ManagementCallback,
      82             :                                public FabricTable::Delegate,
      83             :                                public SubscriptionsInfoProvider
      84             : {
      85             : public:
      86             :     /**
      87             :      * @brief Retrieve the singleton Interaction Model Engine.
      88             :      *
      89             :      *  @return  A pointer to the shared InteractionModel Engine
      90             :      *
      91             :      */
      92             :     static InteractionModelEngine * GetInstance(void);
      93             : 
      94             :     /**
      95             :      * Spec 8.5.1 A publisher SHALL always ensure that every fabric the node is commissioned into can create at least three
      96             :      * subscriptions to the publisher and that each subscription SHALL support at least 3 attribute/event paths.
      97             :      */
      98             :     static constexpr size_t kMinSupportedSubscriptionsPerFabric = 3;
      99             :     static constexpr size_t kMinSupportedPathsPerSubscription   = 3;
     100             :     static constexpr size_t kMinSupportedPathsPerReadRequest    = 9;
     101             :     static constexpr size_t kMinSupportedReadRequestsPerFabric  = 1;
     102             :     static constexpr size_t kReadHandlerPoolSize                = CHIP_IM_MAX_NUM_SUBSCRIPTIONS + CHIP_IM_MAX_NUM_READS;
     103             : 
     104             :     // TODO: Per spec, the above numbers should be 3, 3, 9, 1, however, we use a lower limit to reduce the memory usage and should
     105             :     // fix it when we have reduced the memory footprint of ReadHandlers.
     106             : 
     107             :     InteractionModelEngine(void);
     108             : 
     109             :     /**
     110             :      *  Initialize the InteractionModel Engine.
     111             :      *
     112             :      *  @param[in]    apExchangeMgr    A pointer to the ExchangeManager object.
     113             :      *  @param[in]    apFabricTable    A pointer to the FabricTable object.
     114             :      *  @param[in]    apCASESessionMgr An optional pointer to a CASESessionManager (used for re-subscriptions).
     115             :      *
     116             :      *  @retval #CHIP_ERROR_INCORRECT_STATE If the state is not equal to
     117             :      *          kState_NotInitialized.
     118             :      *  @retval #CHIP_NO_ERROR On success.
     119             :      *
     120             :      */
     121             :     CHIP_ERROR Init(Messaging::ExchangeManager * apExchangeMgr, FabricTable * apFabricTable,
     122             :                     reporting::ReportScheduler * reportScheduler, CASESessionManager * apCASESessionMgr = nullptr,
     123             :                     SubscriptionResumptionStorage * subscriptionResumptionStorage = nullptr);
     124             : 
     125             :     void Shutdown();
     126             : 
     127        1465 :     Messaging::ExchangeManager * GetExchangeManager(void) const { return mpExchangeMgr; }
     128             : 
     129             :     /**
     130             :      * Returns a pointer to the CASESessionManager. This can return nullptr if one wasn't
     131             :      * provided in the call to Init().
     132             :      */
     133           0 :     CASESessionManager * GetCASESessionManager() const { return mpCASESessionMgr; }
     134             : 
     135             : #if CHIP_CONFIG_ENABLE_READ_CLIENT
     136             :     /**
     137             :      * Tears down an active subscription.
     138             :      *
     139             :      * @retval #CHIP_ERROR_KEY_NOT_FOUND If the subscription is not found.
     140             :      * @retval #CHIP_NO_ERROR On success.
     141             :      */
     142             :     CHIP_ERROR ShutdownSubscription(const ScopedNodeId & aPeerNodeId, SubscriptionId aSubscriptionId);
     143             : 
     144             :     /**
     145             :      * Tears down active subscriptions for a given peer node ID.
     146             :      */
     147             :     void ShutdownSubscriptions(FabricIndex aFabricIndex, NodeId aPeerNodeId);
     148             : 
     149             :     /**
     150             :      * Tears down all active subscriptions for a given fabric.
     151             :      */
     152             :     void ShutdownSubscriptions(FabricIndex aFabricIndex);
     153             : 
     154             :     /**
     155             :      * Tears down all active subscriptions.
     156             :      */
     157             :     void ShutdownAllSubscriptions();
     158             : #endif // CHIP_CONFIG_ENABLE_READ_CLIENT
     159             : 
     160             :     uint32_t GetNumActiveReadHandlers() const;
     161             :     uint32_t GetNumActiveReadHandlers(ReadHandler::InteractionType type) const;
     162             : 
     163             :     /**
     164             :      * Returns the number of active readhandlers with a specific type on a specific fabric.
     165             :      */
     166             :     uint32_t GetNumActiveReadHandlers(ReadHandler::InteractionType type, FabricIndex fabricIndex) const;
     167             : 
     168             :     uint32_t GetNumActiveWriteHandlers() const;
     169             : 
     170             :     /**
     171             :      * Returns the handler at a particular index within the active handler list.
     172             :      */
     173             :     ReadHandler * ActiveHandlerAt(unsigned int aIndex);
     174             : 
     175             :     /**
     176             :      * Returns the write handler at a particular index within the active handler list.
     177             :      */
     178             :     WriteHandler * ActiveWriteHandlerAt(unsigned int aIndex);
     179             : 
     180             :     /**
     181             :      * The Magic number of this InteractionModelEngine, the magic number is set during Init()
     182             :      */
     183          72 :     uint32_t GetMagicNumber() const { return mMagic; }
     184             : 
     185        7460 :     reporting::Engine & GetReportingEngine() { return mReportingEngine; }
     186             : 
     187         288 :     reporting::ReportScheduler * GetReportScheduler() { return mReportScheduler; }
     188             : 
     189             :     void ReleaseAttributePathList(ObjectList<AttributePathParams> *& aAttributePathList);
     190             : 
     191             :     CHIP_ERROR PushFrontAttributePathList(ObjectList<AttributePathParams> *& aAttributePathList,
     192             :                                           AttributePathParams & aAttributePath);
     193             : 
     194             :     // If a concrete path indicates an attribute that is also referenced by a wildcard path in the request,
     195             :     // the path SHALL be removed from the list.
     196             :     void RemoveDuplicateConcreteAttributePath(ObjectList<AttributePathParams> *& aAttributePaths);
     197             : 
     198             :     void ReleaseEventPathList(ObjectList<EventPathParams> *& aEventPathList);
     199             : 
     200             :     CHIP_ERROR PushFrontEventPathParamsList(ObjectList<EventPathParams> *& aEventPathList, EventPathParams & aEventPath);
     201             : 
     202             :     void ReleaseDataVersionFilterList(ObjectList<DataVersionFilter> *& aDataVersionFilterList);
     203             : 
     204             :     CHIP_ERROR PushFrontDataVersionFilterList(ObjectList<DataVersionFilter> *& aDataVersionFilterList,
     205             :                                               DataVersionFilter & aDataVersionFilter);
     206             : 
     207             :     CHIP_ERROR RegisterCommandHandler(CommandHandlerInterface * handler);
     208             :     CHIP_ERROR UnregisterCommandHandler(CommandHandlerInterface * handler);
     209             :     CommandHandlerInterface * FindCommandHandler(EndpointId endpointId, ClusterId clusterId);
     210             :     void UnregisterCommandHandlers(EndpointId endpointId);
     211             : 
     212             :     /*
     213             :      * Register an application callback to be notified of notable events when handling reads/subscribes.
     214             :      */
     215             :     void RegisterReadHandlerAppCallback(ReadHandler::ApplicationCallback * mpApplicationCallback)
     216             :     {
     217             :         mpReadHandlerApplicationCallback = mpApplicationCallback;
     218             :     }
     219             :     void UnregisterReadHandlerAppCallback() { mpReadHandlerApplicationCallback = nullptr; }
     220             : 
     221             :     /**
     222             :      * Called when a timed interaction has failed (i.e. the exchange it was
     223             :      * happening on has closed while the exchange delegate was the timed
     224             :      * handler).
     225             :      */
     226             :     void OnTimedInteractionFailed(TimedHandler * apTimedHandler);
     227             : 
     228             :     /**
     229             :      * Called when a timed invoke is received.  This function takes over all
     230             :      * handling of the exchange, status reporting, and so forth.
     231             :      */
     232             :     void OnTimedInvoke(TimedHandler * apTimedHandler, Messaging::ExchangeContext * apExchangeContext,
     233             :                        const PayloadHeader & aPayloadHeader, System::PacketBufferHandle && aPayload);
     234             : 
     235             :     /**
     236             :      * Called when a timed write is received.  This function takes over all
     237             :      * handling of the exchange, status reporting, and so forth.
     238             :      */
     239             :     void OnTimedWrite(TimedHandler * apTimedHandler, Messaging::ExchangeContext * apExchangeContext,
     240             :                       const PayloadHeader & aPayloadHeader, System::PacketBufferHandle && aPayload);
     241             : 
     242             : #if CHIP_CONFIG_ENABLE_READ_CLIENT
     243             :     /**
     244             :      *  Activate the idle subscriptions.
     245             :      *
     246             :      *  When subscribing to ICD and liveness timeout reached, the read client will move to `InactiveICDSubscription` state and
     247             :      * resubscription can be triggered via OnActiveModeNotification().
     248             :      */
     249             :     void OnActiveModeNotification(ScopedNodeId aPeer);
     250             : 
     251             :     /**
     252             :      *  Used to notify when a peer becomes LIT ICD or vice versa.
     253             :      *
     254             :      *  ReadClient will call this function when it finds any updates of the OperatingMode attribute from ICD management
     255             :      * cluster. The application doesn't need to call this function, usually.
     256             :      */
     257             :     void OnPeerTypeChange(ScopedNodeId aPeer, ReadClient::PeerType aType);
     258             : 
     259             :     /**
     260             :      * Add a read client to the internally tracked list of weak references. This list is used to
     261             :      * correctly dispatch unsolicited reports to the right matching handler by subscription ID.
     262             :      */
     263             :     void AddReadClient(ReadClient * apReadClient);
     264             : 
     265             :     /**
     266             :      * Remove a read client from the internally tracked list of weak references.
     267             :      */
     268             :     void RemoveReadClient(ReadClient * apReadClient);
     269             : 
     270             :     /**
     271             :      * Test to see if a read client is in the actively tracked list.
     272             :      */
     273             :     bool InActiveReadClientList(ReadClient * apReadClient);
     274             : 
     275             :     /**
     276             :      * Return the number of active read clients being tracked by the engine.
     277             :      */
     278             :     size_t GetNumActiveReadClients();
     279             : #endif // CHIP_CONFIG_ENABLE_READ_CLIENT
     280             : 
     281             :     /**
     282             :      * Returns the number of dirty subscriptions. Including the subscriptions that are generating reports.
     283             :      */
     284             :     size_t GetNumDirtySubscriptions() const;
     285             : 
     286             :     /**
     287             :      * Returns whether the write operation to the given path is conflict with another write operations. (i.e. another write
     288             :      * transaction is in the middle of processing the chunked value of the given path.)
     289             :      */
     290             :     bool HasConflictWriteRequests(const WriteHandler * apWriteHandler, const ConcreteAttributePath & aPath);
     291             : 
     292             :     /**
     293             :      * Select the oldest (and the one that exceeds the per subscription resource minimum if there are any) read handler on the
     294             :      * fabric with the given fabric index. Evict it when the fabric uses more resources than the per fabric quota or aForceEvict is
     295             :      * true.
     296             :      *
     297             :      * @retval Whether we have evicted a subscription.
     298             :      */
     299             :     bool TrimFabricForSubscriptions(FabricIndex aFabricIndex, bool aForceEvict);
     300             : 
     301             :     /**
     302             :      * Select a read handler and abort the read transaction if the fabric is using more resources (number of paths or number of read
     303             :      * handlers) then we guaranteed.
     304             :      *
     305             :      * - The youngest oversized read handlers will be chosen first.
     306             :      * - If there are no oversized read handlers, the youngest read handlers will be chosen.
     307             :      *
     308             :      * @retval Whether we have evicted a read transaction.
     309             :      */
     310             :     bool TrimFabricForRead(FabricIndex aFabricIndex);
     311             : 
     312             :     /**
     313             :      * Returns the minimal value of guaranteed subscriptions per fabic. UINT16_MAX will be returned if current app is configured to
     314             :      * use heap for the object pools used by interaction model engine.
     315             :      *
     316             :      * @retval the minimal value of guaranteed subscriptions per fabic.
     317             :      */
     318             :     uint16_t GetMinGuaranteedSubscriptionsPerFabric() const;
     319             : 
     320             :     // virtual method from FabricTable::Delegate
     321             :     void OnFabricRemoved(const FabricTable & fabricTable, FabricIndex fabricIndex) override;
     322             : 
     323         258 :     SubscriptionResumptionStorage * GetSubscriptionResumptionStorage() { return mpSubscriptionResumptionStorage; };
     324             : 
     325             :     CHIP_ERROR ResumeSubscriptions();
     326             : 
     327             :     bool SubjectHasActiveSubscription(FabricIndex aFabricIndex, NodeId subjectID) override;
     328             : 
     329             :     bool SubjectHasPersistedSubscription(FabricIndex aFabricIndex, NodeId subjectID) override;
     330             : 
     331             : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
     332             :     //
     333             :     // Get direct access to the underlying read handler pool
     334             :     //
     335             :     auto & GetReadHandlerPool() { return mReadHandlers; }
     336             : 
     337             :     //
     338             :     // Override the maximal capacity of the fabric table only for interaction model engine
     339             :     //
     340             :     // If -1 is passed in, no override is instituted and default behavior resumes.
     341             :     //
     342             :     void SetConfigMaxFabrics(int32_t sz) { mMaxNumFabricsOverride = sz; }
     343             : 
     344             :     //
     345             :     // Override the maximal capacity of the underlying read handler pool to mimic
     346             :     // out of memory scenarios in unit-tests. You need to SetConfigMaxFabrics to make GetGuaranteedReadRequestsPerFabric
     347             :     // working correctly.
     348             :     //
     349             :     // If -1 is passed in, no override is instituted and default behavior resumes.
     350             :     //
     351             :     void SetHandlerCapacityForReads(int32_t sz) { mReadHandlerCapacityForReadsOverride = sz; }
     352             :     void SetHandlerCapacityForSubscriptions(int32_t sz) { mReadHandlerCapacityForSubscriptionsOverride = sz; }
     353             : 
     354             :     //
     355             :     // Override the maximal capacity of the underlying attribute path pool and event path pool to mimic
     356             :     // out of paths exhausted scenarios in unit-tests.
     357             :     //
     358             :     // If -1 is passed in, no override is instituted and default behavior resumes.
     359             :     //
     360             :     void SetPathPoolCapacityForReads(int32_t sz) { mPathPoolCapacityForReadsOverride = sz; }
     361             :     void SetPathPoolCapacityForSubscriptions(int32_t sz) { mPathPoolCapacityForSubscriptionsOverride = sz; }
     362             : 
     363             :     //
     364             :     // We won't limit the handler used per fabric on platforms that are using heap for memory pools, so we introduces a flag to
     365             :     // enforce such check based on the configured size. This flag is used for unit tests only, there is another compare time flag
     366             :     // CHIP_CONFIG_IM_FORCE_FABRIC_QUOTA_CHECK for stress tests.
     367             :     //
     368             :     void SetForceHandlerQuota(bool forceHandlerQuota) { mForceHandlerQuota = forceHandlerQuota; }
     369             : 
     370             :     //
     371             :     // When testing subscriptions using the high-level APIs in src/controller/ReadInteraction.h,
     372             :     // they don't provide for the ability to shut down those subscriptions after they've been established.
     373             :     //
     374             :     // So for the purposes of unit tests, add a helper here to shut down and clean-up all active handlers.
     375             :     //
     376             :     void ShutdownActiveReads()
     377             :     {
     378             : #if CHIP_CONFIG_ENABLE_READ_CLIENT
     379             :         for (auto * readClient = mpActiveReadClientList; readClient != nullptr;)
     380             :         {
     381             :             readClient->mpImEngine = nullptr;
     382             :             auto * tmpClient       = readClient->GetNextClient();
     383             :             readClient->SetNextClient(nullptr);
     384             :             readClient->Close(CHIP_NO_ERROR);
     385             :             readClient = tmpClient;
     386             :         }
     387             : 
     388             :         //
     389             :         // After that, we just null out our tracker.
     390             :         //
     391             :         mpActiveReadClientList = nullptr;
     392             : #endif // CHIP_CONFIG_ENABLE_READ_CLIENT
     393             : 
     394             :         mReadHandlers.ReleaseAll();
     395             :     }
     396             : #endif
     397             : 
     398             : private:
     399             :     friend class reporting::Engine;
     400             :     friend class TestCommandInteraction;
     401             :     friend class TestInteractionModelEngine;
     402             :     friend class SubscriptionResumptionSessionEstablisher;
     403             :     using Status = Protocols::InteractionModel::Status;
     404             : 
     405             :     void OnDone(CommandHandler & apCommandObj) override;
     406             :     void OnDone(ReadHandler & apReadObj) override;
     407             : 
     408        1388 :     ReadHandler::ApplicationCallback * GetAppCallback() override { return mpReadHandlerApplicationCallback; }
     409             : 
     410       12760 :     InteractionModelEngine * GetInteractionModelEngine() override { return this; }
     411             : 
     412             :     CHIP_ERROR OnUnsolicitedMessageReceived(const PayloadHeader & payloadHeader, ExchangeDelegate *& newDelegate) override;
     413             : 
     414             :     /**
     415             :      * Called when Interaction Model receives a Command Request message.
     416             :      */
     417             :     Status OnInvokeCommandRequest(Messaging::ExchangeContext * apExchangeContext, const PayloadHeader & aPayloadHeader,
     418             :                                   System::PacketBufferHandle && aPayload, bool aIsTimedInvoke);
     419             :     CHIP_ERROR OnMessageReceived(Messaging::ExchangeContext * apExchangeContext, const PayloadHeader & aPayloadHeader,
     420             :                                  System::PacketBufferHandle && aPayload) override;
     421             :     void OnResponseTimeout(Messaging::ExchangeContext * ec) override;
     422             : 
     423             :     /**
     424             :      * This parses the attribute path list to ensure it is well formed. If so, for each path in the list, it will expand to a list
     425             :      * of concrete paths and walk each path to check if it has privileges to read that attribute.
     426             :      *
     427             :      * If there is AT LEAST one "existent path" (as the spec calls it) that has sufficient privilege, aHasValidAttributePath
     428             :      * will be set to true. Otherwise, it will be set to false.
     429             :      *
     430             :      * aRequestedAttributePathCount will be updated to reflect the number of attribute paths in the request.
     431             :      *
     432             :      *
     433             :      */
     434             :     static CHIP_ERROR ParseAttributePaths(const Access::SubjectDescriptor & aSubjectDescriptor,
     435             :                                           AttributePathIBs::Parser & aAttributePathListParser, bool & aHasValidAttributePath,
     436             :                                           size_t & aRequestedAttributePathCount);
     437             : 
     438             :     /**
     439             :      * This parses the event path list to ensure it is well formed. If so, for each path in the list, it will expand to a list
     440             :      * of concrete paths and walk each path to check if it has privileges to read that event.
     441             :      *
     442             :      * If there is AT LEAST one "existent path" (as the spec calls it) that has sufficient privilege, aHasValidEventPath
     443             :      * will be set to true. Otherwise, it will be set to false.
     444             :      *
     445             :      * aRequestedEventPathCount will be updated to reflect the number of event paths in the request.
     446             :      */
     447             :     static CHIP_ERROR ParseEventPaths(const Access::SubjectDescriptor & aSubjectDescriptor,
     448             :                                       EventPathIBs::Parser & aEventPathListParser, bool & aHasValidEventPath,
     449             :                                       size_t & aRequestedEventPathCount);
     450             : 
     451             :     /**
     452             :      * Called when Interaction Model receives a Read Request message.  Errors processing
     453             :      * the Read Request are handled entirely within this function.  If the
     454             :      * status returned is not Status::Success, the caller will send a status
     455             :      * response message with that status.
     456             :      */
     457             :     Status OnReadInitialRequest(Messaging::ExchangeContext * apExchangeContext, const PayloadHeader & aPayloadHeader,
     458             :                                 System::PacketBufferHandle && aPayload, ReadHandler::InteractionType aInteractionType);
     459             : 
     460             :     /**
     461             :      * Called when Interaction Model receives a Write Request message.  Errors processing
     462             :      * the Write Request are handled entirely within this function. If the
     463             :      * status returned is not Status::Success, the caller will send a status
     464             :      * response message with that status.
     465             :      */
     466             :     Status OnWriteRequest(Messaging::ExchangeContext * apExchangeContext, const PayloadHeader & aPayloadHeader,
     467             :                           System::PacketBufferHandle && aPayload, bool aIsTimedWrite);
     468             : 
     469             :     /**
     470             :      * Called when Interaction Model receives a Timed Request message.  Errors processing
     471             :      * the Timed Request are handled entirely within this function. The caller pre-sets status to failure and the callee is
     472             :      * expected to set it to success if it does not want an automatic status response message to be sent.
     473             :      */
     474             :     CHIP_ERROR OnTimedRequest(Messaging::ExchangeContext * apExchangeContext, const PayloadHeader & aPayloadHeader,
     475             :                               System::PacketBufferHandle && aPayload, Protocols::InteractionModel::Status & aStatus);
     476             : 
     477             :     /**This function handles processing of un-solicited ReportData messages on the client, which can
     478             :      * only occur post subscription establishment
     479             :      */
     480             :     Status OnUnsolicitedReportData(Messaging::ExchangeContext * apExchangeContext, const PayloadHeader & aPayloadHeader,
     481             :                                    System::PacketBufferHandle && aPayload);
     482             : 
     483             :     void DispatchCommand(CommandHandler & apCommandObj, const ConcreteCommandPath & aCommandPath,
     484             :                          TLV::TLVReader & apPayload) override;
     485             :     Protocols::InteractionModel::Status CommandExists(const ConcreteCommandPath & aCommandPath) override;
     486             : 
     487             :     bool HasActiveRead();
     488             : 
     489         136 :     inline size_t GetPathPoolCapacityForReads() const
     490             :     {
     491             : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
     492         136 :         return (mPathPoolCapacityForReadsOverride == -1) ? CHIP_IM_SERVER_MAX_NUM_PATH_GROUPS_FOR_READS
     493         136 :                                                          : static_cast<size_t>(mPathPoolCapacityForReadsOverride);
     494             : #else
     495             :         return CHIP_IM_SERVER_MAX_NUM_PATH_GROUPS_FOR_READS;
     496             : #endif
     497             :     }
     498             : 
     499         821 :     inline size_t GetReadHandlerPoolCapacityForReads() const
     500             :     {
     501             : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
     502         821 :         return (mReadHandlerCapacityForReadsOverride == -1) ? CHIP_IM_MAX_NUM_READS
     503         821 :                                                             : static_cast<size_t>(mReadHandlerCapacityForReadsOverride);
     504             : #else
     505             :         return CHIP_IM_MAX_NUM_READS;
     506             : #endif
     507             :     }
     508             : 
     509         237 :     inline size_t GetPathPoolCapacityForSubscriptions() const
     510             :     {
     511             : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
     512         237 :         return (mPathPoolCapacityForSubscriptionsOverride == -1) ? CHIP_IM_SERVER_MAX_NUM_PATH_GROUPS_FOR_SUBSCRIPTIONS
     513         237 :                                                                  : static_cast<size_t>(mPathPoolCapacityForSubscriptionsOverride);
     514             : #else
     515             :         return CHIP_IM_SERVER_MAX_NUM_PATH_GROUPS_FOR_SUBSCRIPTIONS;
     516             : #endif
     517             :     }
     518             : 
     519         237 :     inline size_t GetReadHandlerPoolCapacityForSubscriptions() const
     520             :     {
     521             : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
     522         237 :         return (mReadHandlerCapacityForSubscriptionsOverride == -1)
     523         237 :             ? CHIP_IM_MAX_NUM_SUBSCRIPTIONS
     524         237 :             : static_cast<size_t>(mReadHandlerCapacityForSubscriptionsOverride);
     525             : #else
     526             :         return CHIP_IM_MAX_NUM_SUBSCRIPTIONS;
     527             : #endif
     528             :     }
     529             : 
     530         786 :     inline uint8_t GetConfigMaxFabrics() const
     531             :     {
     532             : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
     533         786 :         return (mMaxNumFabricsOverride == -1) ? CHIP_CONFIG_MAX_FABRICS : static_cast<uint8_t>(mMaxNumFabricsOverride);
     534             : #else
     535             :         return CHIP_CONFIG_MAX_FABRICS;
     536             : #endif
     537             :     }
     538             : 
     539         753 :     inline size_t GetGuaranteedReadRequestsPerFabric() const
     540             :     {
     541         753 :         return GetReadHandlerPoolCapacityForReads() / GetConfigMaxFabrics();
     542             :     }
     543             : 
     544             :     /**
     545             :      * Verify and ensure (by killing oldest read handlers that make the resources used by the current fabric exceed the fabric
     546             :      * quota)
     547             :      * - If the subscription uses resources within the per subscription limit, this function will always success by evicting
     548             :      * existing subscriptions.
     549             :      * - If the subscription uses more than per subscription limit, this function will return PATHS_EXHAUSTED if we are running out
     550             :      * of paths.
     551             :      *
     552             :      * After the checks above, we will try to ensure we have a free Readhandler for processing the subscription.
     553             :      *
     554             :      * @retval true when we have enough resources for the incoming subscription, false if not.
     555             :      */
     556             :     bool EnsureResourceForSubscription(FabricIndex aFabricIndex, size_t aRequestedAttributePathCount,
     557             :                                        size_t aRequestedEventPathCount);
     558             : 
     559             :     /**
     560             :      * Verify and ensure (by killing oldest read handlers that make the resources used by the current fabric exceed the fabric
     561             :      * quota) the resources for handling a new read transaction with the given resource requirments.
     562             :      * - PASE sessions will be counted in a virtual fabric (i.e. kInvalidFabricIndex will be consided as a "valid" fabric in this
     563             :      * function)
     564             :      * - If the existing resources can serve this read transaction, this function will return Status::Success.
     565             :      * - or if the resources used by read transactions in the fabric index meets the per fabric resource limit (i.e. 9 paths & 1
     566             :      * read) after accepting this read request, this function will always return Status::Success by evicting existing read
     567             :      * transactions from other fabrics which are using more than the guaranteed minimum number of read.
     568             :      * - or if the resources used by read transactions in the fabric index will exceed the per fabric resource limit (i.e. 9 paths &
     569             :      * 1 read) after accepting this read request, this function will return a failure status without evicting any existing
     570             :      * transaction.
     571             :      * - However, read transactions on PASE sessions won't evict any existing read transactions when we have already commissioned
     572             :      * CHIP_CONFIG_MAX_FABRICS fabrics on the device.
     573             :      *
     574             :      * @retval Status::Success: The read transaction can be accepted.
     575             :      * @retval Status::Busy: The remaining resource is insufficient to handle this read request, and the accessing fabric for this
     576             :      * read request will use more resources than we guaranteed, the client is expected to retry later.
     577             :      * @retval Status::PathsExhausted: The attribute / event path pool is exhausted, and the read request is requesting more
     578             :      * resources than we guaranteed.
     579             :      */
     580             :     Status EnsureResourceForRead(FabricIndex aFabricIndex, size_t aRequestedAttributePathCount, size_t aRequestedEventPathCount);
     581             : 
     582             :     /**
     583             :      * Helper for various ShutdownSubscriptions functions.  The subscriptions
     584             :      * that match all the provided arguments will be shut down.
     585             :      */
     586             :     void ShutdownMatchingSubscriptions(const Optional<FabricIndex> & aFabricIndex = NullOptional,
     587             :                                        const Optional<NodeId> & aPeerNodeId       = NullOptional);
     588             : 
     589             :     static void ResumeSubscriptionsTimerCallback(System::Layer * apSystemLayer, void * apAppState);
     590             : 
     591             :     template <typename T, size_t N>
     592             :     void ReleasePool(ObjectList<T> *& aObjectList, ObjectPool<ObjectList<T>, N> & aObjectPool);
     593             :     template <typename T, size_t N>
     594             :     CHIP_ERROR PushFront(ObjectList<T> *& aObjectList, T & aData, ObjectPool<ObjectList<T>, N> & aObjectPool);
     595             : 
     596             :     Messaging::ExchangeManager * mpExchangeMgr = nullptr;
     597             : 
     598             :     CommandHandlerInterface * mCommandHandlerList = nullptr;
     599             : 
     600             :     ObjectPool<CommandHandler, CHIP_IM_MAX_NUM_COMMAND_HANDLER> mCommandHandlerObjs;
     601             :     ObjectPool<TimedHandler, CHIP_IM_MAX_NUM_TIMED_HANDLER> mTimedHandlers;
     602             :     WriteHandler mWriteHandlers[CHIP_IM_MAX_NUM_WRITE_HANDLER];
     603             :     reporting::Engine mReportingEngine;
     604             :     reporting::ReportScheduler * mReportScheduler = nullptr;
     605             : 
     606             :     static constexpr size_t kReservedHandlersForReads = kMinSupportedReadRequestsPerFabric * (CHIP_CONFIG_MAX_FABRICS);
     607             :     static constexpr size_t kReservedPathsForReads    = kMinSupportedPathsPerReadRequest * kReservedHandlersForReads;
     608             : 
     609             : #if !CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
     610             :     static_assert(CHIP_IM_SERVER_MAX_NUM_PATH_GROUPS_FOR_SUBSCRIPTIONS >=
     611             :                       CHIP_CONFIG_MAX_FABRICS * (kMinSupportedPathsPerSubscription * kMinSupportedSubscriptionsPerFabric),
     612             :                   "CHIP_IM_SERVER_MAX_NUM_PATH_GROUPS_FOR_SUBSCRIPTIONS is too small to match the requirements of spec 8.5.1");
     613             :     static_assert(CHIP_IM_SERVER_MAX_NUM_PATH_GROUPS_FOR_READS >=
     614             :                       CHIP_CONFIG_MAX_FABRICS * (kMinSupportedReadRequestsPerFabric * kMinSupportedPathsPerReadRequest),
     615             :                   "CHIP_IM_SERVER_MAX_NUM_PATH_GROUPS_FOR_READS is too small to match the requirements of spec 8.5.1");
     616             :     static_assert(CHIP_IM_MAX_NUM_SUBSCRIPTIONS >= CHIP_CONFIG_MAX_FABRICS * kMinSupportedSubscriptionsPerFabric,
     617             :                   "CHIP_IM_MAX_NUM_SUBSCRIPTIONS is too small to match the requirements of spec 8.5.1");
     618             :     static_assert(CHIP_IM_MAX_NUM_READS >= CHIP_CONFIG_MAX_FABRICS * kMinSupportedReadRequestsPerFabric,
     619             :                   "CHIP_IM_MAX_NUM_READS is too small to match the requirements of spec 8.5.1");
     620             : #endif
     621             : 
     622             :     ObjectPool<ObjectList<AttributePathParams>,
     623             :                CHIP_IM_SERVER_MAX_NUM_PATH_GROUPS_FOR_READS + CHIP_IM_SERVER_MAX_NUM_PATH_GROUPS_FOR_SUBSCRIPTIONS>
     624             :         mAttributePathPool;
     625             :     ObjectPool<ObjectList<EventPathParams>,
     626             :                CHIP_IM_SERVER_MAX_NUM_PATH_GROUPS_FOR_READS + CHIP_IM_SERVER_MAX_NUM_PATH_GROUPS_FOR_SUBSCRIPTIONS>
     627             :         mEventPathPool;
     628             :     ObjectPool<ObjectList<DataVersionFilter>,
     629             :                CHIP_IM_SERVER_MAX_NUM_PATH_GROUPS_FOR_READS + CHIP_IM_SERVER_MAX_NUM_PATH_GROUPS_FOR_SUBSCRIPTIONS>
     630             :         mDataVersionFilterPool;
     631             : 
     632             :     ObjectPool<ReadHandler, CHIP_IM_MAX_NUM_READS + CHIP_IM_MAX_NUM_SUBSCRIPTIONS> mReadHandlers;
     633             : 
     634             : #if CHIP_CONFIG_ENABLE_READ_CLIENT
     635             :     ReadClient * mpActiveReadClientList = nullptr;
     636             : #endif
     637             : 
     638             :     ReadHandler::ApplicationCallback * mpReadHandlerApplicationCallback = nullptr;
     639             : 
     640             : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
     641             :     int mReadHandlerCapacityForSubscriptionsOverride = -1;
     642             :     int mPathPoolCapacityForSubscriptionsOverride    = -1;
     643             : 
     644             :     int mReadHandlerCapacityForReadsOverride = -1;
     645             :     int mPathPoolCapacityForReadsOverride    = -1;
     646             : 
     647             :     int mMaxNumFabricsOverride = -1;
     648             : 
     649             :     // We won't limit the handler used per fabric on platforms that are using heap for memory pools, so we introduces a flag to
     650             :     // enforce such check based on the configured size. This flag is used for unit tests only, there is another compare time flag
     651             :     // CHIP_CONFIG_IM_FORCE_FABRIC_QUOTA_CHECK for stress tests.
     652             :     bool mForceHandlerQuota = false;
     653             : #endif
     654             : 
     655             : #if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS && CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION
     656             :     bool HasSubscriptionsToResume();
     657             :     uint32_t ComputeTimeSecondsTillNextSubscriptionResumption();
     658             :     uint32_t mNumSubscriptionResumptionRetries = 0;
     659             :     bool mSubscriptionResumptionScheduled      = false;
     660             : #endif
     661             : 
     662             :     FabricTable * mpFabricTable;
     663             : 
     664             :     CASESessionManager * mpCASESessionMgr = nullptr;
     665             : 
     666             :     SubscriptionResumptionStorage * mpSubscriptionResumptionStorage = nullptr;
     667             : 
     668             :     // A magic number for tracking values between stack Shutdown()-s and Init()-s.
     669             :     // An ObjectHandle is valid iff. its magic equals to this one.
     670             :     uint32_t mMagic = 0;
     671             : };
     672             : 
     673             : void DispatchSingleClusterCommand(const ConcreteCommandPath & aCommandPath, chip::TLV::TLVReader & aReader,
     674             :                                   CommandHandler * apCommandObj);
     675             : 
     676             : /**
     677             :  *  Check whether the given cluster exists on the given endpoint and supports
     678             :  *  the given command.  If it does, Success will be returned.  If it does not,
     679             :  *  one of UnsupportedEndpoint, UnsupportedCluster, or UnsupportedCommand
     680             :  *  will be returned, depending on how the command fails to exist.
     681             :  */
     682             : Protocols::InteractionModel::Status ServerClusterCommandExists(const ConcreteCommandPath & aCommandPath);
     683             : 
     684             : /**
     685             :  *  Fetch attribute value and version info and write to the AttributeReport provided.
     686             :  *  The ReadSingleClusterData will do everything required for encoding an attribute, i.e. it will try to put one or more
     687             :  * AttributeReportIB to the AttributeReportIBs::Builder.
     688             :  *  When the endpoint / cluster / attribute data specified by aPath does not exist, corresponding interaction
     689             :  * model error code will be put into aAttributeReports, and CHIP_NO_ERROR will be returned. If the data exists on the server, the
     690             :  * data (with tag kData) and the data version (with tag kDataVersion) will be put into aAttributeReports. TLVWriter error will be
     691             :  * returned if any error occurred while encoding these values. This function is implemented by CHIP as a part of cluster data
     692             :  * storage & management.
     693             :  *
     694             :  *  @param[in]    aSubjectDescriptor    The subject descriptor for the read.
     695             :  *  @param[in]    aPath                 The concrete path of the data being read.
     696             :  *  @param[in]    aAttributeReports      The TLV Builder for Cluter attribute builder.
     697             :  *
     698             :  *  @retval  CHIP_NO_ERROR on success
     699             :  */
     700             : CHIP_ERROR ReadSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, bool aIsFabricFiltered,
     701             :                                  const ConcreteReadAttributePath & aPath, AttributeReportIBs::Builder & aAttributeReports,
     702             :                                  AttributeValueEncoder::AttributeEncodeState * apEncoderState);
     703             : 
     704             : /**
     705             :  *  Check whether concrete attribute path is an "existent attribute path" in spec terms.
     706             :  *  @param[in]    aPath                 The concrete path of the data being read.
     707             :  *  @retval  boolean   true if the concrete attribute path indicates an attribute that exists on the node.
     708             :  */
     709             : bool ConcreteAttributePathExists(const ConcreteAttributePath & aPath);
     710             : 
     711             : /**
     712             :  *  Get the registered attribute access override. nullptr when attribute access override is not found.
     713             :  *
     714             :  * TODO(#16806): This function and registerAttributeAccessOverride can be member functions of InteractionModelEngine.
     715             :  */
     716             : AttributeAccessInterface * GetAttributeAccessOverride(EndpointId aEndpointId, ClusterId aClusterId);
     717             : 
     718             : /**
     719             :  * TODO: Document.
     720             :  */
     721             : CHIP_ERROR WriteSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor,
     722             :                                   const ConcreteDataAttributePath & aAttributePath, TLV::TLVReader & aReader,
     723             :                                   WriteHandler * apWriteHandler);
     724             : 
     725             : /**
     726             :  * Check if the given cluster has the given DataVersion.
     727             :  */
     728             : bool IsClusterDataVersionEqual(const ConcreteClusterPath & aConcreteClusterPath, DataVersion aRequiredVersion);
     729             : 
     730             : /**
     731             :  * Returns true if device type is on endpoint, false otherwise.
     732             :  */
     733             : bool IsDeviceTypeOnEndpoint(DeviceTypeId deviceType, EndpointId endpoint);
     734             : 
     735             : /**
     736             :  * Returns the metadata of the attribute for the given path.
     737             :  *
     738             :  * @retval The metadata of the attribute, will return null if the given attribute does not exists.
     739             :  */
     740             : const EmberAfAttributeMetadata * GetAttributeMetadata(const ConcreteAttributePath & aPath);
     741             : 
     742             : /**
     743             :  * Returns the event support status for the given event, as an interaction model status.
     744             :  */
     745             : Protocols::InteractionModel::Status CheckEventSupportStatus(const ConcreteEventPath & aPath);
     746             : 
     747             : } // namespace app
     748             : } // namespace chip

Generated by: LCOV version 1.14