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

Generated by: LCOV version 2.0-1