Matter SDK Coverage Report
Current view: top level - app - ReadHandler.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 84.7 % 425 360
Test Date: 2025-01-17 19:00:11 Functions: 90.6 % 32 29

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2020 Project CHIP Authors
       4              :  *    All rights reserved.
       5              :  *
       6              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       7              :  *    you may not use this file except in compliance with the License.
       8              :  *    You may obtain a copy of the License at
       9              :  *
      10              :  *        http://www.apache.org/licenses/LICENSE-2.0
      11              :  *
      12              :  *    Unless required by applicable law or agreed to in writing, software
      13              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      14              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15              :  *    See the License for the specific language governing permissions and
      16              :  *    limitations under the License.
      17              :  */
      18              : 
      19              : /**
      20              :  *    @file
      21              :  *      This file defines read handler for a CHIP Interaction Data model
      22              :  *
      23              :  */
      24              : 
      25              : #include <app/AppConfig.h>
      26              : #include <app/InteractionModelEngine.h>
      27              : #include <app/MessageDef/EventPathIB.h>
      28              : #include <app/MessageDef/StatusResponseMessage.h>
      29              : #include <app/MessageDef/SubscribeRequestMessage.h>
      30              : #include <app/MessageDef/SubscribeResponseMessage.h>
      31              : #include <app/data-model-provider/Provider.h>
      32              : #include <app/icd/server/ICDServerConfig.h>
      33              : #include <lib/core/TLVUtilities.h>
      34              : #include <messaging/ExchangeContext.h>
      35              : 
      36              : #include <app/ReadHandler.h>
      37              : #include <app/reporting/Engine.h>
      38              : 
      39              : #if CHIP_CONFIG_ENABLE_ICD_SERVER
      40              : #include <app/icd/server/ICDConfigurationData.h> //nogncheck
      41              : #endif
      42              : 
      43              : namespace chip {
      44              : namespace app {
      45              : using Status = Protocols::InteractionModel::Status;
      46              : 
      47           33 : uint16_t ReadHandler::GetPublisherSelectedIntervalLimit()
      48              : {
      49              : #if CHIP_CONFIG_ENABLE_ICD_SERVER
      50              :     return std::chrono::duration_cast<System::Clock::Seconds16>(ICDConfigurationData::GetInstance().GetIdleModeDuration()).count();
      51              : #else
      52           33 :     return kSubscriptionMaxIntervalPublisherLimit;
      53              : #endif
      54              : }
      55              : 
      56         1060 : ReadHandler::ReadHandler(ManagementCallback & apCallback, Messaging::ExchangeContext * apExchangeContext,
      57         1060 :                          InteractionType aInteractionType, Observer * observer, DataModel::Provider * apDataModel) :
      58         1060 :     mAttributePathExpandIterator(apDataModel, nullptr),
      59         1060 :     mExchangeCtx(*this), mManagementCallback(apCallback)
      60              : {
      61         1060 :     VerifyOrDie(apExchangeContext != nullptr);
      62              : 
      63         1060 :     mExchangeCtx.Grab(apExchangeContext);
      64              : #if CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
      65              :     // TODO: this should be replaced by a pointer to the InteractionModelEngine that created the ReadHandler
      66              :     // once InteractionModelEngine is no longer a singleton (see issue 23625)
      67              :     mExchangeMgr = apExchangeContext->GetExchangeMgr();
      68              : #endif // CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
      69              : 
      70         1060 :     mInteractionType            = aInteractionType;
      71         1060 :     mLastWrittenEventsBytes     = 0;
      72         1060 :     mTransactionStartGeneration = mManagementCallback.GetInteractionModelEngine()->GetReportingEngine().GetDirtySetGeneration();
      73         1060 :     mFlags.ClearAll();
      74         1060 :     SetStateFlag(ReadHandlerFlags::PrimingReports);
      75              : 
      76         1060 :     mSessionHandle.Grab(mExchangeCtx->GetSessionHandle());
      77              : 
      78         1060 :     VerifyOrDie(observer != nullptr);
      79         1060 :     mObserver = observer;
      80         1060 : }
      81              : 
      82              : #if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
      83            0 : ReadHandler::ReadHandler(ManagementCallback & apCallback, Observer * observer, DataModel::Provider * apDataModel) :
      84            0 :     mAttributePathExpandIterator(apDataModel, nullptr), mExchangeCtx(*this), mManagementCallback(apCallback)
      85              : {
      86            0 :     mInteractionType = InteractionType::Subscribe;
      87            0 :     mFlags.ClearAll();
      88              : 
      89            0 :     VerifyOrDie(observer != nullptr);
      90            0 :     mObserver = observer;
      91            0 : }
      92              : 
      93            0 : void ReadHandler::OnSubscriptionResumed(const SessionHandle & sessionHandle,
      94              :                                         SubscriptionResumptionSessionEstablisher & resumptionSessionEstablisher)
      95              : {
      96            0 :     mSubscriptionId          = resumptionSessionEstablisher.mSubscriptionInfo.mSubscriptionId;
      97            0 :     mMinIntervalFloorSeconds = resumptionSessionEstablisher.mSubscriptionInfo.mMinInterval;
      98            0 :     mMaxInterval             = resumptionSessionEstablisher.mSubscriptionInfo.mMaxInterval;
      99            0 :     SetStateFlag(ReadHandlerFlags::FabricFiltered, resumptionSessionEstablisher.mSubscriptionInfo.mFabricFiltered);
     100              : 
     101              :     // Move dynamically allocated attributes and events from the SubscriptionInfo struct into
     102              :     // the object pool managed by the IM engine
     103            0 :     for (size_t i = 0; i < resumptionSessionEstablisher.mSubscriptionInfo.mAttributePaths.AllocatedSize(); i++)
     104              :     {
     105            0 :         AttributePathParams params = resumptionSessionEstablisher.mSubscriptionInfo.mAttributePaths[i].GetParams();
     106            0 :         CHIP_ERROR err = mManagementCallback.GetInteractionModelEngine()->PushFrontAttributePathList(mpAttributePathList, params);
     107            0 :         if (err != CHIP_NO_ERROR)
     108              :         {
     109            0 :             Close();
     110            0 :             return;
     111              :         }
     112              :     }
     113            0 :     for (size_t i = 0; i < resumptionSessionEstablisher.mSubscriptionInfo.mEventPaths.AllocatedSize(); i++)
     114              :     {
     115            0 :         EventPathParams params = resumptionSessionEstablisher.mSubscriptionInfo.mEventPaths[i].GetParams();
     116            0 :         CHIP_ERROR err = mManagementCallback.GetInteractionModelEngine()->PushFrontEventPathParamsList(mpEventPathList, params);
     117            0 :         if (err != CHIP_NO_ERROR)
     118              :         {
     119            0 :             Close();
     120            0 :             return;
     121              :         }
     122              :     }
     123              : 
     124            0 :     mSessionHandle.Grab(sessionHandle);
     125              : 
     126            0 :     SetStateFlag(ReadHandlerFlags::ActiveSubscription);
     127              : 
     128            0 :     auto * appCallback = mManagementCallback.GetAppCallback();
     129            0 :     if (appCallback)
     130              :     {
     131            0 :         appCallback->OnSubscriptionEstablished(*this);
     132              :     }
     133              :     // Notify the observer that a subscription has been resumed
     134            0 :     mObserver->OnSubscriptionEstablished(this);
     135              : 
     136            0 :     MoveToState(HandlerState::CanStartReporting);
     137              : 
     138            0 :     SingleLinkedListNode<AttributePathParams> * attributePath = mpAttributePathList;
     139            0 :     while (attributePath)
     140              :     {
     141            0 :         mManagementCallback.GetInteractionModelEngine()->GetReportingEngine().SetDirty(attributePath->mValue);
     142            0 :         attributePath = attributePath->mpNext;
     143              :     }
     144              : }
     145              : 
     146              : #endif // CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
     147              : 
     148         1060 : ReadHandler::~ReadHandler()
     149              : {
     150         1060 :     mObserver->OnReadHandlerDestroyed(this);
     151              : 
     152         1060 :     auto * appCallback = mManagementCallback.GetAppCallback();
     153         1060 :     if (mFlags.Has(ReadHandlerFlags::ActiveSubscription) && appCallback)
     154              :     {
     155          167 :         mFlags.Clear(ReadHandlerFlags::ActiveSubscription);
     156          167 :         appCallback->OnSubscriptionTerminated(*this);
     157              :     }
     158              : 
     159         1060 :     if (IsAwaitingReportResponse())
     160              :     {
     161            2 :         mManagementCallback.GetInteractionModelEngine()->GetReportingEngine().OnReportConfirm();
     162              :     }
     163         1060 :     mManagementCallback.GetInteractionModelEngine()->ReleaseAttributePathList(mpAttributePathList);
     164         1060 :     mManagementCallback.GetInteractionModelEngine()->ReleaseEventPathList(mpEventPathList);
     165         1060 :     mManagementCallback.GetInteractionModelEngine()->ReleaseDataVersionFilterList(mpDataVersionFilterList);
     166         1060 : }
     167              : 
     168          798 : void ReadHandler::Close(CloseOptions options)
     169              : {
     170              : #if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
     171          798 :     if (IsType(InteractionType::Subscribe) && options == CloseOptions::kDropPersistedSubscription)
     172              :     {
     173           31 :         auto * subscriptionResumptionStorage = mManagementCallback.GetInteractionModelEngine()->GetSubscriptionResumptionStorage();
     174           31 :         if (subscriptionResumptionStorage)
     175              :         {
     176            0 :             subscriptionResumptionStorage->Delete(GetInitiatorNodeId(), GetAccessingFabricIndex(), mSubscriptionId);
     177              :         }
     178              :     }
     179              : #endif // CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
     180              : 
     181              : #if CHIP_PROGRESS_LOGGING
     182          798 :     if (IsType(InteractionType::Subscribe))
     183              :     {
     184           48 :         const ScopedNodeId & peer = mSessionHandle ? mSessionHandle->GetPeer() : ScopedNodeId();
     185           48 :         ChipLogProgress(DataManagement, "Subscription id 0x%" PRIx32 " from node " ChipLogFormatScopedNodeId " torn down",
     186              :                         mSubscriptionId, ChipLogValueScopedNodeId(peer));
     187              :     }
     188              : #endif // CHIP_PROGRESS_LOGGING
     189              : 
     190          798 :     MoveToState(HandlerState::AwaitingDestruction);
     191          798 :     mManagementCallback.OnDone(*this);
     192          798 : }
     193              : 
     194         1014 : void ReadHandler::OnInitialRequest(System::PacketBufferHandle && aPayload)
     195              : {
     196         1014 :     CHIP_ERROR err = CHIP_NO_ERROR;
     197         1014 :     System::PacketBufferHandle response;
     198              : 
     199         1014 :     if (IsType(InteractionType::Subscribe))
     200              :     {
     201          229 :         err = ProcessSubscribeRequest(std::move(aPayload));
     202              :     }
     203              :     else
     204              :     {
     205          785 :         err = ProcessReadRequest(std::move(aPayload));
     206              :     }
     207              : 
     208         1014 :     if (err != CHIP_NO_ERROR)
     209              :     {
     210            8 :         Status status = Status::InvalidAction;
     211            8 :         if (err.IsIMStatus())
     212              :         {
     213            0 :             status = StatusIB(err).mStatus;
     214              :         }
     215            8 :         StatusResponse::Send(status, mExchangeCtx.Get(), /* aExpectResponse = */ false);
     216              :         // At this point we can't have a persisted subscription, since that
     217              :         // happens only when ProcessSubscribeRequest returns success. And our
     218              :         // subscription id is almost certainly not actually useful at this
     219              :         // point, either.  So don't try to mess with persisted subscriptions in
     220              :         // Close().
     221            8 :         Close(CloseOptions::kKeepPersistedSubscription);
     222              :     }
     223              :     else
     224              :     {
     225              :         // Force us to be in a dirty state so we get processed by the reporting
     226         1006 :         SetStateFlag(ReadHandlerFlags::ForceDirty);
     227              :     }
     228         1014 : }
     229              : 
     230         1155 : CHIP_ERROR ReadHandler::OnStatusResponse(Messaging::ExchangeContext * apExchangeContext, System::PacketBufferHandle && aPayload,
     231              :                                          bool & aSendStatusResponse)
     232              : {
     233         1155 :     CHIP_ERROR err         = CHIP_NO_ERROR;
     234         1155 :     aSendStatusResponse    = true;
     235         1155 :     CHIP_ERROR statusError = CHIP_NO_ERROR;
     236         1155 :     SuccessOrExit(err = StatusResponse::ProcessStatusResponse(std::move(aPayload), statusError));
     237              :     // Since this is a valid Status Response message, we don't have to send a Status Response in reply to it.
     238         1153 :     aSendStatusResponse = false;
     239         1153 :     SuccessOrExit(err = statusError);
     240         1141 :     switch (mState)
     241              :     {
     242         1141 :     case HandlerState::AwaitingReportResponse:
     243         1141 :         if (IsChunkedReport())
     244              :         {
     245          853 :             mExchangeCtx->WillSendMessage();
     246              :         }
     247          288 :         else if (IsType(InteractionType::Subscribe))
     248              :         {
     249          288 :             if (IsPriming())
     250              :             {
     251          211 :                 err = SendSubscribeResponse();
     252              : 
     253          211 :                 SetStateFlag(ReadHandlerFlags::ActiveSubscription);
     254              : 
     255          211 :                 auto * appCallback = mManagementCallback.GetAppCallback();
     256          211 :                 if (appCallback)
     257              :                 {
     258          167 :                     appCallback->OnSubscriptionEstablished(*this);
     259              :                 }
     260          211 :                 mObserver->OnSubscriptionEstablished(this);
     261              :             }
     262              :         }
     263              :         else
     264              :         {
     265              :             //
     266              :             // We're done processing a read, so let's close out and return.
     267              :             //
     268            0 :             Close();
     269            0 :             return CHIP_NO_ERROR;
     270              :         }
     271              : 
     272         1141 :         MoveToState(HandlerState::CanStartReporting);
     273         1141 :         break;
     274              : 
     275            0 :     case HandlerState::CanStartReporting:
     276              :     case HandlerState::Idle:
     277              :     default:
     278            0 :         err = CHIP_ERROR_INCORRECT_STATE;
     279            0 :         break;
     280              :     }
     281              : 
     282         1155 : exit:
     283         1155 :     return err;
     284              : }
     285              : 
     286           31 : CHIP_ERROR ReadHandler::SendStatusReport(Protocols::InteractionModel::Status aStatus)
     287              : {
     288           31 :     VerifyOrReturnLogError(mState == HandlerState::CanStartReporting, CHIP_ERROR_INCORRECT_STATE);
     289           31 :     if (IsPriming() || IsChunkedReport())
     290              :     {
     291           31 :         mSessionHandle.Grab(mExchangeCtx->GetSessionHandle());
     292              :     }
     293              :     else
     294              :     {
     295            0 :         VerifyOrReturnLogError(!mExchangeCtx, CHIP_ERROR_INCORRECT_STATE);
     296            0 :         VerifyOrReturnLogError(mSessionHandle, CHIP_ERROR_INCORRECT_STATE);
     297              : #if CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
     298              :         auto exchange = mExchangeMgr->NewContext(mSessionHandle.Get().Value(), this);
     299              : #else  // CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
     300              :         auto exchange =
     301            0 :             mManagementCallback.GetInteractionModelEngine()->GetExchangeManager()->NewContext(mSessionHandle.Get().Value(), this);
     302              : #endif // CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
     303            0 :         VerifyOrReturnLogError(exchange != nullptr, CHIP_ERROR_INCORRECT_STATE);
     304            0 :         mExchangeCtx.Grab(exchange);
     305              :     }
     306              : 
     307           31 :     VerifyOrReturnLogError(mExchangeCtx, CHIP_ERROR_INCORRECT_STATE);
     308           31 :     return StatusResponse::Send(aStatus, mExchangeCtx.Get(), /* aExpectResponse = */ false);
     309              : }
     310              : 
     311         1879 : CHIP_ERROR ReadHandler::SendReportData(System::PacketBufferHandle && aPayload, bool aMoreChunks)
     312              : {
     313         1879 :     VerifyOrReturnLogError(mState == HandlerState::CanStartReporting, CHIP_ERROR_INCORRECT_STATE);
     314         1875 :     VerifyOrDie(!IsAwaitingReportResponse()); // Should not be reportable!
     315         1875 :     if (IsPriming() || IsChunkedReport())
     316              :     {
     317         1784 :         mSessionHandle.Grab(mExchangeCtx->GetSessionHandle());
     318              :     }
     319              :     else
     320              :     {
     321           91 :         VerifyOrReturnLogError(!mExchangeCtx, CHIP_ERROR_INCORRECT_STATE);
     322           91 :         VerifyOrReturnLogError(mSessionHandle, CHIP_ERROR_INCORRECT_STATE);
     323              : #if CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
     324              :         auto exchange = mExchangeMgr->NewContext(mSessionHandle.Get().Value(), this);
     325              : #else  // CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
     326              :         auto exchange =
     327           91 :             mManagementCallback.GetInteractionModelEngine()->GetExchangeManager()->NewContext(mSessionHandle.Get().Value(), this);
     328              : #endif // CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
     329           91 :         VerifyOrReturnLogError(exchange != nullptr, CHIP_ERROR_INCORRECT_STATE);
     330           89 :         mExchangeCtx.Grab(exchange);
     331              :     }
     332              : 
     333         1873 :     VerifyOrReturnLogError(mExchangeCtx, CHIP_ERROR_INCORRECT_STATE);
     334              : 
     335         1873 :     if (!IsReporting())
     336              :     {
     337         1064 :         mCurrentReportsBeginGeneration =
     338         1064 :             mManagementCallback.GetInteractionModelEngine()->GetReportingEngine().GetDirtySetGeneration();
     339              :     }
     340         1873 :     SetStateFlag(ReadHandlerFlags::ChunkedReport, aMoreChunks);
     341         1873 :     bool responseExpected = IsType(InteractionType::Subscribe) || aMoreChunks;
     342              : 
     343         1873 :     mExchangeCtx->UseSuggestedResponseTimeout(app::kExpectedIMProcessingTime);
     344         1873 :     CHIP_ERROR err = mExchangeCtx->SendMessage(Protocols::InteractionModel::MsgType::ReportData, std::move(aPayload),
     345              :                                                responseExpected ? Messaging::SendMessageFlags::kExpectResponse
     346              :                                                                 : Messaging::SendMessageFlags::kNone);
     347         1873 :     if (err == CHIP_NO_ERROR)
     348              :     {
     349         1871 :         if (responseExpected)
     350              :         {
     351         1169 :             MoveToState(HandlerState::AwaitingReportResponse);
     352              :         }
     353              :         else
     354              :         {
     355              :             // Make sure we're not treated as an in-flight report waiting for a
     356              :             // response by the reporting engine.
     357          702 :             mManagementCallback.GetInteractionModelEngine()->GetReportingEngine().OnReportConfirm();
     358              :         }
     359              : 
     360              :         // If we just finished a non-priming subscription report, notify our observers.
     361              :         // Priming reports are handled when we send a SubscribeResponse.
     362         1871 :         if (IsType(InteractionType::Subscribe) && !IsPriming() && !IsChunkedReport())
     363              :         {
     364           87 :             mObserver->OnSubscriptionReportSent(this);
     365              :         }
     366              :     }
     367         1873 :     if (!aMoreChunks)
     368              :     {
     369         1010 :         mPreviousReportsBeginGeneration = mCurrentReportsBeginGeneration;
     370         1010 :         ClearForceDirtyFlag();
     371         1010 :         mManagementCallback.GetInteractionModelEngine()->ReleaseDataVersionFilterList(mpDataVersionFilterList);
     372              :     }
     373              : 
     374         1873 :     return err;
     375              : }
     376              : 
     377         1157 : CHIP_ERROR ReadHandler::OnMessageReceived(Messaging::ExchangeContext * apExchangeContext, const PayloadHeader & aPayloadHeader,
     378              :                                           System::PacketBufferHandle && aPayload)
     379              : {
     380         1157 :     CHIP_ERROR err          = CHIP_NO_ERROR;
     381         1157 :     bool sendStatusResponse = true;
     382         1157 :     if (aPayloadHeader.HasMessageType(Protocols::InteractionModel::MsgType::StatusResponse))
     383              :     {
     384         1155 :         err = OnStatusResponse(apExchangeContext, std::move(aPayload), sendStatusResponse);
     385              :     }
     386              :     else
     387              :     {
     388            2 :         ChipLogDetail(DataManagement, "ReadHandler:: Msg type %d not supported", aPayloadHeader.GetMessageType());
     389            2 :         err = CHIP_ERROR_INVALID_MESSAGE_TYPE;
     390              :     }
     391              : 
     392         1157 :     if (sendStatusResponse)
     393              :     {
     394            4 :         StatusResponse::Send(Status::InvalidAction, apExchangeContext, false /*aExpectResponse*/);
     395              :     }
     396              : 
     397         1157 :     if (err != CHIP_NO_ERROR)
     398              :     {
     399           16 :         Close();
     400              :     }
     401         1157 :     return err;
     402              : }
     403              : 
     404            5 : bool ReadHandler::IsFromSubscriber(Messaging::ExchangeContext & apExchangeContext) const
     405              : {
     406            5 :     return (IsType(InteractionType::Subscribe) &&
     407           15 :             GetInitiatorNodeId() == apExchangeContext.GetSessionHandle()->AsSecureSession()->GetPeerNodeId() &&
     408           10 :             GetAccessingFabricIndex() == apExchangeContext.GetSessionHandle()->GetFabricIndex());
     409              : }
     410              : 
     411           11 : void ReadHandler::OnResponseTimeout(Messaging::ExchangeContext * apExchangeContext)
     412              : {
     413           11 :     ChipLogError(DataManagement, "Time out! failed to receive status response from Exchange: " ChipLogFormatExchange,
     414              :                  ChipLogValueExchange(apExchangeContext));
     415              : #if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
     416           11 :     Close(CloseOptions::kKeepPersistedSubscription);
     417              : #else
     418              :     Close();
     419              : #endif
     420           11 : }
     421              : 
     422          789 : CHIP_ERROR ReadHandler::ProcessReadRequest(System::PacketBufferHandle && aPayload)
     423              : {
     424          789 :     CHIP_ERROR err = CHIP_NO_ERROR;
     425          789 :     System::PacketBufferTLVReader reader;
     426              : 
     427          789 :     ReadRequestMessage::Parser readRequestParser;
     428          789 :     EventPathIBs::Parser eventPathListParser;
     429          789 :     EventFilterIBs::Parser eventFilterIBsParser;
     430          789 :     AttributePathIBs::Parser attributePathListParser;
     431              : 
     432          789 :     reader.Init(std::move(aPayload));
     433              : 
     434          789 :     ReturnErrorOnFailure(readRequestParser.Init(reader));
     435              : 
     436              :     // No need to pretty-print here.  We pretty-print read requests in the read
     437              :     // case of InteractionModelEngine::OnReadInitialRequest, so we do it even if
     438              :     // we reject a read request.
     439              : 
     440          789 :     err = readRequestParser.GetAttributeRequests(&attributePathListParser);
     441          789 :     if (err == CHIP_END_OF_TLV)
     442              :     {
     443          121 :         err = CHIP_NO_ERROR;
     444              :     }
     445          668 :     else if (err == CHIP_NO_ERROR)
     446              :     {
     447          668 :         ReturnErrorOnFailure(ProcessAttributePaths(attributePathListParser));
     448          668 :         DataVersionFilterIBs::Parser dataVersionFilterListParser;
     449          668 :         err = readRequestParser.GetDataVersionFilters(&dataVersionFilterListParser);
     450          668 :         if (err == CHIP_END_OF_TLV)
     451              :         {
     452          588 :             err = CHIP_NO_ERROR;
     453              :         }
     454           80 :         else if (err == CHIP_NO_ERROR)
     455              :         {
     456           80 :             ReturnErrorOnFailure(ProcessDataVersionFilterList(dataVersionFilterListParser));
     457              :         }
     458              :     }
     459          789 :     ReturnErrorOnFailure(err);
     460          789 :     err = readRequestParser.GetEventRequests(&eventPathListParser);
     461          789 :     if (err == CHIP_END_OF_TLV)
     462              :     {
     463          472 :         err = CHIP_NO_ERROR;
     464              :     }
     465          317 :     else if (err == CHIP_NO_ERROR)
     466              :     {
     467          317 :         ReturnErrorOnFailure(err);
     468          317 :         ReturnErrorOnFailure(ProcessEventPaths(eventPathListParser));
     469          317 :         err = readRequestParser.GetEventFilters(&eventFilterIBsParser);
     470          317 :         if (err == CHIP_END_OF_TLV)
     471              :         {
     472            3 :             err = CHIP_NO_ERROR;
     473              :         }
     474          314 :         else if (err == CHIP_NO_ERROR)
     475              :         {
     476          314 :             ReturnErrorOnFailure(ProcessEventFilters(eventFilterIBsParser));
     477              :         }
     478              :     }
     479          789 :     ReturnErrorOnFailure(err);
     480              : 
     481              :     bool isFabricFiltered;
     482          789 :     ReturnErrorOnFailure(readRequestParser.GetIsFabricFiltered(&isFabricFiltered));
     483          785 :     SetStateFlag(ReadHandlerFlags::FabricFiltered, isFabricFiltered);
     484          785 :     ReturnErrorOnFailure(readRequestParser.ExitContainer());
     485          785 :     MoveToState(HandlerState::CanStartReporting);
     486              : 
     487          785 :     mExchangeCtx->WillSendMessage();
     488              : 
     489              :     // There must be no code after the WillSendMessage() call that can cause
     490              :     // this method to return a failure.
     491              : 
     492          785 :     return CHIP_NO_ERROR;
     493          789 : }
     494              : 
     495          895 : CHIP_ERROR ReadHandler::ProcessAttributePaths(AttributePathIBs::Parser & aAttributePathListParser)
     496              : {
     497          895 :     CHIP_ERROR err = CHIP_NO_ERROR;
     498          895 :     TLV::TLVReader reader;
     499          895 :     aAttributePathListParser.GetReader(&reader);
     500         2361 :     while (CHIP_NO_ERROR == (err = reader.Next()))
     501              :     {
     502         1466 :         VerifyOrReturnError(TLV::AnonymousTag() == reader.GetTag(), CHIP_ERROR_INVALID_TLV_TAG);
     503         1466 :         AttributePathParams attribute;
     504         1466 :         AttributePathIB::Parser path;
     505         1466 :         ReturnErrorOnFailure(path.Init(reader));
     506         1466 :         ReturnErrorOnFailure(path.ParsePath(attribute));
     507         1466 :         ReturnErrorOnFailure(
     508              :             mManagementCallback.GetInteractionModelEngine()->PushFrontAttributePathList(mpAttributePathList, attribute));
     509              :     }
     510              :     // if we have exhausted this container
     511          895 :     if (CHIP_END_OF_TLV == err)
     512              :     {
     513          895 :         mManagementCallback.GetInteractionModelEngine()->RemoveDuplicateConcreteAttributePath(mpAttributePathList);
     514          895 :         mAttributePathExpandIterator.ResetTo(mpAttributePathList);
     515          895 :         err = CHIP_NO_ERROR;
     516              :     }
     517          895 :     return err;
     518              : }
     519              : 
     520          145 : CHIP_ERROR ReadHandler::ProcessDataVersionFilterList(DataVersionFilterIBs::Parser & aDataVersionFilterListParser)
     521              : {
     522          145 :     CHIP_ERROR err = CHIP_NO_ERROR;
     523          145 :     TLV::TLVReader reader;
     524              : 
     525          145 :     aDataVersionFilterListParser.GetReader(&reader);
     526         2637 :     while (CHIP_NO_ERROR == (err = reader.Next()))
     527              :     {
     528         2492 :         VerifyOrReturnError(TLV::AnonymousTag() == reader.GetTag(), CHIP_ERROR_INVALID_TLV_TAG);
     529         2492 :         DataVersionFilter versionFilter;
     530         2492 :         ClusterPathIB::Parser path;
     531         2492 :         DataVersionFilterIB::Parser filter;
     532         2492 :         ReturnErrorOnFailure(filter.Init(reader));
     533         2492 :         DataVersion version = 0;
     534         2492 :         ReturnErrorOnFailure(filter.GetDataVersion(&version));
     535         2492 :         versionFilter.mDataVersion.SetValue(version);
     536         2492 :         ReturnErrorOnFailure(filter.GetPath(&path));
     537         2492 :         ReturnErrorOnFailure(path.GetEndpoint(&(versionFilter.mEndpointId)));
     538         2492 :         ReturnErrorOnFailure(path.GetCluster(&(versionFilter.mClusterId)));
     539         2492 :         VerifyOrReturnError(versionFilter.IsValidDataVersionFilter(), CHIP_ERROR_IM_MALFORMED_DATA_VERSION_FILTER_IB);
     540         2492 :         ReturnErrorOnFailure(mManagementCallback.GetInteractionModelEngine()->PushFrontDataVersionFilterList(
     541              :             mpDataVersionFilterList, versionFilter));
     542         2492 :     }
     543              : 
     544          145 :     if (CHIP_END_OF_TLV == err)
     545              :     {
     546          145 :         err = CHIP_NO_ERROR;
     547              :     }
     548          145 :     return err;
     549              : }
     550              : 
     551          335 : CHIP_ERROR ReadHandler::ProcessEventPaths(EventPathIBs::Parser & aEventPathsParser)
     552              : {
     553          335 :     CHIP_ERROR err = CHIP_NO_ERROR;
     554          335 :     TLV::TLVReader reader;
     555          335 :     aEventPathsParser.GetReader(&reader);
     556          832 :     while (CHIP_NO_ERROR == (err = reader.Next()))
     557              :     {
     558          497 :         VerifyOrReturnError(TLV::AnonymousTag() == reader.GetTag(), CHIP_ERROR_INVALID_TLV_TAG);
     559          497 :         EventPathParams event;
     560          497 :         EventPathIB::Parser path;
     561          497 :         ReturnErrorOnFailure(path.Init(reader));
     562          497 :         ReturnErrorOnFailure(path.ParsePath(event));
     563          497 :         ReturnErrorOnFailure(mManagementCallback.GetInteractionModelEngine()->PushFrontEventPathParamsList(mpEventPathList, event));
     564              :     }
     565              : 
     566              :     // if we have exhausted this container
     567          335 :     if (CHIP_END_OF_TLV == err)
     568              :     {
     569          335 :         err = CHIP_NO_ERROR;
     570              :     }
     571          335 :     return err;
     572              : }
     573              : 
     574          314 : CHIP_ERROR ReadHandler::ProcessEventFilters(EventFilterIBs::Parser & aEventFiltersParser)
     575              : {
     576          314 :     CHIP_ERROR err = CHIP_NO_ERROR;
     577          314 :     TLV::TLVReader reader;
     578          314 :     aEventFiltersParser.GetReader(&reader);
     579              : 
     580          628 :     while (CHIP_NO_ERROR == (err = reader.Next()))
     581              :     {
     582          314 :         VerifyOrReturnError(TLV::AnonymousTag() == reader.GetTag(), CHIP_ERROR_INVALID_TLV_TAG);
     583          314 :         EventFilterIB::Parser filter;
     584          314 :         ReturnErrorOnFailure(filter.Init(reader));
     585              :         // this is for current node, and would have only one event filter.
     586          314 :         ReturnErrorOnFailure(filter.GetEventMin(&(mEventMin)));
     587              :     }
     588          314 :     if (CHIP_END_OF_TLV == err)
     589              :     {
     590          314 :         err = CHIP_NO_ERROR;
     591              :     }
     592          314 :     return err;
     593              : }
     594              : 
     595         4134 : const char * ReadHandler::GetStateStr() const
     596              : {
     597              : #if CHIP_DETAIL_LOGGING
     598         4134 :     switch (mState)
     599              :     {
     600            4 :     case HandlerState::Idle:
     601            4 :         return "Idle";
     602          798 :     case HandlerState::AwaitingDestruction:
     603          798 :         return "AwaitingDestruction";
     604         2163 :     case HandlerState::CanStartReporting:
     605         2163 :         return "CanStartReporting";
     606              : 
     607         1169 :     case HandlerState::AwaitingReportResponse:
     608         1169 :         return "AwaitingReportResponse";
     609              :     }
     610              : #endif // CHIP_DETAIL_LOGGING
     611            0 :     return "N/A";
     612              : }
     613              : 
     614         4134 : void ReadHandler::MoveToState(const HandlerState aTargetState)
     615              : {
     616         4134 :     if (aTargetState == mState)
     617              :     {
     618            0 :         return;
     619              :     }
     620              : 
     621         4134 :     if (IsAwaitingReportResponse() && aTargetState != HandlerState::AwaitingReportResponse)
     622              :     {
     623         1167 :         mManagementCallback.GetInteractionModelEngine()->GetReportingEngine().OnReportConfirm();
     624              :     }
     625              : 
     626         4134 :     mState = aTargetState;
     627         4134 :     ChipLogDetail(DataManagement, "IM RH moving to [%s]", GetStateStr());
     628              : 
     629              :     //
     630              :     // If we just unblocked sending reports, let's go ahead and schedule the reporting
     631              :     // engine to run to kick that off.
     632              :     //
     633         4134 :     if (aTargetState == HandlerState::CanStartReporting)
     634              :     {
     635         2163 :         if (ShouldReportUnscheduled())
     636              :         {
     637         1842 :             mManagementCallback.GetInteractionModelEngine()->GetReportingEngine().ScheduleRun();
     638              :         }
     639              :         else
     640              :         {
     641              :             // If we became reportable, the scheduler will schedule a run as soon as allowed
     642          321 :             mObserver->OnBecameReportable(this);
     643              :         }
     644              :     }
     645              : }
     646              : 
     647          887 : bool ReadHandler::CheckEventClean(EventManagement & aEventManager)
     648              : {
     649          887 :     if (mFlags.Has(ReadHandlerFlags::ChunkedReport))
     650              :     {
     651          525 :         if ((mLastScheduledEventNumber != 0) && (mEventMin <= mLastScheduledEventNumber))
     652              :         {
     653          519 :             return false;
     654              :         }
     655              :     }
     656              :     else
     657              :     {
     658          362 :         EventNumber lastEventNumber = aEventManager.GetLastEventNumber();
     659          362 :         if ((lastEventNumber != 0) && (mEventMin <= lastEventNumber))
     660              :         {
     661              :             // We have more events. snapshot last event number
     662          344 :             aEventManager.SetScheduledEventInfo(mLastScheduledEventNumber, mLastWrittenEventsBytes);
     663          344 :             return false;
     664              :         }
     665              :     }
     666           24 :     return true;
     667              : }
     668              : 
     669          211 : CHIP_ERROR ReadHandler::SendSubscribeResponse()
     670              : {
     671          211 :     System::PacketBufferHandle packet = System::PacketBufferHandle::New(chip::app::kMaxSecureSduLengthBytes);
     672          211 :     VerifyOrReturnLogError(!packet.IsNull(), CHIP_ERROR_NO_MEMORY);
     673              : 
     674          211 :     System::PacketBufferTLVWriter writer;
     675          211 :     writer.Init(std::move(packet));
     676              : 
     677          211 :     SubscribeResponseMessage::Builder response;
     678          211 :     ReturnErrorOnFailure(response.Init(&writer));
     679          211 :     ReturnErrorOnFailure(response.SubscriptionId(mSubscriptionId).MaxInterval(mMaxInterval).EndOfSubscribeResponseMessage());
     680              : 
     681          211 :     ReturnErrorOnFailure(writer.Finalize(&packet));
     682          211 :     VerifyOrReturnLogError(mExchangeCtx, CHIP_ERROR_INCORRECT_STATE);
     683              : 
     684          211 :     ClearStateFlag(ReadHandlerFlags::PrimingReports);
     685          211 :     return mExchangeCtx->SendMessage(Protocols::InteractionModel::MsgType::SubscribeResponse, std::move(packet));
     686          211 : }
     687              : 
     688          233 : CHIP_ERROR ReadHandler::ProcessSubscribeRequest(System::PacketBufferHandle && aPayload)
     689              : {
     690          233 :     System::PacketBufferTLVReader reader;
     691          233 :     reader.Init(std::move(aPayload));
     692              : 
     693          233 :     SubscribeRequestMessage::Parser subscribeRequestParser;
     694          233 :     ReturnErrorOnFailure(subscribeRequestParser.Init(reader));
     695              : 
     696              :     // No need to pretty-print here.  We pretty-print subscribe requests in the
     697              :     // subscribe case of InteractionModelEngine::OnReadInitialRequest, so we do
     698              :     // it even if we reject a subscribe request.
     699              : 
     700          233 :     AttributePathIBs::Parser attributePathListParser;
     701          233 :     CHIP_ERROR err = subscribeRequestParser.GetAttributeRequests(&attributePathListParser);
     702          233 :     if (err == CHIP_END_OF_TLV)
     703              :     {
     704            6 :         err = CHIP_NO_ERROR;
     705              :     }
     706          227 :     else if (err == CHIP_NO_ERROR)
     707              :     {
     708          227 :         ReturnErrorOnFailure(ProcessAttributePaths(attributePathListParser));
     709          227 :         DataVersionFilterIBs::Parser dataVersionFilterListParser;
     710          227 :         err = subscribeRequestParser.GetDataVersionFilters(&dataVersionFilterListParser);
     711          227 :         if (err == CHIP_END_OF_TLV)
     712              :         {
     713          162 :             err = CHIP_NO_ERROR;
     714              :         }
     715           65 :         else if (err == CHIP_NO_ERROR)
     716              :         {
     717           65 :             ReturnErrorOnFailure(ProcessDataVersionFilterList(dataVersionFilterListParser));
     718              :         }
     719              :     }
     720          233 :     ReturnErrorOnFailure(err);
     721              : 
     722          233 :     EventPathIBs::Parser eventPathListParser;
     723          233 :     err = subscribeRequestParser.GetEventRequests(&eventPathListParser);
     724          233 :     if (err == CHIP_END_OF_TLV)
     725              :     {
     726          215 :         err = CHIP_NO_ERROR;
     727              :     }
     728           18 :     else if (err == CHIP_NO_ERROR)
     729              :     {
     730           18 :         ReturnErrorOnFailure(ProcessEventPaths(eventPathListParser));
     731           18 :         EventFilterIBs::Parser eventFilterIBsParser;
     732           18 :         err = subscribeRequestParser.GetEventFilters(&eventFilterIBsParser);
     733           18 :         if (err == CHIP_END_OF_TLV)
     734              :         {
     735           18 :             err = CHIP_NO_ERROR;
     736              :         }
     737            0 :         else if (err == CHIP_NO_ERROR)
     738              :         {
     739            0 :             ReturnErrorOnFailure(ProcessEventFilters(eventFilterIBsParser));
     740              :         }
     741              :     }
     742          233 :     ReturnErrorOnFailure(err);
     743              : 
     744          233 :     ReturnErrorOnFailure(subscribeRequestParser.GetMinIntervalFloorSeconds(&mMinIntervalFloorSeconds));
     745          233 :     ReturnErrorOnFailure(subscribeRequestParser.GetMaxIntervalCeilingSeconds(&mSubscriberRequestedMaxInterval));
     746          233 :     mMaxInterval = mSubscriberRequestedMaxInterval;
     747              : 
     748          233 :     VerifyOrReturnError(mMinIntervalFloorSeconds <= mMaxInterval, CHIP_ERROR_INVALID_ARGUMENT);
     749              : 
     750              : #if CHIP_CONFIG_ENABLE_ICD_SERVER
     751              : 
     752              :     // Default behavior for ICDs where the wanted MaxInterval for a subscription is the IdleModeDuration
     753              :     // defined in the ICD Management Cluster.
     754              :     // Behavior can be changed with the OnSubscriptionRequested function defined in the application callbacks
     755              : 
     756              :     // Default Behavior Steps :
     757              :     // If MinInterval > IdleModeDuration, try to set the MaxInterval to the first interval of IdleModeDurations above the
     758              :     // MinInterval.
     759              :     // If the next interval is greater than the MaxIntervalCeiling, use the MaxIntervalCeiling.
     760              :     // Otherwise, use IdleModeDuration as MaxInterval
     761              : 
     762              :     // GetPublisherSelectedIntervalLimit() returns the IdleModeDuration if the device is an ICD
     763              :     uint32_t decidedMaxInterval = GetPublisherSelectedIntervalLimit();
     764              : 
     765              :     // Check if the PublisherSelectedIntervalLimit is 0. If so, set decidedMaxInterval to MaxIntervalCeiling
     766              :     if (decidedMaxInterval == 0)
     767              :     {
     768              :         decidedMaxInterval = mMaxInterval;
     769              :     }
     770              : 
     771              :     // If requestedMinInterval is greater than the IdleTimeInterval, select next active up time as max interval
     772              :     if (mMinIntervalFloorSeconds > decidedMaxInterval)
     773              :     {
     774              :         uint16_t ratio = mMinIntervalFloorSeconds / static_cast<uint16_t>(decidedMaxInterval);
     775              :         if (mMinIntervalFloorSeconds % decidedMaxInterval)
     776              :         {
     777              :             ratio++;
     778              :         }
     779              : 
     780              :         decidedMaxInterval *= ratio;
     781              :     }
     782              : 
     783              :     // Verify that decidedMaxInterval is an acceptable value (overflow)
     784              :     if (decidedMaxInterval > System::Clock::Seconds16::max().count())
     785              :     {
     786              :         decidedMaxInterval = System::Clock::Seconds16::max().count();
     787              :     }
     788              : 
     789              :     // Verify that the decidedMaxInterval respects MAX(GetPublisherSelectedIntervalLimit(), MaxIntervalCeiling)
     790              :     uint16_t maximumMaxInterval = std::max(GetPublisherSelectedIntervalLimit(), mMaxInterval);
     791              :     if (decidedMaxInterval > maximumMaxInterval)
     792              :     {
     793              :         decidedMaxInterval = maximumMaxInterval;
     794              :     }
     795              : 
     796              :     // Set max interval of the subscription
     797              :     mMaxInterval = static_cast<uint16_t>(decidedMaxInterval);
     798              : 
     799              : #endif // CHIP_CONFIG_ENABLE_ICD_SERVER
     800              : 
     801              :     //
     802              :     // Notify the application (if requested) of the impending subscription and check whether we should still proceed to set it up.
     803              :     // This also provides the application an opportunity to modify the negotiated min/max intervals set above.
     804              :     //
     805          233 :     auto * appCallback = mManagementCallback.GetAppCallback();
     806          233 :     if (appCallback)
     807              :     {
     808          173 :         if (appCallback->OnSubscriptionRequested(*this, *mExchangeCtx->GetSessionHandle()->AsSecureSession()) != CHIP_NO_ERROR)
     809              :         {
     810            6 :             return CHIP_ERROR_TRANSACTION_CANCELED;
     811              :         }
     812              :     }
     813              : 
     814          227 :     ChipLogProgress(DataManagement, "Final negotiated min/max parameters: Min = %ds, Max = %ds", mMinIntervalFloorSeconds,
     815              :                     mMaxInterval);
     816              : 
     817              :     bool isFabricFiltered;
     818          227 :     ReturnErrorOnFailure(subscribeRequestParser.GetIsFabricFiltered(&isFabricFiltered));
     819          227 :     SetStateFlag(ReadHandlerFlags::FabricFiltered, isFabricFiltered);
     820          227 :     ReturnErrorOnFailure(Crypto::DRBG_get_bytes(reinterpret_cast<uint8_t *>(&mSubscriptionId), sizeof(mSubscriptionId)));
     821          227 :     ReturnErrorOnFailure(subscribeRequestParser.ExitContainer());
     822          227 :     MoveToState(HandlerState::CanStartReporting);
     823              : 
     824          227 :     mExchangeCtx->WillSendMessage();
     825              : 
     826              : #if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
     827          227 :     PersistSubscription();
     828              : #endif // CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
     829              : 
     830          227 :     return CHIP_NO_ERROR;
     831          233 : }
     832              : 
     833          227 : void ReadHandler::PersistSubscription()
     834              : {
     835          227 :     auto * subscriptionResumptionStorage = mManagementCallback.GetInteractionModelEngine()->GetSubscriptionResumptionStorage();
     836          227 :     VerifyOrReturn(subscriptionResumptionStorage != nullptr);
     837              : 
     838              :     // TODO(#31873): We need to store the CAT information to enable better interactions with ICDs
     839            0 :     SubscriptionResumptionStorage::SubscriptionInfo subscriptionInfo = { .mNodeId         = GetInitiatorNodeId(),
     840            0 :                                                                          .mFabricIndex    = GetAccessingFabricIndex(),
     841            0 :                                                                          .mSubscriptionId = mSubscriptionId,
     842            0 :                                                                          .mMinInterval    = mMinIntervalFloorSeconds,
     843            0 :                                                                          .mMaxInterval    = mMaxInterval,
     844            0 :                                                                          .mFabricFiltered = IsFabricFiltered() };
     845            0 :     VerifyOrReturn(subscriptionInfo.SetAttributePaths(mpAttributePathList) == CHIP_NO_ERROR);
     846            0 :     VerifyOrReturn(subscriptionInfo.SetEventPaths(mpEventPathList) == CHIP_NO_ERROR);
     847              : 
     848            0 :     CHIP_ERROR err = subscriptionResumptionStorage->Save(subscriptionInfo);
     849            0 :     if (err != CHIP_NO_ERROR)
     850              :     {
     851            0 :         ChipLogError(DataManagement, "Failed to save subscription info error: '%" CHIP_ERROR_FORMAT, err.Format());
     852              :     }
     853            0 : }
     854              : 
     855         1097 : void ReadHandler::ResetPathIterator()
     856              : {
     857         1097 :     mAttributePathExpandIterator.ResetTo(mpAttributePathList);
     858         1097 :     mAttributeEncoderState.Reset();
     859         1097 : }
     860              : 
     861          345 : void ReadHandler::AttributePathIsDirty(const AttributePathParams & aAttributeChanged)
     862              : {
     863          345 :     ConcreteAttributePath path;
     864              : 
     865          345 :     mDirtyGeneration = mManagementCallback.GetInteractionModelEngine()->GetReportingEngine().GetDirtySetGeneration();
     866              : 
     867              :     // We won't reset the path iterator for every AttributePathIsDirty call to reduce the number of full data reports.
     868              :     // The iterator will be reset after finishing each report session.
     869              :     //
     870              :     // Here we just reset the iterator to the beginning of the current cluster, if the dirty path affects it.
     871              :     // This will ensure the reports are consistent within a single cluster generated from a single path in the request.
     872              : 
     873              :     // TODO (#16699): Currently we can only guarantee the reports generated from a single path in the request are consistent. The
     874              :     // data might be inconsistent if the user send a request with two paths from the same cluster. We need to clearify the behavior
     875              :     // or make it consistent.
     876          609 :     if (mAttributePathExpandIterator.Get(path) &&
     877         1135 :         (aAttributeChanged.HasWildcardEndpointId() || aAttributeChanged.mEndpointId == path.mEndpointId) &&
     878          526 :         (aAttributeChanged.HasWildcardClusterId() || aAttributeChanged.mClusterId == path.mClusterId))
     879              :     {
     880          263 :         ChipLogDetail(DataManagement,
     881              :                       "The dirty path intersects the cluster we are currently reporting; reset the iterator to the beginning of "
     882              :                       "that cluster");
     883              :         // If we're currently in the middle of generating reports for a given cluster and that in turn is marked dirty, let's reset
     884              :         // our iterator to point back to the beginning of that cluster. This ensures that the receiver will get a coherent view of
     885              :         // the state of the cluster as present on the server
     886          263 :         mAttributePathExpandIterator.ResetCurrentCluster();
     887          263 :         mAttributeEncoderState.Reset();
     888              :     }
     889              : 
     890              :     // ReportScheduler will take care of verifying the reportability of the handler and schedule the run
     891          345 :     mObserver->OnBecameReportable(this);
     892          345 : }
     893              : 
     894         9393 : Transport::SecureSession * ReadHandler::GetSession() const
     895              : {
     896         9393 :     if (!mSessionHandle)
     897              :     {
     898            0 :         return nullptr;
     899              :     }
     900         9393 :     return mSessionHandle->AsSecureSession();
     901              : }
     902              : 
     903           19 : void ReadHandler::ForceDirtyState()
     904              : {
     905           19 :     SetStateFlag(ReadHandlerFlags::ForceDirty);
     906           19 : }
     907              : 
     908         6443 : void ReadHandler::SetStateFlag(ReadHandlerFlags aFlag, bool aValue)
     909              : {
     910         6443 :     bool oldReportable = ShouldStartReporting();
     911         6443 :     mFlags.Set(aFlag, aValue);
     912              : 
     913              :     // If we became reportable, schedule a reporting run.
     914         6443 :     if (!oldReportable && ShouldStartReporting())
     915              :     {
     916              :         // If we became reportable, the scheduler will schedule a run as soon as allowed
     917           13 :         mObserver->OnBecameReportable(this);
     918              :     }
     919         6443 : }
     920              : 
     921         1238 : void ReadHandler::ClearStateFlag(ReadHandlerFlags aFlag)
     922              : {
     923         1238 :     SetStateFlag(aFlag, false);
     924         1238 : }
     925              : 
     926         1906 : size_t ReadHandler::GetReportBufferMaxSize()
     927              : {
     928         1906 :     Transport::SecureSession * session = GetSession();
     929         1906 :     if (session && session->AllowsLargePayload())
     930              :     {
     931            0 :         return kMaxLargeSecureSduLengthBytes;
     932              :     }
     933         1906 :     return kMaxSecureSduLengthBytes;
     934              : }
     935              : 
     936              : } // namespace app
     937              : } // namespace chip
        

Generated by: LCOV version 2.0-1