Matter SDK Coverage Report
Current view: top level - app - ReadClient.cpp (source / functions) Coverage Total Hit
Test: SHA:6c8f029dd2432dc900f1c9245c324e69bd79e40a Lines: 85.1 % 684 582
Test Date: 2026-08-08 07:40:09 Functions: 85.7 % 49 42

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2021 Project CHIP Authors
       4              :  *    All rights reserved.
       5              :  *
       6              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       7              :  *    you may not use this file except in compliance with the License.
       8              :  *    You may obtain a copy of the License at
       9              :  *
      10              :  *        http://www.apache.org/licenses/LICENSE-2.0
      11              :  *
      12              :  *    Unless required by applicable law or agreed to in writing, software
      13              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      14              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15              :  *    See the License for the specific language governing permissions and
      16              :  *    limitations under the License.
      17              :  */
      18              : 
      19              : /**
      20              :  *    @file
      21              :  *      This file defines the initiator side of a CHIP Read Interaction.
      22              :  *
      23              :  */
      24              : 
      25              : #include <app/AppConfig.h>
      26              : #include <app/InteractionModelEngine.h>
      27              : #include <app/InteractionModelHelper.h>
      28              : #include <app/ReadClient.h>
      29              : #include <app/StatusResponse.h>
      30              : #include <assert.h>
      31              : #include <lib/core/TLVTypes.h>
      32              : #include <lib/support/FibonacciUtils.h>
      33              : #include <messaging/ReliableMessageMgr.h>
      34              : #include <messaging/ReliableMessageProtocolConfig.h>
      35              : #include <platform/LockTracker.h>
      36              : #include <tracing/metric_event.h>
      37              : 
      38              : #include <app-common/zap-generated/cluster-objects.h>
      39              : #include <app-common/zap-generated/ids/Attributes.h>
      40              : #include <app-common/zap-generated/ids/Clusters.h>
      41              : 
      42              : namespace chip {
      43              : namespace app {
      44              : 
      45              : using Status = Protocols::InteractionModel::Status;
      46              : 
      47         1127 : ReadClient::ReadClient(InteractionModelEngine * apImEngine, Messaging::ExchangeManager * apExchangeMgr, Callback & apCallback,
      48         1127 :                        InteractionType aInteractionType) :
      49         1127 :     mExchange(*this),
      50         1127 :     mpCallback(apCallback), mOnConnectedCallback(HandleDeviceConnected, this),
      51         2254 :     mOnConnectionFailureCallback(HandleDeviceConnectionFailure, this)
      52              : {
      53         1127 :     assertChipStackLockedByCurrentThread();
      54              : 
      55         1127 :     mpExchangeMgr    = apExchangeMgr;
      56         1127 :     mInteractionType = aInteractionType;
      57              : 
      58         1127 :     mpImEngine = apImEngine;
      59              : 
      60         1127 :     if (aInteractionType == InteractionType::Subscribe)
      61              :     {
      62          319 :         mpImEngine->AddReadClient(this);
      63              :     }
      64         1127 : }
      65              : 
      66          285 : void ReadClient::ClearActiveSubscriptionState()
      67              : {
      68          285 :     mIsReporting                  = false;
      69          285 :     mWaitingForFirstPrimingReport = true;
      70          285 :     mPendingMoreChunks            = false;
      71          285 :     mMinIntervalFloorSeconds      = 0;
      72          285 :     mMaxInterval                  = 0;
      73          285 :     mSubscriptionId               = 0;
      74          285 :     mIsResubscriptionScheduled    = false;
      75          285 :     mSuppressResponse             = false;
      76              : 
      77          285 :     MoveToState(ClientState::Idle);
      78          285 : }
      79              : 
      80          589 : void ReadClient::StopResubscription()
      81              : {
      82          589 :     CancelLivenessCheckTimer();
      83          589 :     CancelResubscribeTimer();
      84              : 
      85              :     // Only deallocate the paths if they are not already deallocated.
      86          589 :     if (mReadPrepareParams.mpAttributePathParamsList != nullptr || mReadPrepareParams.mpEventPathParamsList != nullptr ||
      87          362 :         mReadPrepareParams.mpDataVersionFilterList != nullptr)
      88              :     {
      89          227 :         mpCallback.OnDeallocatePaths(std::move(mReadPrepareParams));
      90              :         // Make sure we will never try to free those pointers again.
      91          227 :         mReadPrepareParams.mpAttributePathParamsList    = nullptr;
      92          227 :         mReadPrepareParams.mAttributePathParamsListSize = 0;
      93          227 :         mReadPrepareParams.mpEventPathParamsList        = nullptr;
      94          227 :         mReadPrepareParams.mEventPathParamsListSize     = 0;
      95          227 :         mReadPrepareParams.mpDataVersionFilterList      = nullptr;
      96          227 :         mReadPrepareParams.mDataVersionFilterListSize   = 0;
      97              :     }
      98          589 : }
      99              : 
     100         1215 : ReadClient::~ReadClient()
     101              : {
     102         1127 :     assertChipStackLockedByCurrentThread();
     103              : 
     104         1127 :     if (IsSubscriptionType())
     105              :     {
     106          319 :         StopResubscription();
     107              : 
     108              :         // Only remove ourselves from the engine's tracker list if we still continue to have a valid pointer to it.
     109              :         // This won't be the case if the engine shut down before this destructor was called (in which case, mpImEngine
     110              :         // will point to null)
     111              :         //
     112          319 :         if (mpImEngine)
     113              :         {
     114          154 :             mpImEngine->RemoveReadClient(this);
     115              :         }
     116              :     }
     117         1215 : }
     118              : 
     119           14 : uint32_t ReadClient::ComputeTimeTillNextSubscription()
     120              : {
     121           14 :     uint32_t maxWaitTimeInMsec = 0;
     122           14 :     uint32_t waitTimeInMsec    = 0;
     123           14 :     uint32_t minWaitTimeInMsec = 0;
     124              : 
     125           14 :     if (mNumRetries <= CHIP_RESUBSCRIBE_MAX_FIBONACCI_STEP_INDEX)
     126              :     {
     127           14 :         maxWaitTimeInMsec = GetFibonacciForIndex(mNumRetries) * CHIP_RESUBSCRIBE_WAIT_TIME_MULTIPLIER_MS;
     128              :     }
     129              :     else
     130              :     {
     131            0 :         maxWaitTimeInMsec = CHIP_RESUBSCRIBE_MAX_RETRY_WAIT_INTERVAL_MS;
     132              :     }
     133              : 
     134           14 :     if (maxWaitTimeInMsec != 0)
     135              :     {
     136            3 :         minWaitTimeInMsec = (CHIP_RESUBSCRIBE_MIN_WAIT_TIME_INTERVAL_PERCENT_PER_STEP * maxWaitTimeInMsec) / 100;
     137            3 :         waitTimeInMsec    = minWaitTimeInMsec + (Crypto::GetRandU32() % (maxWaitTimeInMsec - minWaitTimeInMsec));
     138              :     }
     139              : 
     140           14 :     if (mMinimalResubscribeDelay.count() > waitTimeInMsec)
     141              :     {
     142            0 :         waitTimeInMsec = mMinimalResubscribeDelay.count();
     143              :     }
     144              : 
     145           14 :     return waitTimeInMsec;
     146              : }
     147              : 
     148           14 : CHIP_ERROR ReadClient::ScheduleResubscription(uint32_t aTimeTillNextResubscriptionMs, Optional<SessionHandle> aNewSessionHandle,
     149              :                                               bool aReestablishCASE)
     150              : {
     151           14 :     VerifyOrReturnError(IsIdle(), CHIP_ERROR_INCORRECT_STATE);
     152              : 
     153              :     //
     154              :     // If we're establishing CASE, make sure we are not provided a new SessionHandle as well.
     155              :     //
     156           14 :     VerifyOrReturnError(!aReestablishCASE || !aNewSessionHandle.HasValue(), CHIP_ERROR_INVALID_ARGUMENT);
     157              : 
     158           14 :     if (aNewSessionHandle.HasValue())
     159              :     {
     160            0 :         mReadPrepareParams.mSessionHolder.Grab(aNewSessionHandle.Value());
     161              :     }
     162              : 
     163           14 :     mForceCaseOnNextResub = aReestablishCASE;
     164           14 :     if (mForceCaseOnNextResub && mReadPrepareParams.mSessionHolder)
     165              :     {
     166              :         // Mark our existing session defunct, so that we will try to
     167              :         // re-establish it when the timer fires (unless something re-establishes
     168              :         // before then).
     169            0 :         mReadPrepareParams.mSessionHolder->AsSecureSession()->MarkAsDefunct();
     170              :     }
     171              : 
     172           28 :     ReturnErrorOnFailure(
     173              :         InteractionModelEngine::GetInstance()->GetExchangeManager()->GetSessionManager()->SystemLayer()->StartTimer(
     174              :             System::Clock::Milliseconds32(aTimeTillNextResubscriptionMs), OnResubscribeTimerCallback, this));
     175           14 :     mIsResubscriptionScheduled = true;
     176              : 
     177           14 :     return CHIP_NO_ERROR;
     178              : }
     179              : 
     180         1029 : void ReadClient::Close(CHIP_ERROR aError, bool allowResubscription)
     181              : {
     182         1029 :     if (IsReadType())
     183              :     {
     184         1488 :         if (aError != CHIP_NO_ERROR)
     185              :         {
     186           51 :             mpCallback.OnError(aError);
     187              :         }
     188              :     }
     189              :     else
     190              :     {
     191          285 :         if (IsAwaitingInitialReport() || IsAwaitingSubscribeResponse())
     192              :         {
     193              :             MATTER_LOG_METRIC_END(Tracing::kMetricDeviceSubscriptionSetup, aError);
     194              :         }
     195              : 
     196          285 :         ClearActiveSubscriptionState();
     197          570 :         if (aError != CHIP_NO_ERROR)
     198              :         {
     199              :             //
     200              :             // We infer that re-subscription was requested by virtue of having a non-zero list of event OR attribute paths present
     201              :             // in mReadPrepareParams. This would only be the case if an application called SendAutoResubscribeRequest which
     202              :             // populates mReadPrepareParams with the values provided by the application.
     203              :             //
     204          116 :             if (allowResubscription &&
     205           49 :                 (mReadPrepareParams.mEventPathParamsListSize != 0 || mReadPrepareParams.mAttributePathParamsListSize != 0))
     206              :             {
     207           16 :                 CHIP_ERROR originalReason = aError;
     208              : 
     209           16 :                 aError = mpCallback.OnResubscriptionNeeded(this, aError);
     210           32 :                 if (aError == CHIP_NO_ERROR)
     211              :                 {
     212           16 :                     return;
     213              :                 }
     214            4 :                 if (aError == CHIP_ERROR_LIT_SUBSCRIBE_INACTIVE_TIMEOUT)
     215              :                 {
     216            4 :                     VerifyOrDie(originalReason == CHIP_ERROR_LIT_SUBSCRIBE_INACTIVE_TIMEOUT);
     217            2 :                     ChipLogProgress(DataManagement, "ICD device is inactive mark subscription as InactiveICDSubscription");
     218            2 :                     MoveToState(ClientState::InactiveICDSubscription);
     219            2 :                     return;
     220              :                 }
     221              :             }
     222              : 
     223              :             //
     224              :             // Either something bad happened when requesting resubscription or the application has decided to not
     225              :             // continue by returning an error. Let's convey the error back up to the application
     226              :             // and shut everything down.
     227              :             //
     228          100 :             mpCallback.OnError(aError);
     229              :         }
     230              : 
     231          269 :         StopResubscription();
     232              :     }
     233              : 
     234         1013 :     mExchange.Release();
     235              : 
     236         1013 :     mpCallback.OnDone(this);
     237              : }
     238              : 
     239            0 : const char * ReadClient::GetStateStr() const
     240              : {
     241              : #if CHIP_DETAIL_LOGGING
     242            0 :     switch (mState)
     243              :     {
     244            0 :     case ClientState::Idle:
     245            0 :         return "Idle";
     246            0 :     case ClientState::AwaitingInitialReport:
     247            0 :         return "AwaitingInitialReport";
     248            0 :     case ClientState::AwaitingSubscribeResponse:
     249            0 :         return "AwaitingSubscribeResponse";
     250            0 :     case ClientState::SubscriptionActive:
     251            0 :         return "SubscriptionActive";
     252            0 :     case ClientState::InactiveICDSubscription:
     253            0 :         return "InactiveICDSubscription";
     254              :     }
     255              : #endif // CHIP_DETAIL_LOGGING
     256            0 :     return "N/A";
     257              : }
     258              : 
     259         1980 : void ReadClient::MoveToState(const ClientState aTargetState)
     260              : {
     261         1980 :     mState = aTargetState;
     262         1980 :     ChipLogDetail(DataManagement, "%s ReadClient[%p]: Moving to [%10.10s]", __func__, this, GetStateStr());
     263         1980 : }
     264              : 
     265          874 : CHIP_ERROR ReadClient::SendRequest(ReadPrepareParams & aReadPrepareParams)
     266              : {
     267          874 :     if (mInteractionType == InteractionType::Read)
     268              :     {
     269          796 :         return SendReadRequest(aReadPrepareParams);
     270              :     }
     271              : 
     272           78 :     if (mInteractionType == InteractionType::Subscribe)
     273              :     {
     274           78 :         return SendSubscribeRequest(aReadPrepareParams);
     275              :     }
     276              : 
     277            0 :     return CHIP_ERROR_INVALID_ARGUMENT;
     278              : }
     279              : 
     280          796 : CHIP_ERROR ReadClient::SendReadRequest(ReadPrepareParams & aReadPrepareParams)
     281              : {
     282          796 :     CHIP_ERROR err = CHIP_NO_ERROR;
     283              : 
     284          796 :     ChipLogDetail(DataManagement, "%s ReadClient[%p]: Sending Read Request", __func__, this);
     285              : 
     286          796 :     VerifyOrReturnError(ClientState::Idle == mState, err = CHIP_ERROR_INCORRECT_STATE);
     287              : 
     288              :     Span<AttributePathParams> attributePaths(aReadPrepareParams.mpAttributePathParamsList,
     289          796 :                                              aReadPrepareParams.mAttributePathParamsListSize);
     290          796 :     Span<EventPathParams> eventPaths(aReadPrepareParams.mpEventPathParamsList, aReadPrepareParams.mEventPathParamsListSize);
     291              :     Span<DataVersionFilter> dataVersionFilters(aReadPrepareParams.mpDataVersionFilterList,
     292          796 :                                                aReadPrepareParams.mDataVersionFilterListSize);
     293              : 
     294          796 :     System::PacketBufferHandle msgBuf;
     295          796 :     ReadRequestMessage::Builder request;
     296          796 :     System::PacketBufferTLVWriter writer;
     297              : 
     298          796 :     TEMPORARY_RETURN_IGNORED InitWriterWithSpaceReserved(writer, kReservedSizeForTLVEncodingOverhead);
     299          796 :     ReturnErrorOnFailure(request.Init(&writer));
     300              : 
     301          796 :     if (!attributePaths.empty())
     302              :     {
     303          674 :         AttributePathIBs::Builder & attributePathListBuilder = request.CreateAttributeRequests();
     304          674 :         ReturnErrorOnFailure(err = request.GetError());
     305          674 :         ReturnErrorOnFailure(GenerateAttributePaths(attributePathListBuilder, attributePaths));
     306              :     }
     307              : 
     308          796 :     if (!eventPaths.empty())
     309              :     {
     310          318 :         EventPathIBs::Builder & eventPathListBuilder = request.CreateEventRequests();
     311          318 :         ReturnErrorOnFailure(err = request.GetError());
     312              : 
     313          318 :         ReturnErrorOnFailure(GenerateEventPaths(eventPathListBuilder, eventPaths));
     314              : 
     315          318 :         Optional<EventNumber> eventMin;
     316          318 :         ReturnErrorOnFailure(GetMinEventNumber(aReadPrepareParams, eventMin));
     317          318 :         if (eventMin.HasValue())
     318              :         {
     319          315 :             EventFilterIBs::Builder & eventFilters = request.CreateEventFilters();
     320          315 :             ReturnErrorOnFailure(err = request.GetError());
     321          315 :             ReturnErrorOnFailure(eventFilters.GenerateEventFilter(eventMin.Value()));
     322              :         }
     323              :     }
     324              : 
     325          796 :     ReturnErrorOnFailure(request.IsFabricFiltered(aReadPrepareParams.mIsFabricFiltered).GetError());
     326              : 
     327          796 :     bool encodedDataVersionList = false;
     328          796 :     TLV::TLVWriter backup;
     329          796 :     request.Checkpoint(backup);
     330          796 :     DataVersionFilterIBs::Builder & dataVersionFilterListBuilder = request.CreateDataVersionFilters();
     331          796 :     ReturnErrorOnFailure(request.GetError());
     332          796 :     if (!attributePaths.empty())
     333              :     {
     334          674 :         ReturnErrorOnFailure(GenerateDataVersionFilterList(dataVersionFilterListBuilder, attributePaths, dataVersionFilters,
     335              :                                                            encodedDataVersionList));
     336              :     }
     337          796 :     ReturnErrorOnFailure(dataVersionFilterListBuilder.GetWriter()->UnreserveBuffer(kReservedSizeForTLVEncodingOverhead));
     338          796 :     if (encodedDataVersionList)
     339              :     {
     340           80 :         ReturnErrorOnFailure(dataVersionFilterListBuilder.EndOfDataVersionFilterIBs());
     341              :     }
     342              :     else
     343              :     {
     344          716 :         request.Rollback(backup);
     345              :     }
     346              : 
     347          796 :     ReturnErrorOnFailure(request.EndOfReadRequestMessage());
     348          796 :     ReturnErrorOnFailure(writer.Finalize(&msgBuf));
     349              : 
     350          796 :     VerifyOrReturnError(aReadPrepareParams.mSessionHolder, CHIP_ERROR_MISSING_SECURE_SESSION);
     351              : 
     352          796 :     auto exchange = mpExchangeMgr->NewContext(aReadPrepareParams.mSessionHolder.Get().Value(), this);
     353          796 :     VerifyOrReturnError(exchange != nullptr, err = CHIP_ERROR_NO_MEMORY);
     354              : 
     355          796 :     mExchange.Grab(exchange);
     356              : 
     357          796 :     if (aReadPrepareParams.mTimeout == System::Clock::kZero)
     358              :     {
     359          796 :         ReturnErrorOnFailure(mExchange->UseSuggestedResponseTimeout(app::kExpectedIMProcessingTime));
     360              :     }
     361              :     else
     362              :     {
     363            0 :         mExchange->SetResponseTimeout(aReadPrepareParams.mTimeout);
     364              :     }
     365              : 
     366          796 :     ReturnErrorOnFailure(mExchange->SendMessage(Protocols::InteractionModel::MsgType::ReadRequest, std::move(msgBuf),
     367              :                                                 Messaging::SendFlags(Messaging::SendMessageFlags::kExpectResponse)));
     368              : 
     369          796 :     mPeer = aReadPrepareParams.mSessionHolder->AsSecureSession()->GetPeer();
     370          796 :     MoveToState(ClientState::AwaitingInitialReport);
     371              : 
     372          796 :     return CHIP_NO_ERROR;
     373          796 : }
     374              : 
     375          344 : CHIP_ERROR ReadClient::GenerateEventPaths(EventPathIBs::Builder & aEventPathsBuilder, const Span<EventPathParams> & aEventPaths)
     376              : {
     377          857 :     for (auto & event : aEventPaths)
     378              :     {
     379          513 :         VerifyOrReturnError(event.IsValidEventPath(), CHIP_ERROR_IM_MALFORMED_EVENT_PATH_IB);
     380          513 :         EventPathIB::Builder & path = aEventPathsBuilder.CreatePath();
     381          513 :         ReturnErrorOnFailure(aEventPathsBuilder.GetError());
     382          513 :         ReturnErrorOnFailure(path.Encode(event));
     383              :     }
     384              : 
     385          344 :     return aEventPathsBuilder.EndOfEventPaths();
     386              : }
     387              : 
     388          986 : CHIP_ERROR ReadClient::GenerateAttributePaths(AttributePathIBs::Builder & aAttributePathIBsBuilder,
     389              :                                               const Span<AttributePathParams> & aAttributePaths)
     390              : {
     391         2986 :     for (auto & attribute : aAttributePaths)
     392              :     {
     393         2002 :         VerifyOrReturnError(attribute.IsValidAttributePath(), CHIP_ERROR_IM_MALFORMED_ATTRIBUTE_PATH_IB);
     394         2000 :         AttributePathIB::Builder & path = aAttributePathIBsBuilder.CreatePath();
     395         2000 :         ReturnErrorOnFailure(aAttributePathIBsBuilder.GetError());
     396         2000 :         ReturnErrorOnFailure(path.Encode(attribute));
     397              :     }
     398              : 
     399          984 :     return aAttributePathIBsBuilder.EndOfAttributePathIBs();
     400              : }
     401              : 
     402          977 : CHIP_ERROR ReadClient::BuildDataVersionFilterList(DataVersionFilterIBs::Builder & aDataVersionFilterIBsBuilder,
     403              :                                                   const Span<AttributePathParams> & aAttributePaths,
     404              :                                                   const Span<DataVersionFilter> & aDataVersionFilters,
     405              :                                                   bool & aEncodedDataVersionList)
     406              : {
     407              : #if CHIP_PROGRESS_LOGGING
     408          977 :     size_t encodedFilterCount    = 0;
     409          977 :     size_t irrelevantFilterCount = 0;
     410          977 :     size_t skippedFilterCount    = 0;
     411              : #endif
     412         3470 :     for (auto & filter : aDataVersionFilters)
     413              :     {
     414         2494 :         VerifyOrReturnError(filter.IsValidDataVersionFilter(), CHIP_ERROR_INVALID_ARGUMENT);
     415              : 
     416              :         // If data version filter is for some cluster none of whose attributes are included in our paths, discard this filter.
     417         2494 :         bool intersected = false;
     418         2506 :         for (auto & path : aAttributePaths)
     419              :         {
     420         2500 :             if (path.IncludesAttributesInCluster(filter))
     421              :             {
     422         2488 :                 intersected = true;
     423         2488 :                 break;
     424              :             }
     425              :         }
     426              : 
     427         2494 :         if (!intersected)
     428              :         {
     429              : #if CHIP_PROGRESS_LOGGING
     430            6 :             ++irrelevantFilterCount;
     431              : #endif
     432            6 :             continue;
     433              :         }
     434              : 
     435         2488 :         TLV::TLVWriter backup;
     436         2488 :         aDataVersionFilterIBsBuilder.Checkpoint(backup);
     437         2488 :         CHIP_ERROR err = aDataVersionFilterIBsBuilder.EncodeDataVersionFilterIB(filter);
     438         4976 :         if (err == CHIP_NO_ERROR)
     439              :         {
     440              : #if CHIP_PROGRESS_LOGGING
     441         2487 :             ++encodedFilterCount;
     442              : #endif
     443         2487 :             aEncodedDataVersionList = true;
     444              :         }
     445            2 :         else if (err == CHIP_ERROR_NO_MEMORY || err == CHIP_ERROR_BUFFER_TOO_SMALL)
     446              :         {
     447              :             // Packet is full, ignore the rest of the list
     448            1 :             aDataVersionFilterIBsBuilder.Rollback(backup);
     449              : #if CHIP_PROGRESS_LOGGING
     450            1 :             ssize_t nonSkippedFilterCount = &filter - aDataVersionFilters.data();
     451            1 :             skippedFilterCount            = aDataVersionFilters.size() - static_cast<size_t>(nonSkippedFilterCount);
     452              : #endif // CHIP_PROGRESS_LOGGING
     453            1 :             break;
     454              :         }
     455              :         else
     456              :         {
     457            0 :             return err;
     458              :         }
     459              :     }
     460              : 
     461          977 :     ChipLogProgress(DataManagement,
     462              :                     "%lu data version filters provided, %lu not relevant, %lu encoded, %lu skipped due to lack of space",
     463              :                     static_cast<unsigned long>(aDataVersionFilters.size()), static_cast<unsigned long>(irrelevantFilterCount),
     464              :                     static_cast<unsigned long>(encodedFilterCount), static_cast<unsigned long>(skippedFilterCount));
     465          977 :     return CHIP_NO_ERROR;
     466              : }
     467              : 
     468          982 : CHIP_ERROR ReadClient::GenerateDataVersionFilterList(DataVersionFilterIBs::Builder & aDataVersionFilterIBsBuilder,
     469              :                                                      const Span<AttributePathParams> & aAttributePaths,
     470              :                                                      const Span<DataVersionFilter> & aDataVersionFilters,
     471              :                                                      bool & aEncodedDataVersionList)
     472              : {
     473              :     // Give the callback a chance first, otherwise use the list we have, if any.
     474          982 :     ReturnErrorOnFailure(
     475              :         mpCallback.OnUpdateDataVersionFilterList(aDataVersionFilterIBsBuilder, aAttributePaths, aEncodedDataVersionList));
     476              : 
     477          982 :     if (!aEncodedDataVersionList)
     478              :     {
     479          977 :         ReturnErrorOnFailure(BuildDataVersionFilterList(aDataVersionFilterIBsBuilder, aAttributePaths, aDataVersionFilters,
     480              :                                                         aEncodedDataVersionList));
     481              :     }
     482              : 
     483          982 :     return CHIP_NO_ERROR;
     484              : }
     485              : 
     486            3 : void ReadClient::OnActiveModeNotification()
     487              : {
     488            3 :     VerifyOrDie(mpImEngine->InActiveReadClientList(this));
     489              : 
     490              :     // Note: this API only works when issuing subscription via SendAutoResubscribeRequest. When SendAutoResubscribeRequest is
     491              :     // called, either mEventPathParamsListSize or mAttributePathParamsListSize is not 0.
     492            3 :     VerifyOrReturn(mReadPrepareParams.mEventPathParamsListSize != 0 || mReadPrepareParams.mAttributePathParamsListSize != 0);
     493              : 
     494              :     // When we reach here, the subscription definitely exceeded the liveness timeout. Just continue the unfinished resubscription
     495              :     // logic in `OnLivenessTimeoutCallback`.
     496            3 :     if (IsInactiveICDSubscription())
     497              :     {
     498            1 :         TriggerResubscriptionForLivenessTimeout(CHIP_ERROR_TIMEOUT);
     499            1 :         return;
     500              :     }
     501              : 
     502              :     // If this API has been called, that means the subscription for this ReadClient is gone
     503              :     // on the server side (because otherwise the server would not have checked in with us).
     504              :     // Even if we think we have a live subscription, we are wrong, and should just forcibly time it
     505              :     // out and schedule a new one.
     506            2 :     if (!mIsResubscriptionScheduled)
     507              :     {
     508              :         // Closing will ultimately trigger ScheduleResubscription with the aReestablishCASE argument set to true, effectively
     509              :         // rendering the session defunct.
     510            1 :         Close(CHIP_ERROR_TIMEOUT);
     511            1 :         return;
     512              :     }
     513              : 
     514              :     // If we have already detected subscription loss and are waiting to try to re-subscribe,
     515              :     // now is a really good time to do it, since the server is listening.
     516            1 :     TriggerResubscribeIfScheduled("check-in message");
     517              : }
     518              : 
     519            3 : void ReadClient::OnPeerTypeChange(PeerType aType)
     520              : {
     521            3 :     VerifyOrDie(mpImEngine->InActiveReadClientList(this));
     522              : 
     523            3 :     mIsPeerLIT = (aType == PeerType::kLITICD);
     524              : 
     525            3 :     ChipLogProgress(DataManagement, "Peer is now %s LIT ICD.", mIsPeerLIT ? "a" : "not a");
     526              : 
     527              :     // If the peer is no longer LIT and we were waiting for a check-in to try to resubscribe,
     528              :     // just try to resubscribe now, because a SIT is not going to send a check-in.
     529            3 :     if (!mIsPeerLIT && IsInactiveICDSubscription())
     530              :     {
     531            0 :         TriggerResubscriptionForLivenessTimeout(CHIP_ERROR_TIMEOUT);
     532              :     }
     533            3 : }
     534              : 
     535         2197 : CHIP_ERROR ReadClient::OnMessageReceived(Messaging::ExchangeContext * apExchangeContext, const PayloadHeader & aPayloadHeader,
     536              :                                          System::PacketBufferHandle && aPayload)
     537              : {
     538         2197 :     CHIP_ERROR err = CHIP_NO_ERROR;
     539         2197 :     Status status  = Status::InvalidAction;
     540              :     // Based on Matter specification (10.7.3. ReportDataMessage), SuppressResponse in ReportDataMessage is omitted if `false`.
     541              :     // If this is a single ReportDataMessage for the current transaction, or this is the last ReportDataMessage in the
     542              :     // transaction (i.e. there is no pending data anymore), then this ReportDataMessage should not have SuppressResponse.
     543              :     // Otherwise, this ReportDataMessage should have SuppressResponse.
     544              :     // For each received message, we assume mSuppressResponse to be false. If it is set true, it will be updated in
     545              :     // ProcessReportData call below.
     546              :     // For all other message types (e.g. SubscribeResponse, StatusResponse etc), mSuppressResponse is not relevant and always false.
     547         2197 :     mSuppressResponse = false;
     548         2197 :     VerifyOrExit(!IsIdle() && !IsInactiveICDSubscription(), err = CHIP_ERROR_INCORRECT_STATE);
     549              : 
     550         2197 :     if (aPayloadHeader.HasMessageType(Protocols::InteractionModel::MsgType::ReportData))
     551              :     {
     552         1841 :         err = ProcessReportData(std::move(aPayload), ReportType::kContinuingTransaction);
     553              :     }
     554          356 :     else if (aPayloadHeader.HasMessageType(Protocols::InteractionModel::MsgType::SubscribeResponse))
     555              :     {
     556          286 :         ChipLogProgress(DataManagement, "SubscribeResponse is received");
     557          286 :         VerifyOrExit(apExchangeContext == mExchange.Get(), err = CHIP_ERROR_INCORRECT_STATE);
     558          286 :         err = ProcessSubscribeResponse(std::move(aPayload));
     559              :         MATTER_LOG_METRIC_END(Tracing::kMetricDeviceSubscriptionSetup, err);
     560              :     }
     561           70 :     else if (aPayloadHeader.HasMessageType(Protocols::InteractionModel::MsgType::StatusResponse))
     562              :     {
     563          138 :         VerifyOrExit(apExchangeContext == mExchange.Get(), err = CHIP_ERROR_INCORRECT_STATE);
     564           70 :         CHIP_ERROR statusError = CHIP_NO_ERROR;
     565           70 :         SuccessOrExit(err = StatusResponse::ProcessStatusResponse(std::move(aPayload), statusError));
     566           70 :         SuccessOrExit(err = statusError);
     567            2 :         err = CHIP_ERROR_INVALID_MESSAGE_TYPE;
     568              :     }
     569              :     else
     570              :     {
     571            0 :         err = CHIP_ERROR_INVALID_MESSAGE_TYPE;
     572              :     }
     573              : 
     574         2197 : exit:
     575         4394 :     if (err != CHIP_NO_ERROR)
     576              :     {
     577          156 :         if (err == CHIP_ERROR_INVALID_SUBSCRIPTION)
     578              :         {
     579            4 :             status = Status::InvalidSubscription;
     580              :         }
     581           78 :         if (!mSuppressResponse)
     582              :         {
     583           76 :             TEMPORARY_RETURN_IGNORED StatusResponse::Send(status, apExchangeContext, false /*aExpectResponse*/);
     584              :         }
     585              :     }
     586              : 
     587         3655 :     if ((!IsSubscriptionType() && !mPendingMoreChunks) || err != CHIP_NO_ERROR)
     588              :     {
     589          771 :         Close(err);
     590              :     }
     591              : 
     592         2197 :     return err;
     593              : }
     594              : 
     595           88 : void ReadClient::OnUnsolicitedReportData(Messaging::ExchangeContext * apExchangeContext, System::PacketBufferHandle && aPayload)
     596              : {
     597           88 :     Status status = Status::Success;
     598           88 :     mExchange.Grab(apExchangeContext);
     599              : 
     600              :     //
     601              :     // Let's update the session we're tracking in our SessionHolder to that associated with the message that was just received.
     602              :     // This CAN be different from the one we were tracking before, since the server is permitted to send exchanges on any valid
     603              :     // session to us, of which there could be multiple.
     604              :     //
     605              :     // Since receipt of a message is proof of a working session on the peer, it's always best to update to that if possible
     606              :     // to maximize our chances of success later.
     607              :     //
     608           88 :     mReadPrepareParams.mSessionHolder.Grab(mExchange->GetSessionHandle());
     609              : 
     610           88 :     mSuppressResponse = false;
     611              : 
     612           88 :     CHIP_ERROR err = ProcessReportData(std::move(aPayload), ReportType::kUnsolicited);
     613          176 :     if (err != CHIP_NO_ERROR)
     614              :     {
     615            0 :         if (err == CHIP_ERROR_INVALID_SUBSCRIPTION)
     616              :         {
     617            0 :             status = Status::InvalidSubscription;
     618              :         }
     619              :         else
     620              :         {
     621            0 :             status = Status::InvalidAction;
     622              :         }
     623              : 
     624            0 :         if (!mSuppressResponse)
     625              :         {
     626            0 :             TEMPORARY_RETURN_IGNORED StatusResponse::Send(status, mExchange.Get(), false /*aExpectResponse*/);
     627              :         }
     628            0 :         Close(err);
     629              :     }
     630           88 : }
     631              : 
     632         1937 : CHIP_ERROR ReadClient::ProcessReportData(System::PacketBufferHandle && aPayload, ReportType aReportType)
     633              : {
     634         1937 :     CHIP_ERROR err = CHIP_NO_ERROR;
     635         1937 :     ReportDataMessage::Parser report;
     636         1937 :     SubscriptionId subscriptionId = 0;
     637         1937 :     EventReportIBs::Parser eventReportIBs;
     638         1937 :     AttributeReportIBs::Parser attributeReportIBs;
     639         1937 :     System::PacketBufferTLVReader reader;
     640         1937 :     reader.Init(std::move(aPayload));
     641         1937 :     err = report.Init(reader);
     642         1937 :     SuccessOrExit(err);
     643              : 
     644              : #if CHIP_CONFIG_IM_PRETTY_PRINT
     645         1935 :     if (aReportType != ReportType::kUnsolicited)
     646              :     {
     647         1847 :         TEMPORARY_RETURN_IGNORED report.PrettyPrint();
     648              :     }
     649              : #endif
     650              : 
     651         1935 :     err = report.GetSuppressResponse(&mSuppressResponse);
     652         1935 :     SuccessOrExit(err);
     653              : 
     654         1935 :     err = report.GetSubscriptionId(&subscriptionId);
     655         3870 :     if (CHIP_NO_ERROR == err)
     656              :     {
     657          428 :         VerifyOrExit(IsSubscriptionType(), err = CHIP_ERROR_INVALID_ARGUMENT);
     658          426 :         if (mWaitingForFirstPrimingReport)
     659              :         {
     660          288 :             mSubscriptionId = subscriptionId;
     661              :         }
     662          138 :         else if (!IsMatchingSubscriptionId(subscriptionId))
     663              :         {
     664            2 :             err = CHIP_ERROR_INVALID_SUBSCRIPTION;
     665              :         }
     666              :     }
     667         3014 :     else if (CHIP_END_OF_TLV == err)
     668              :     {
     669         1507 :         if (IsSubscriptionType())
     670              :         {
     671            0 :             err = CHIP_ERROR_INVALID_ARGUMENT;
     672              :         }
     673              :         else
     674              :         {
     675         1507 :             err = CHIP_NO_ERROR;
     676              :         }
     677              :     }
     678         1933 :     SuccessOrExit(err);
     679              : 
     680         1931 :     err = report.GetMoreChunkedMessages(&mPendingMoreChunks);
     681         3862 :     if (CHIP_END_OF_TLV == err)
     682              :     {
     683         1063 :         mPendingMoreChunks = false;
     684         1063 :         err                = CHIP_NO_ERROR;
     685              :     }
     686         1931 :     SuccessOrExit(err);
     687              : 
     688         1931 :     err = report.GetEventReports(&eventReportIBs);
     689         3862 :     if (err == CHIP_END_OF_TLV)
     690              :     {
     691         1290 :         err = CHIP_NO_ERROR;
     692              :     }
     693         1282 :     else if (err == CHIP_NO_ERROR)
     694              :     {
     695          641 :         chip::TLV::TLVReader EventReportsReader;
     696          641 :         eventReportIBs.GetReader(&EventReportsReader);
     697          641 :         err = ProcessEventReportIBs(EventReportsReader);
     698              :     }
     699         1931 :     SuccessOrExit(err);
     700              : 
     701         1931 :     err = report.GetAttributeReportIBs(&attributeReportIBs);
     702         3862 :     if (err == CHIP_END_OF_TLV)
     703              :     {
     704          634 :         err = CHIP_NO_ERROR;
     705              :     }
     706         2594 :     else if (err == CHIP_NO_ERROR)
     707              :     {
     708         1297 :         TLV::TLVReader attributeReportIBsReader;
     709         1297 :         attributeReportIBs.GetReader(&attributeReportIBsReader);
     710         1297 :         err = ProcessAttributeReportIBs(attributeReportIBsReader);
     711              :     }
     712         1931 :     SuccessOrExit(err);
     713              : 
     714         1927 :     if (mIsReporting && !mPendingMoreChunks)
     715              :     {
     716         1030 :         mpCallback.OnReportEnd();
     717         1030 :         mIsReporting = false;
     718              :     }
     719              : 
     720         1927 :     SuccessOrExit(err = report.ExitContainer());
     721              : 
     722         1927 : exit:
     723         1937 :     if (IsSubscriptionType())
     724              :     {
     725          428 :         if (IsAwaitingInitialReport())
     726              :         {
     727          290 :             MoveToState(ClientState::AwaitingSubscribeResponse);
     728              :         }
     729          247 :         else if (IsSubscriptionActive() && err == CHIP_NO_ERROR)
     730              :         {
     731              :             //
     732              :             // Only refresh the liveness check timer if we've successfully established
     733              :             // a subscription and have a valid value for mMaxInterval which the function
     734              :             // relies on.
     735              :             //
     736          109 :             mpCallback.NotifySubscriptionStillActive(*this);
     737          109 :             err = RefreshLivenessCheckTimer();
     738              :         }
     739              :     }
     740              : 
     741         3171 :     if (!mSuppressResponse && err == CHIP_NO_ERROR)
     742              :     {
     743         1230 :         bool noResponseExpected = IsSubscriptionActive() && !mPendingMoreChunks;
     744         1230 :         err                     = StatusResponse::Send(Status::Success, mExchange.Get(), !noResponseExpected);
     745              :     }
     746              : 
     747         1937 :     mWaitingForFirstPrimingReport = false;
     748         3874 :     return err;
     749         1937 : }
     750              : 
     751           12 : void ReadClient::OnResponseTimeout(Messaging::ExchangeContext * apExchangeContext)
     752              : {
     753           12 :     ChipLogError(DataManagement, "Time out! failed to receive report data from Exchange: " ChipLogFormatExchange,
     754              :                  ChipLogValueExchange(apExchangeContext));
     755              : 
     756           12 :     Close(CHIP_ERROR_TIMEOUT);
     757           12 : }
     758              : 
     759            5 : CHIP_ERROR ReadClient::ReadICDOperatingModeFromAttributeDataIB(TLV::TLVReader && aReader, PeerType & aType)
     760              : {
     761              :     Clusters::IcdManagement::Attributes::OperatingMode::TypeInfo::DecodableType operatingMode;
     762              : 
     763            5 :     CHIP_ERROR err = DataModel::Decode(aReader, operatingMode);
     764            5 :     ReturnErrorOnFailure(err);
     765              : 
     766            5 :     switch (operatingMode)
     767              :     {
     768            4 :     case Clusters::IcdManagement::OperatingModeEnum::kSit:
     769            4 :         aType = PeerType::kNormal;
     770            4 :         break;
     771            1 :     case Clusters::IcdManagement::OperatingModeEnum::kLit:
     772            1 :         aType = PeerType::kLITICD;
     773            1 :         break;
     774            0 :     default:
     775            0 :         err = CHIP_ERROR_INVALID_ARGUMENT;
     776            0 :         break;
     777              :     }
     778              : 
     779            5 :     return err;
     780              : }
     781              : 
     782         5226 : CHIP_ERROR ReadClient::ProcessAttributePath(AttributePathIB::Parser & aAttributePathParser,
     783              :                                             ConcreteDataAttributePath & aAttributePath)
     784              : {
     785              :     // The ReportData must contain a concrete attribute path.  Don't validate ID
     786              :     // ranges here, so we can tell apart "malformed data" and "out of range
     787              :     // IDs".
     788         5226 :     CHIP_ERROR err = CHIP_NO_ERROR;
     789              :     // The ReportData must contain a concrete attribute path
     790         5226 :     err = aAttributePathParser.GetConcreteAttributePath(aAttributePath, AttributePathIB::ValidateIdRanges::kNo);
     791        10452 :     VerifyOrReturnError(err == CHIP_NO_ERROR, CHIP_ERROR_IM_MALFORMED_ATTRIBUTE_PATH_IB);
     792         5222 :     return CHIP_NO_ERROR;
     793              : }
     794              : 
     795         6802 : void ReadClient::NoteReportingData()
     796              : {
     797         6802 :     if (!mIsReporting)
     798              :     {
     799         1084 :         mpCallback.OnReportBegin();
     800         1084 :         mIsReporting = true;
     801              :     }
     802         6802 : }
     803              : 
     804         1297 : CHIP_ERROR ReadClient::ProcessAttributeReportIBs(TLV::TLVReader & aAttributeReportIBsReader)
     805              : {
     806         1297 :     CHIP_ERROR err = CHIP_NO_ERROR;
     807        13038 :     while (CHIP_NO_ERROR == (err = aAttributeReportIBsReader.Next()))
     808              :     {
     809         5226 :         TLV::TLVReader dataReader;
     810         5226 :         AttributeReportIB::Parser report;
     811         5226 :         AttributeDataIB::Parser data;
     812         5226 :         AttributeStatusIB::Parser status;
     813         5226 :         AttributePathIB::Parser path;
     814         5226 :         ConcreteDataAttributePath attributePath;
     815         5226 :         StatusIB statusIB;
     816              : 
     817         5226 :         TLV::TLVReader reader = aAttributeReportIBsReader;
     818         5226 :         ReturnErrorOnFailure(report.Init(reader));
     819              : 
     820         5226 :         err = report.GetAttributeStatus(&status);
     821        10452 :         if (CHIP_NO_ERROR == err)
     822              :         {
     823            9 :             StatusIB::Parser errorStatus;
     824            9 :             ReturnErrorOnFailure(status.GetPath(&path));
     825            9 :             ReturnErrorOnFailure(ProcessAttributePath(path, attributePath));
     826            9 :             if (!attributePath.IsValid())
     827              :             {
     828              :                 // Don't fail the entire read or subscription when there is an
     829              :                 // out-of-range ID.  Just skip that one AttributeReportIB.
     830            0 :                 ChipLogError(DataManagement,
     831              :                              "Skipping AttributeStatusIB with out-of-range IDs: (%d, " ChipLogFormatMEI ", " ChipLogFormatMEI ") ",
     832              :                              attributePath.mEndpointId, ChipLogValueMEI(attributePath.mClusterId),
     833              :                              ChipLogValueMEI(attributePath.mAttributeId));
     834            0 :                 continue;
     835              :             }
     836              : 
     837            9 :             ReturnErrorOnFailure(status.GetErrorStatus(&errorStatus));
     838            9 :             ReturnErrorOnFailure(errorStatus.DecodeStatusIB(statusIB));
     839            9 :             NoteReportingData();
     840            9 :             mpCallback.OnAttributeData(attributePath, nullptr, statusIB);
     841              :         }
     842        10434 :         else if (CHIP_END_OF_TLV == err)
     843              :         {
     844         5217 :             ReturnErrorOnFailure(report.GetAttributeData(&data));
     845         5217 :             ReturnErrorOnFailure(data.GetPath(&path));
     846         5217 :             ReturnErrorOnFailure(ProcessAttributePath(path, attributePath));
     847         5213 :             if (!attributePath.IsValid())
     848              :             {
     849              :                 // Don't fail the entire read or subscription when there is an
     850              :                 // out-of-range ID.  Just skip that one AttributeReportIB.
     851            2 :                 ChipLogError(DataManagement,
     852              :                              "Skipping AttributeDataIB  with out-of-range IDs: (%d, " ChipLogFormatMEI ", " ChipLogFormatMEI ") ",
     853              :                              attributePath.mEndpointId, ChipLogValueMEI(attributePath.mClusterId),
     854              :                              ChipLogValueMEI(attributePath.mAttributeId));
     855            2 :                 continue;
     856              :             }
     857              : 
     858         5211 :             DataVersion version = 0;
     859         5211 :             ReturnErrorOnFailure(data.GetDataVersion(&version));
     860         5211 :             attributePath.mDataVersion.SetValue(version);
     861              : 
     862         5211 :             if (mReadPrepareParams.mpDataVersionFilterList != nullptr)
     863              :             {
     864           65 :                 UpdateDataVersionFilters(attributePath);
     865              :             }
     866              : 
     867         5211 :             ReturnErrorOnFailure(data.GetData(&dataReader));
     868              : 
     869              :             // The element in an array may be another array -- so we should only set the list operation when we are handling the
     870              :             // whole list.
     871         5211 :             if (!attributePath.IsListOperation() && dataReader.GetType() == TLV::kTLVType_Array)
     872              :             {
     873         2975 :                 attributePath.mListOp = ConcreteDataAttributePath::ListOperation::ReplaceAll;
     874              :             }
     875              : 
     876         5211 :             if (attributePath.MatchesConcreteAttributePath(ConcreteAttributePath(
     877              :                     kRootEndpointId, Clusters::IcdManagement::Id, Clusters::IcdManagement::Attributes::OperatingMode::Id)))
     878              :             {
     879              :                 PeerType peerType;
     880            5 :                 TLV::TLVReader operatingModeTlvReader;
     881            5 :                 operatingModeTlvReader.Init(dataReader);
     882           10 :                 if (CHIP_NO_ERROR == ReadICDOperatingModeFromAttributeDataIB(std::move(operatingModeTlvReader), peerType))
     883              :                 {
     884              :                     // It is safe to call `OnPeerTypeChange` since we are in the middle of parsing the attribute data, And
     885              :                     // the subscription should be active so `OnActiveModeNotification` is a no-op in this case.
     886            5 :                     InteractionModelEngine::GetInstance()->OnPeerTypeChange(mPeer, peerType);
     887              :                 }
     888              :                 else
     889              :                 {
     890            0 :                     ChipLogError(DataManagement, "Failed to get ICD state from attribute data with error'%" CHIP_ERROR_FORMAT "'",
     891              :                                  err.Format());
     892              :                 }
     893              :             }
     894              : 
     895         5211 :             NoteReportingData();
     896         5211 :             mpCallback.OnAttributeData(attributePath, &dataReader, statusIB);
     897              :         }
     898              :     }
     899              : 
     900         2586 :     if (CHIP_END_OF_TLV == err)
     901              :     {
     902         1293 :         err = CHIP_NO_ERROR;
     903              :     }
     904              : 
     905         1293 :     return err;
     906              : }
     907              : 
     908          641 : CHIP_ERROR ReadClient::ProcessEventReportIBs(TLV::TLVReader & aEventReportIBsReader)
     909              : {
     910          641 :     CHIP_ERROR err = CHIP_NO_ERROR;
     911         4446 :     while (CHIP_NO_ERROR == (err = aEventReportIBsReader.Next()))
     912              :     {
     913         1582 :         TLV::TLVReader dataReader;
     914         1582 :         EventReportIB::Parser report;
     915         1582 :         EventDataIB::Parser data;
     916         1582 :         EventHeader header;
     917         1582 :         StatusIB statusIB; // Default value for statusIB is success.
     918              : 
     919         1582 :         TLV::TLVReader reader = aEventReportIBsReader;
     920         1582 :         ReturnErrorOnFailure(report.Init(reader));
     921              : 
     922         1582 :         err = report.GetEventData(&data);
     923              : 
     924         3164 :         if (err == CHIP_NO_ERROR)
     925              :         {
     926         1579 :             header.mTimestamp = mEventTimestamp;
     927         1579 :             ReturnErrorOnFailure(data.DecodeEventHeader(header));
     928         1579 :             mEventTimestamp = header.mTimestamp;
     929              : 
     930         1579 :             ReturnErrorOnFailure(data.GetData(&dataReader));
     931              : 
     932              :             //
     933              :             // Update the event number being tracked in mReadPrepareParams in case
     934              :             // we want to send it in the next SubscribeRequest message to convey
     935              :             // the event number for which we have already received an event.
     936              :             //
     937         1579 :             mReadPrepareParams.mEventNumber.SetValue(header.mEventNumber + 1);
     938              : 
     939         1579 :             NoteReportingData();
     940         1579 :             mpCallback.OnEventData(header, &dataReader, nullptr);
     941              :         }
     942            6 :         else if (err == CHIP_END_OF_TLV)
     943              :         {
     944            3 :             EventStatusIB::Parser status;
     945            3 :             EventPathIB::Parser pathIB;
     946            3 :             StatusIB::Parser statusIBParser;
     947            3 :             ReturnErrorOnFailure(report.GetEventStatus(&status));
     948            3 :             ReturnErrorOnFailure(status.GetPath(&pathIB));
     949            3 :             ReturnErrorOnFailure(pathIB.GetEventPath(&header.mPath));
     950            3 :             ReturnErrorOnFailure(status.GetErrorStatus(&statusIBParser));
     951            3 :             ReturnErrorOnFailure(statusIBParser.DecodeStatusIB(statusIB));
     952              : 
     953            3 :             NoteReportingData();
     954            3 :             mpCallback.OnEventData(header, nullptr, &statusIB);
     955              :         }
     956              :     }
     957              : 
     958         1282 :     if (CHIP_END_OF_TLV == err)
     959              :     {
     960          641 :         err = CHIP_NO_ERROR;
     961              :     }
     962              : 
     963          641 :     return err;
     964              : }
     965              : 
     966            0 : void ReadClient::OverrideLivenessTimeout(System::Clock::Timeout aLivenessTimeout)
     967              : {
     968            0 :     mLivenessTimeoutOverride = aLivenessTimeout;
     969            0 :     auto err                 = RefreshLivenessCheckTimer();
     970            0 :     if (err != CHIP_NO_ERROR)
     971              :     {
     972            0 :         Close(err);
     973              :     }
     974            0 : }
     975              : 
     976          393 : CHIP_ERROR ReadClient::RefreshLivenessCheckTimer()
     977              : {
     978          393 :     CHIP_ERROR err = CHIP_NO_ERROR;
     979              : 
     980          393 :     VerifyOrReturnError(IsSubscriptionActive(), CHIP_ERROR_INCORRECT_STATE);
     981              : 
     982          393 :     CancelLivenessCheckTimer();
     983              : 
     984              :     System::Clock::Timeout timeout;
     985          393 :     ReturnErrorOnFailure(ComputeLivenessCheckTimerTimeout(&timeout));
     986              : 
     987              :     // EFR32/MBED/INFINION/K32W's chrono count return long unsigned, but other platform returns unsigned
     988          393 :     ChipLogProgress(
     989              :         DataManagement,
     990              :         "Refresh LivenessCheckTime for %lu milliseconds with SubscriptionId = 0x%08" PRIx32 " Peer = %02x:" ChipLogFormatX64,
     991              :         static_cast<long unsigned>(timeout.count()), mSubscriptionId, GetFabricIndex(), ChipLogValueX64(GetPeerNodeId()));
     992          393 :     err = InteractionModelEngine::GetInstance()->GetExchangeManager()->GetSessionManager()->SystemLayer()->StartTimer(
     993          393 :         timeout, OnLivenessTimeoutCallback, this);
     994              : 
     995          393 :     return err;
     996              : }
     997              : 
     998          393 : CHIP_ERROR ReadClient::ComputeLivenessCheckTimerTimeout(System::Clock::Timeout * aTimeout)
     999              : {
    1000          393 :     if (mLivenessTimeoutOverride != System::Clock::kZero)
    1001              :     {
    1002            0 :         *aTimeout = mLivenessTimeoutOverride;
    1003            0 :         return CHIP_NO_ERROR;
    1004              :     }
    1005              : 
    1006          393 :     VerifyOrReturnError(mReadPrepareParams.mSessionHolder, CHIP_ERROR_INCORRECT_STATE);
    1007              : 
    1008              :     //
    1009              :     // To calculate the duration we're willing to wait for a report to come to us, we take into account the maximum interval of
    1010              :     // the subscription AND the time it takes for the report to make it to us in the worst case.
    1011              :     //
    1012              :     // We have no way to estimate what the network latency will be, but we do know the other side will time out its ReportData
    1013              :     // after its computed round-trip timeout plus the processing time it gives us (app::kExpectedIMProcessingTime).  Once it
    1014              :     // times out, assuming it sent the report at all, there's no point in us thinking we still have a subscription.
    1015              :     //
    1016              :     // We can't use ComputeRoundTripTimeout() on the session for two reasons: we want the roundtrip timeout from the point of
    1017              :     // view of the peer, not us, and we want to start off with the assumption the peer will likely have, which is that we are
    1018              :     // idle, whereas ComputeRoundTripTimeout() uses the current activity state of the peer.
    1019              :     //
    1020              :     // So recompute the round-trip timeout directly.  Assume MRP, since in practice that is likely what is happening.
    1021          393 :     auto & peerMRPConfig = mReadPrepareParams.mSessionHolder->GetRemoteMRPConfig();
    1022              :     // Peer will assume we are idle (hence we pass kZero to GetMessageReceiptTimeout()), but will assume we treat it as active
    1023              :     // for the response, so to match the retransmission timeout computation for the message back to the peer, we should treat
    1024              :     // it as active and handling non-initial message, isFirstMessageOnExchange needs to be set as false for
    1025              :     // GetRetransmissionTimeout.
    1026              :     auto roundTripTimeout =
    1027          393 :         mReadPrepareParams.mSessionHolder->GetMessageReceiptTimeout(System::Clock::kZero, true /*isFirstMessageOnExchange*/) +
    1028          393 :         kExpectedIMProcessingTime +
    1029          393 :         GetRetransmissionTimeout(peerMRPConfig.mActiveRetransTimeout, peerMRPConfig.mIdleRetransTimeout,
    1030          393 :                                  System::SystemClock().GetMonotonicTimestamp(), peerMRPConfig.mActiveThresholdTime,
    1031          393 :                                  false /*isFirstMessageOnExchange*/);
    1032          393 :     *aTimeout = System::Clock::Seconds16(mMaxInterval) + roundTripTimeout;
    1033          393 :     return CHIP_NO_ERROR;
    1034              : }
    1035              : 
    1036          982 : void ReadClient::CancelLivenessCheckTimer()
    1037              : {
    1038          982 :     InteractionModelEngine::GetInstance()->GetExchangeManager()->GetSessionManager()->SystemLayer()->CancelTimer(
    1039              :         OnLivenessTimeoutCallback, this);
    1040          982 : }
    1041              : 
    1042          590 : void ReadClient::CancelResubscribeTimer()
    1043              : {
    1044          590 :     InteractionModelEngine::GetInstance()->GetExchangeManager()->GetSessionManager()->SystemLayer()->CancelTimer(
    1045              :         OnResubscribeTimerCallback, this);
    1046          590 :     mIsResubscriptionScheduled = false;
    1047          590 : }
    1048              : 
    1049            8 : void ReadClient::OnLivenessTimeoutCallback(System::Layer * apSystemLayer, void * apAppState)
    1050              : {
    1051            8 :     ReadClient * const _this = reinterpret_cast<ReadClient *>(apAppState);
    1052              : 
    1053              :     // TODO: add a more specific error here for liveness timeout failure to distinguish between other classes of timeouts (i.e
    1054              :     // response timeouts).
    1055            8 :     CHIP_ERROR subscriptionTerminationCause = CHIP_ERROR_TIMEOUT;
    1056              : 
    1057              :     //
    1058              :     // Might as well try to see if this instance exists in the tracked list in the IM.
    1059              :     // This might blow-up if either the client has since been free'ed (use-after-free), or if the engine has since
    1060              :     // been shutdown at which point the client wouldn't exist in the active read client list.
    1061              :     //
    1062            8 :     VerifyOrDie(_this->mpImEngine->InActiveReadClientList(_this));
    1063              : 
    1064            8 :     ChipLogError(DataManagement,
    1065              :                  "Subscription Liveness timeout with SubscriptionID = 0x%08" PRIx32 ", Peer = %02x:" ChipLogFormatX64,
    1066              :                  _this->mSubscriptionId, _this->GetFabricIndex(), ChipLogValueX64(_this->GetPeerNodeId()));
    1067              : 
    1068              :     // If subscription client is able to handle check-in messages and peer operation mode is LIT,
    1069              :     // use CHIP_ERROR_LIT_SUBSCRIBE_INACTIVE_TIMEOUT as subscriptionTerminationCause.
    1070              :     // This will cause us to wait for a check-in message before trying to re-subscribe, instead of trying
    1071              :     // (and probably failing, because we are dealing with a LIT ICD) off a timer.
    1072            8 :     if (_this->mIsPeerLIT && _this->mReadPrepareParams.mRegisteredCheckInToken)
    1073              :     {
    1074            3 :         subscriptionTerminationCause = CHIP_ERROR_LIT_SUBSCRIBE_INACTIVE_TIMEOUT;
    1075              :     }
    1076              : 
    1077            8 :     _this->TriggerResubscriptionForLivenessTimeout(subscriptionTerminationCause);
    1078            8 : }
    1079              : 
    1080            9 : void ReadClient::TriggerResubscriptionForLivenessTimeout(CHIP_ERROR aReason)
    1081              : {
    1082              :     // We didn't get a message from the server on time; it's possible that it no
    1083              :     // longer has a useful CASE session to us.  Mark defunct all sessions that
    1084              :     // have not seen peer activity in at least as long as our session.
    1085            9 :     const auto & holder = mReadPrepareParams.mSessionHolder;
    1086            9 :     if (holder)
    1087              :     {
    1088            9 :         System::Clock::Timestamp lastPeerActivity = holder->AsSecureSession()->GetLastPeerActivityTime();
    1089            9 :         mpImEngine->GetExchangeManager()->GetSessionManager()->ForEachMatchingSession(mPeer, [&lastPeerActivity](auto * session) {
    1090            9 :             if (!session->IsCASESession())
    1091              :             {
    1092            9 :                 return;
    1093              :             }
    1094              : 
    1095            0 :             if (session->GetLastPeerActivityTime() > lastPeerActivity)
    1096              :             {
    1097            0 :                 return;
    1098              :             }
    1099              : 
    1100            0 :             session->MarkAsDefunct();
    1101              :         });
    1102              :     }
    1103              : 
    1104            9 :     Close(aReason);
    1105            9 : }
    1106              : 
    1107          286 : CHIP_ERROR ReadClient::ProcessSubscribeResponse(System::PacketBufferHandle && aPayload)
    1108              : {
    1109          286 :     System::PacketBufferTLVReader reader;
    1110          286 :     reader.Init(std::move(aPayload));
    1111              : 
    1112          286 :     SubscribeResponseMessage::Parser subscribeResponse;
    1113          286 :     ReturnErrorOnFailure(subscribeResponse.Init(reader));
    1114              : 
    1115              : #if CHIP_CONFIG_IM_PRETTY_PRINT
    1116          286 :     TEMPORARY_RETURN_IGNORED subscribeResponse.PrettyPrint();
    1117              : #endif
    1118              : 
    1119          286 :     SubscriptionId subscriptionId = 0;
    1120          572 :     VerifyOrReturnError(subscribeResponse.GetSubscriptionId(&subscriptionId) == CHIP_NO_ERROR, CHIP_ERROR_INVALID_ARGUMENT);
    1121          286 :     VerifyOrReturnError(IsMatchingSubscriptionId(subscriptionId), CHIP_ERROR_INVALID_SUBSCRIPTION);
    1122          284 :     ReturnErrorOnFailure(subscribeResponse.GetMaxInterval(&mMaxInterval));
    1123              : 
    1124              : #if CHIP_PROGRESS_LOGGING
    1125          284 :     auto duration = System::Clock::Milliseconds32(System::SystemClock().GetMonotonicTimestamp() - mSubscribeRequestTime);
    1126              : #endif
    1127          284 :     ChipLogProgress(DataManagement,
    1128              :                     "Subscription established in %" PRIu32 "ms with SubscriptionID = 0x%08" PRIx32 " MinInterval = %u"
    1129              :                     "s MaxInterval = %us Peer = %02x:" ChipLogFormatX64,
    1130              :                     duration.count(), mSubscriptionId, mMinIntervalFloorSeconds, mMaxInterval, GetFabricIndex(),
    1131              :                     ChipLogValueX64(GetPeerNodeId()));
    1132              : 
    1133          284 :     ReturnErrorOnFailure(subscribeResponse.ExitContainer());
    1134              : 
    1135          284 :     MoveToState(ClientState::SubscriptionActive);
    1136              : 
    1137          284 :     mpCallback.OnSubscriptionEstablished(subscriptionId);
    1138              : 
    1139          284 :     mNumRetries = 0;
    1140              : 
    1141          284 :     ReturnErrorOnFailure(RefreshLivenessCheckTimer());
    1142              : 
    1143          284 :     return CHIP_NO_ERROR;
    1144          286 : }
    1145              : 
    1146          227 : CHIP_ERROR ReadClient::SendAutoResubscribeRequest(ReadPrepareParams && aReadPrepareParams)
    1147              : {
    1148              :     // Make sure we don't use minimal resubscribe delays from previous attempts
    1149              :     // for this one.
    1150          227 :     mMinimalResubscribeDelay = System::Clock::kZero;
    1151              : 
    1152          227 :     mReadPrepareParams = std::move(aReadPrepareParams);
    1153          227 :     CHIP_ERROR err     = SendSubscribeRequest(mReadPrepareParams);
    1154          454 :     if (err != CHIP_NO_ERROR)
    1155              :     {
    1156            1 :         StopResubscription();
    1157              :     }
    1158          227 :     return err;
    1159              : }
    1160              : 
    1161            0 : CHIP_ERROR ReadClient::SendAutoResubscribeRequest(const ScopedNodeId & aPublisherId, ReadPrepareParams && aReadPrepareParams)
    1162              : {
    1163            0 :     mPeer              = aPublisherId;
    1164            0 :     mReadPrepareParams = std::move(aReadPrepareParams);
    1165            0 :     CHIP_ERROR err     = EstablishSessionToPeer();
    1166            0 :     if (err != CHIP_NO_ERROR)
    1167              :     {
    1168              :         // Make sure we call our callback's OnDeallocatePaths.
    1169            0 :         StopResubscription();
    1170              :     }
    1171            0 :     return err;
    1172              : }
    1173              : 
    1174          318 : CHIP_ERROR ReadClient::SendSubscribeRequest(const ReadPrepareParams & aReadPrepareParams)
    1175              : {
    1176          318 :     VerifyOrReturnError(aReadPrepareParams.mMinIntervalFloorSeconds <= aReadPrepareParams.mMaxIntervalCeilingSeconds,
    1177              :                         CHIP_ERROR_INVALID_ARGUMENT);
    1178              : 
    1179          315 :     auto err = SendSubscribeRequestImpl(aReadPrepareParams);
    1180          630 :     if (CHIP_NO_ERROR != err)
    1181              :     {
    1182              :         MATTER_LOG_METRIC_END(Tracing::kMetricDeviceSubscriptionSetup, err);
    1183              :     }
    1184          315 :     return err;
    1185              : }
    1186              : 
    1187          315 : CHIP_ERROR ReadClient::SendSubscribeRequestImpl(const ReadPrepareParams & aReadPrepareParams)
    1188              : {
    1189              :     MATTER_LOG_METRIC_BEGIN(Tracing::kMetricDeviceSubscriptionSetup);
    1190              : 
    1191              : #if CHIP_PROGRESS_LOGGING
    1192          315 :     mSubscribeRequestTime = System::SystemClock().GetMonotonicTimestamp();
    1193              : #endif
    1194              : 
    1195          315 :     VerifyOrReturnError(ClientState::Idle == mState, CHIP_ERROR_INCORRECT_STATE);
    1196              : 
    1197          315 :     if (&aReadPrepareParams != &mReadPrepareParams)
    1198              :     {
    1199           78 :         mReadPrepareParams.mSessionHolder = aReadPrepareParams.mSessionHolder;
    1200              :     }
    1201              : 
    1202          315 :     mIsPeerLIT                                 = aReadPrepareParams.mIsPeerLIT;
    1203          315 :     mReadPrepareParams.mRegisteredCheckInToken = aReadPrepareParams.mRegisteredCheckInToken;
    1204              : 
    1205          315 :     if (aReadPrepareParams.mRegisteredCheckInToken)
    1206              :     {
    1207           11 :         ChipLogProgress(DataManagement, "ICD Check-In token has been registered in peer device " ChipLogFormatScopedNodeId,
    1208              :                         ChipLogValueScopedNodeId(mPeer));
    1209              :     }
    1210              : 
    1211          315 :     mMinIntervalFloorSeconds = aReadPrepareParams.mMinIntervalFloorSeconds;
    1212              : 
    1213              :     // Todo: Remove the below, Update span in ReadPrepareParams
    1214          315 :     Span<AttributePathParams> attributePaths(aReadPrepareParams.mpAttributePathParamsList,
    1215          315 :                                              aReadPrepareParams.mAttributePathParamsListSize);
    1216          315 :     Span<EventPathParams> eventPaths(aReadPrepareParams.mpEventPathParamsList, aReadPrepareParams.mEventPathParamsListSize);
    1217          315 :     Span<DataVersionFilter> dataVersionFilters(aReadPrepareParams.mpDataVersionFilterList,
    1218          315 :                                                aReadPrepareParams.mDataVersionFilterListSize);
    1219              : 
    1220          315 :     System::PacketBufferHandle msgBuf;
    1221          315 :     System::PacketBufferTLVWriter writer;
    1222          315 :     SubscribeRequestMessage::Builder request;
    1223          315 :     TEMPORARY_RETURN_IGNORED InitWriterWithSpaceReserved(writer, kReservedSizeForTLVEncodingOverhead);
    1224              : 
    1225          315 :     ReturnErrorOnFailure(request.Init(&writer));
    1226              : 
    1227          315 :     request.KeepSubscriptions(aReadPrepareParams.mKeepSubscriptions)
    1228          315 :         .MinIntervalFloorSeconds(aReadPrepareParams.mMinIntervalFloorSeconds)
    1229          315 :         .MaxIntervalCeilingSeconds(aReadPrepareParams.mMaxIntervalCeilingSeconds);
    1230              : 
    1231          315 :     if (!attributePaths.empty())
    1232              :     {
    1233          308 :         AttributePathIBs::Builder & attributePathListBuilder = request.CreateAttributeRequests();
    1234          308 :         ReturnErrorOnFailure(attributePathListBuilder.GetError());
    1235          308 :         ReturnErrorOnFailure(GenerateAttributePaths(attributePathListBuilder, attributePaths));
    1236              :     }
    1237              : 
    1238          315 :     if (!eventPaths.empty())
    1239              :     {
    1240           22 :         EventPathIBs::Builder & eventPathListBuilder = request.CreateEventRequests();
    1241           22 :         ReturnErrorOnFailure(eventPathListBuilder.GetError());
    1242           22 :         ReturnErrorOnFailure(GenerateEventPaths(eventPathListBuilder, eventPaths));
    1243              : 
    1244           22 :         Optional<EventNumber> eventMin;
    1245           22 :         ReturnErrorOnFailure(GetMinEventNumber(aReadPrepareParams, eventMin));
    1246           22 :         if (eventMin.HasValue())
    1247              :         {
    1248            0 :             EventFilterIBs::Builder & eventFilters = request.CreateEventFilters();
    1249            0 :             ReturnErrorOnFailure(request.GetError());
    1250            0 :             ReturnErrorOnFailure(eventFilters.GenerateEventFilter(eventMin.Value()));
    1251              :         }
    1252              :     }
    1253              : 
    1254          315 :     ReturnErrorOnFailure(request.IsFabricFiltered(aReadPrepareParams.mIsFabricFiltered).GetError());
    1255              : 
    1256          315 :     bool encodedDataVersionList = false;
    1257          315 :     TLV::TLVWriter backup;
    1258          315 :     request.Checkpoint(backup);
    1259          315 :     DataVersionFilterIBs::Builder & dataVersionFilterListBuilder = request.CreateDataVersionFilters();
    1260          315 :     ReturnErrorOnFailure(request.GetError());
    1261          315 :     if (!attributePaths.empty())
    1262              :     {
    1263          308 :         ReturnErrorOnFailure(GenerateDataVersionFilterList(dataVersionFilterListBuilder, attributePaths, dataVersionFilters,
    1264              :                                                            encodedDataVersionList));
    1265              :     }
    1266          315 :     ReturnErrorOnFailure(dataVersionFilterListBuilder.GetWriter()->UnreserveBuffer(kReservedSizeForTLVEncodingOverhead));
    1267          315 :     if (encodedDataVersionList)
    1268              :     {
    1269           65 :         ReturnErrorOnFailure(dataVersionFilterListBuilder.EndOfDataVersionFilterIBs());
    1270              :     }
    1271              :     else
    1272              :     {
    1273          250 :         request.Rollback(backup);
    1274              :     }
    1275              : 
    1276          315 :     ReturnErrorOnFailure(request.EndOfSubscribeRequestMessage());
    1277          315 :     ReturnErrorOnFailure(writer.Finalize(&msgBuf));
    1278              : 
    1279          315 :     VerifyOrReturnError(aReadPrepareParams.mSessionHolder, CHIP_ERROR_MISSING_SECURE_SESSION);
    1280              : 
    1281          315 :     auto exchange = mpExchangeMgr->NewContext(aReadPrepareParams.mSessionHolder.Get().Value(), this);
    1282          315 :     if (exchange == nullptr)
    1283              :     {
    1284            0 :         if (aReadPrepareParams.mSessionHolder->AsSecureSession()->IsActiveSession())
    1285              :         {
    1286            0 :             return CHIP_ERROR_NO_MEMORY;
    1287              :         }
    1288              : 
    1289              :         // Trying to subscribe with a defunct session somehow.
    1290            0 :         return CHIP_ERROR_INCORRECT_STATE;
    1291              :     }
    1292              : 
    1293          315 :     mExchange.Grab(exchange);
    1294              : 
    1295          315 :     if (aReadPrepareParams.mTimeout == System::Clock::kZero)
    1296              :     {
    1297          315 :         ReturnErrorOnFailure(mExchange->UseSuggestedResponseTimeout(app::kExpectedIMProcessingTime));
    1298              :     }
    1299              :     else
    1300              :     {
    1301            0 :         mExchange->SetResponseTimeout(aReadPrepareParams.mTimeout);
    1302              :     }
    1303              : 
    1304          315 :     ReturnErrorOnFailure(mExchange->SendMessage(Protocols::InteractionModel::MsgType::SubscribeRequest, std::move(msgBuf),
    1305              :                                                 Messaging::SendFlags(Messaging::SendMessageFlags::kExpectResponse)));
    1306              : 
    1307          315 :     mPeer = aReadPrepareParams.mSessionHolder->AsSecureSession()->GetPeer();
    1308              : 
    1309          315 :     MoveToState(ClientState::AwaitingInitialReport);
    1310              : 
    1311          315 :     return CHIP_NO_ERROR;
    1312          315 : }
    1313              : 
    1314            6 : CHIP_ERROR ReadClient::DefaultResubscribePolicy(CHIP_ERROR aTerminationCause)
    1315              : {
    1316           12 :     if (aTerminationCause == CHIP_ERROR_LIT_SUBSCRIBE_INACTIVE_TIMEOUT)
    1317              :     {
    1318            0 :         ChipLogProgress(DataManagement, "ICD device is inactive, skipping scheduling resubscribe within DefaultResubscribePolicy");
    1319            0 :         return CHIP_ERROR_LIT_SUBSCRIBE_INACTIVE_TIMEOUT;
    1320              :     }
    1321              : 
    1322            6 :     VerifyOrReturnError(IsIdle(), CHIP_ERROR_INCORRECT_STATE);
    1323              : 
    1324            6 :     auto timeTillNextResubscription = ComputeTimeTillNextSubscription();
    1325            6 :     ChipLogProgress(DataManagement,
    1326              :                     "Will try to resubscribe to %02x:" ChipLogFormatX64 " at retry index %" PRIu32 " after %" PRIu32
    1327              :                     "ms due to error %" CHIP_ERROR_FORMAT,
    1328              :                     GetFabricIndex(), ChipLogValueX64(GetPeerNodeId()), mNumRetries, timeTillNextResubscription,
    1329              :                     aTerminationCause.Format());
    1330           12 :     return ScheduleResubscription(timeTillNextResubscription, NullOptional, aTerminationCause == CHIP_ERROR_TIMEOUT);
    1331              : }
    1332              : 
    1333            0 : void ReadClient::HandleDeviceConnected(void * context, Messaging::ExchangeManager & exchangeMgr,
    1334              :                                        const SessionHandle & sessionHandle)
    1335              : {
    1336            0 :     ReadClient * const _this = static_cast<ReadClient *>(context);
    1337            0 :     VerifyOrDie(_this != nullptr);
    1338              : 
    1339            0 :     ChipLogProgress(DataManagement, "HandleDeviceConnected");
    1340            0 :     _this->mReadPrepareParams.mSessionHolder.Grab(sessionHandle);
    1341            0 :     _this->mpExchangeMgr = &exchangeMgr;
    1342              : 
    1343            0 :     _this->mpCallback.OnCASESessionEstablished(sessionHandle, _this->mReadPrepareParams);
    1344              : 
    1345            0 :     auto err = _this->SendSubscribeRequest(_this->mReadPrepareParams);
    1346            0 :     if (err != CHIP_NO_ERROR)
    1347              :     {
    1348            0 :         _this->Close(err);
    1349              :     }
    1350            0 : }
    1351              : 
    1352            0 : void ReadClient::HandleDeviceConnectionFailure(void * context, const OperationalSessionSetup::ConnectionFailureInfo & failureInfo)
    1353              : {
    1354            0 :     ReadClient * const _this = static_cast<ReadClient *>(context);
    1355            0 :     VerifyOrDie(_this != nullptr);
    1356              : 
    1357            0 :     ChipLogError(DataManagement, "Failed to establish CASE for re-subscription with error '%" CHIP_ERROR_FORMAT "'",
    1358              :                  failureInfo.error.Format());
    1359              : 
    1360              : #if CHIP_CONFIG_ENABLE_BUSY_HANDLING_FOR_OPERATIONAL_SESSION_SETUP
    1361              : #if CHIP_DETAIL_LOGGING
    1362            0 :     if (failureInfo.requestedBusyDelay.HasValue())
    1363              :     {
    1364            0 :         ChipLogDetail(DataManagement, "Will delay resubscription by %u ms due to BUSY response",
    1365              :                       failureInfo.requestedBusyDelay.Value().count());
    1366              :     }
    1367              : #endif // CHIP_DETAIL_LOGGING
    1368            0 :     _this->mMinimalResubscribeDelay = failureInfo.requestedBusyDelay.ValueOr(System::Clock::kZero);
    1369              : #else
    1370              :     _this->mMinimalResubscribeDelay = System::Clock::kZero;
    1371              : #endif // CHIP_CONFIG_ENABLE_BUSY_HANDLING_FOR_OPERATIONAL_SESSION_SETUP
    1372              : 
    1373            0 :     _this->Close(failureInfo.error);
    1374            0 : }
    1375              : 
    1376           11 : void ReadClient::OnResubscribeTimerCallback(System::Layer * /* If this starts being used, fix callers that pass nullptr */,
    1377              :                                             void * apAppState)
    1378              : {
    1379           11 :     ReadClient * const _this = static_cast<ReadClient *>(apAppState);
    1380           11 :     VerifyOrDie(_this != nullptr);
    1381              : 
    1382           11 :     _this->mIsResubscriptionScheduled = false;
    1383              : 
    1384              :     CHIP_ERROR err;
    1385              : 
    1386           11 :     ChipLogProgress(DataManagement, "OnResubscribeTimerCallback: ForceCASE = %d", _this->mForceCaseOnNextResub);
    1387           11 :     _this->mNumRetries++;
    1388              : 
    1389           11 :     bool allowResubscribeOnError = true;
    1390           22 :     if (!_this->mReadPrepareParams.mSessionHolder ||
    1391           11 :         !_this->mReadPrepareParams.mSessionHolder->AsSecureSession()->IsActiveSession())
    1392              :     {
    1393              :         // We don't have an active CASE session.  We need to go ahead and set
    1394              :         // one up, if we can.
    1395            0 :         if (_this->EstablishSessionToPeer() == CHIP_NO_ERROR)
    1396              :         {
    1397            0 :             return;
    1398              :         }
    1399              : 
    1400            0 :         if (_this->mForceCaseOnNextResub)
    1401              :         {
    1402              :             // Caller asked us to force CASE but we have no way to do CASE.
    1403              :             // Just stop trying.
    1404            0 :             allowResubscribeOnError = false;
    1405              :         }
    1406              : 
    1407              :         // No way to send our subscribe request.
    1408            0 :         err = CHIP_ERROR_INCORRECT_STATE;
    1409            0 :         ExitNow();
    1410              :     }
    1411              : 
    1412           11 :     err = _this->SendSubscribeRequest(_this->mReadPrepareParams);
    1413              : 
    1414           11 : exit:
    1415           22 :     if (err != CHIP_NO_ERROR)
    1416              :     {
    1417              :         //
    1418              :         // Call Close (which should trigger re-subscription again) EXCEPT if we got here because we didn't have a valid
    1419              :         // CASESessionManager pointer when mForceCaseOnNextResub was true.
    1420              :         //
    1421              :         // In that case, don't permit re-subscription to occur.
    1422              :         //
    1423            0 :         _this->Close(err, allowResubscribeOnError);
    1424              :     }
    1425              : }
    1426              : 
    1427           65 : void ReadClient::UpdateDataVersionFilters(const ConcreteDataAttributePath & aPath)
    1428              : {
    1429          130 :     for (size_t index = 0; index < mReadPrepareParams.mDataVersionFilterListSize; index++)
    1430              :     {
    1431           65 :         if (mReadPrepareParams.mpDataVersionFilterList[index].mEndpointId == aPath.mEndpointId &&
    1432           65 :             mReadPrepareParams.mpDataVersionFilterList[index].mClusterId == aPath.mClusterId)
    1433              :         {
    1434              :             // Now we know the current version for this cluster is aPath.mDataVersion.
    1435           65 :             mReadPrepareParams.mpDataVersionFilterList[index].mDataVersion = aPath.mDataVersion;
    1436              :         }
    1437              :     }
    1438           65 : }
    1439              : 
    1440          340 : CHIP_ERROR ReadClient::GetMinEventNumber(const ReadPrepareParams & aReadPrepareParams, Optional<EventNumber> & aEventMin)
    1441              : {
    1442          340 :     if (aReadPrepareParams.mEventNumber.HasValue())
    1443              :     {
    1444          313 :         aEventMin = aReadPrepareParams.mEventNumber;
    1445              :     }
    1446              :     else
    1447              :     {
    1448           27 :         ReturnErrorOnFailure(mpCallback.GetHighestReceivedEventNumber(aEventMin));
    1449           27 :         if (aEventMin.HasValue())
    1450              :         {
    1451              :             // We want to start with the first event _after_ the last one we received.
    1452            2 :             aEventMin.SetValue(aEventMin.Value() + 1);
    1453              :         }
    1454              :     }
    1455          340 :     return CHIP_NO_ERROR;
    1456              : }
    1457              : 
    1458          202 : bool ReadClient::TriggerResubscribeIfScheduled(const char * reason)
    1459              : {
    1460          202 :     if (!mIsResubscriptionScheduled)
    1461              :     {
    1462          201 :         return false;
    1463              :     }
    1464              : 
    1465            1 :     ChipLogDetail(DataManagement, "ReadClient[%p] triggering resubscribe, reason: %s", this, reason);
    1466            1 :     CancelResubscribeTimer();
    1467            1 :     OnResubscribeTimerCallback(nullptr, this);
    1468              : 
    1469            1 :     return true;
    1470              : }
    1471              : 
    1472            0 : Optional<System::Clock::Timeout> ReadClient::GetSubscriptionTimeout()
    1473              : {
    1474            0 :     if (!IsSubscriptionType() || !IsSubscriptionActive())
    1475              :     {
    1476            0 :         return NullOptional;
    1477              :     }
    1478              : 
    1479              :     System::Clock::Timeout timeout;
    1480            0 :     CHIP_ERROR err = ComputeLivenessCheckTimerTimeout(&timeout);
    1481            0 :     if (err != CHIP_NO_ERROR)
    1482              :     {
    1483            0 :         return NullOptional;
    1484              :     }
    1485              : 
    1486            0 :     return MakeOptional(timeout);
    1487              : }
    1488              : 
    1489            0 : CHIP_ERROR ReadClient::EstablishSessionToPeer()
    1490              : {
    1491            0 :     ChipLogProgress(DataManagement, "Trying to establish a CASE session for subscription");
    1492            0 :     auto * caseSessionManager = InteractionModelEngine::GetInstance()->GetCASESessionManager();
    1493            0 :     VerifyOrReturnError(caseSessionManager != nullptr, CHIP_ERROR_INCORRECT_STATE);
    1494            0 :     caseSessionManager->FindOrEstablishSession(mPeer, &mOnConnectedCallback, &mOnConnectionFailureCallback);
    1495            0 :     return CHIP_NO_ERROR;
    1496              : }
    1497              : 
    1498              : } // namespace app
    1499              : } // namespace chip
        

Generated by: LCOV version 2.0-1