From 35203631a703d74110beba55dbf1466d83ce949b Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 24 Mar 2023 15:42:00 -0400 Subject: [PATCH] Add a way to ask a ReadClient what its liveness check timeout is. (#25804) --- src/app/ReadClient.cpp | 79 ++++++++++++++++++++++++++---------------- src/app/ReadClient.h | 11 ++++++ 2 files changed, 61 insertions(+), 29 deletions(-) diff --git a/src/app/ReadClient.cpp b/src/app/ReadClient.cpp index 1875251e511df3..e430c0ea5ddb48 100644 --- a/src/app/ReadClient.cpp +++ b/src/app/ReadClient.cpp @@ -789,39 +789,12 @@ CHIP_ERROR ReadClient::RefreshLivenessCheckTimer() { CHIP_ERROR err = CHIP_NO_ERROR; - VerifyOrReturnError(mState == ClientState::SubscriptionActive, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(IsSubscriptionActive(), CHIP_ERROR_INCORRECT_STATE); CancelLivenessCheckTimer(); System::Clock::Timeout timeout; - - if (mLivenessTimeoutOverride != System::Clock::kZero) - { - timeout = mLivenessTimeoutOverride; - } - else - { - VerifyOrReturnError(mReadPrepareParams.mSessionHolder, CHIP_ERROR_INCORRECT_STATE); - - // - // To calculate the duration we're willing to wait for a report to come to us, we take into account the maximum interval of - // the subscription AND the time it takes for the report to make it to us in the worst case. This latter bit involves - // computing the Ack timeout from the publisher for the ReportData message being sent to us using our IDLE interval as the - // basis for that computation. - // - // Make sure to use the retransmission computation that includes backoff. For purposes of that computation, treat us as - // active now (since we are right now sending/receiving messages), and use the default "how long are we guaranteed to stay - // active" threshold for now. - // - // TODO: We need to find a good home for this logic that will correctly compute this based on transport. For now, this will - // suffice since we don't use TCP as a transport currently and subscriptions over BLE aren't really a thing. - // - const auto & ourMrpConfig = GetDefaultMRPConfig(); - auto publisherTransmissionTimeout = - GetRetransmissionTimeout(ourMrpConfig.mActiveRetransTimeout, ourMrpConfig.mIdleRetransTimeout, - System::SystemClock().GetMonotonicTimestamp(), Transport::kMinActiveTime); - timeout = System::Clock::Seconds16(mMaxInterval) + publisherTransmissionTimeout; - } + ReturnErrorOnFailure(ComputeLivenessCheckTimerTimeout(&timeout)); // EFR32/MBED/INFINION/K32W's chrono count return long unsigned, but other platform returns unsigned ChipLogProgress( @@ -834,6 +807,37 @@ CHIP_ERROR ReadClient::RefreshLivenessCheckTimer() return err; } +CHIP_ERROR ReadClient::ComputeLivenessCheckTimerTimeout(System::Clock::Timeout * aTimeout) +{ + if (mLivenessTimeoutOverride != System::Clock::kZero) + { + *aTimeout = mLivenessTimeoutOverride; + return CHIP_NO_ERROR; + } + + VerifyOrReturnError(mReadPrepareParams.mSessionHolder, CHIP_ERROR_INCORRECT_STATE); + + // + // To calculate the duration we're willing to wait for a report to come to us, we take into account the maximum interval of + // the subscription AND the time it takes for the report to make it to us in the worst case. This latter bit involves + // computing the Ack timeout from the publisher for the ReportData message being sent to us using our IDLE interval as the + // basis for that computation. + // + // Make sure to use the retransmission computation that includes backoff. For purposes of that computation, treat us as + // active now (since we are right now sending/receiving messages), and use the default "how long are we guaranteed to stay + // active" threshold for now. + // + // TODO: We need to find a good home for this logic that will correctly compute this based on transport. For now, this will + // suffice since we don't use TCP as a transport currently and subscriptions over BLE aren't really a thing. + // + const auto & ourMrpConfig = GetDefaultMRPConfig(); + auto publisherTransmissionTimeout = + GetRetransmissionTimeout(ourMrpConfig.mActiveRetransTimeout, ourMrpConfig.mIdleRetransTimeout, + System::SystemClock().GetMonotonicTimestamp(), Transport::kMinActiveTime); + *aTimeout = System::Clock::Seconds16(mMaxInterval) + publisherTransmissionTimeout; + return CHIP_NO_ERROR; +} + void ReadClient::CancelLivenessCheckTimer() { InteractionModelEngine::GetInstance()->GetExchangeManager()->GetSessionManager()->SystemLayer()->CancelTimer( @@ -1188,5 +1192,22 @@ void ReadClient::TriggerResubscribeIfScheduled(const char * reason) OnResubscribeTimerCallback(nullptr, this); } +Optional ReadClient::GetSubscriptionTimeout() +{ + if (!IsSubscriptionType() || !IsSubscriptionActive()) + { + return NullOptional; + } + + System::Clock::Timeout timeout; + CHIP_ERROR err = ComputeLivenessCheckTimerTimeout(&timeout); + if (err != CHIP_NO_ERROR) + { + return NullOptional; + } + + return MakeOptional(timeout); +} + } // namespace app } // namespace chip diff --git a/src/app/ReadClient.h b/src/app/ReadClient.h index a4d2b087dd967d..0fa98b02b6e7dc 100644 --- a/src/app/ReadClient.h +++ b/src/app/ReadClient.h @@ -425,6 +425,16 @@ class ReadClient : public Messaging::ExchangeDelegate */ void TriggerResubscribeIfScheduled(const char * reason); + /** + * Returns the timeout after which we consider the subscription to have + * dropped, if we have received no messages within that amount of time. + * + * Returns NullOptional if a subscription has not yet been established (and + * hence the MaxInterval is not yet known), or if the subscription session + * is gone and hence the relevant MRP parameters can no longer be determined. + */ + Optional GetSubscriptionTimeout(); + private: friend class TestReadInteraction; friend class InteractionModelEngine; @@ -471,6 +481,7 @@ class ReadClient : public Messaging::ExchangeDelegate static void OnLivenessTimeoutCallback(System::Layer * apSystemLayer, void * apAppState); CHIP_ERROR ProcessSubscribeResponse(System::PacketBufferHandle && aPayload); CHIP_ERROR RefreshLivenessCheckTimer(); + CHIP_ERROR ComputeLivenessCheckTimerTimeout(System::Clock::Timeout * aTimeout); void CancelLivenessCheckTimer(); void CancelResubscribeTimer(); void MoveToState(const ClientState aTargetState);