Matter SDK Coverage Report
Current view: top level - app - InteractionModelEngine.h (source / functions) Coverage Total Hit
Test: SHA:fd700f088ee2d8b07407ec02bd01329ac87109ab Lines: 98.0 % 50 49
Test Date: 2026-01-14 08:11:11 Functions: 96.2 % 26 25

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

Generated by: LCOV version 2.0-1