Skip to content

Commit 9789220

Browse files
ReadClient should delay re-subscribe attempts based on delay in BUSY responses.
The ifdefs are to reduce the codesize costs for situations where the BUSY handling is not needed (e.g. if the application does not use ReadClient at all and does not care about handling the timeout from BUSY from OperationalSessionSetup).
1 parent 6c89640 commit 9789220

6 files changed

+72
-12
lines changed

src/app/BUILD.gn

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ buildconfig_header("app_buildconfig") {
7777
"TIME_SYNC_ENABLE_TSC_FEATURE=${time_sync_enable_tsc_feature}",
7878
"NON_SPEC_COMPLIANT_OTA_ACTION_DELAY_FLOOR=${non_spec_compliant_ota_action_delay_floor}",
7979
"CHIP_DEVICE_CONFIG_DYNAMIC_SERVER=${chip_build_controller_dynamic_server}",
80+
"CHIP_CONFIG_ENABLE_BUSY_HANDLING_FOR_OPERATIONAL_SESSION_SETUP=${chip_enable_busy_handling_for_operational_session_setup}",
8081
]
8182

8283
visibility = [ ":app_config" ]

src/app/OperationalSessionSetup.cpp

+17-4
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,12 @@ void OperationalSessionSetup::DequeueConnectionCallbacks(CHIP_ERROR error, Sessi
351351
auto * exchangeMgr = mInitParams.exchangeMgr;
352352
Optional<SessionHandle> optionalSessionHandle = mSecureSession.Get();
353353
ScopedNodeId peerId = mPeerId;
354+
System::Clock::Milliseconds16 requestedBusyDelay =
355+
#if CHIP_CONFIG_ENABLE_BUSY_HANDLING_FOR_OPERATIONAL_SESSION_SETUP
356+
mRequestedBusyDelay;
357+
#else
358+
System::Clock::kZero;
359+
#endif // CHIP_CONFIG_ENABLE_BUSY_HANDLING_FOR_OPERATIONAL_SESSION_SETUP
354360

355361
if (releaseBehavior == ReleaseBehavior::Release)
356362
{
@@ -361,14 +367,15 @@ void OperationalSessionSetup::DequeueConnectionCallbacks(CHIP_ERROR error, Sessi
361367
// DO NOT touch any members of this object after this point. It's dead.
362368

363369
NotifyConnectionCallbacks(failureReady, setupFailureReady, successReady, error, stage, peerId, performingAddressUpdate,
364-
exchangeMgr, optionalSessionHandle);
370+
exchangeMgr, optionalSessionHandle, requestedBusyDelay);
365371
}
366372

367373
void OperationalSessionSetup::NotifyConnectionCallbacks(Cancelable & failureReady, Cancelable & setupFailureReady,
368374
Cancelable & successReady, CHIP_ERROR error,
369375
SessionEstablishmentStage stage, const ScopedNodeId & peerId,
370376
bool performingAddressUpdate, Messaging::ExchangeManager * exchangeMgr,
371-
const Optional<SessionHandle> & optionalSessionHandle)
377+
const Optional<SessionHandle> & optionalSessionHandle,
378+
System::Clock::Milliseconds16 requestedBusyDelay)
372379
{
373380
//
374381
// If we encountered no error, go ahead and call all success callbacks. Otherwise,
@@ -401,6 +408,12 @@ void OperationalSessionSetup::NotifyConnectionCallbacks(Cancelable & failureRead
401408
{
402409
// Initialize the ConnnectionFailureInfo object
403410
ConnnectionFailureInfo failureInfo(peerId, error, stage);
411+
#if CHIP_CONFIG_ENABLE_BUSY_HANDLING_FOR_OPERATIONAL_SESSION_SETUP
412+
if (error == CHIP_ERROR_BUSY)
413+
{
414+
failureInfo.requestedBusyDelay.Emplace(requestedBusyDelay);
415+
}
416+
#endif // CHIP_CONFIG_ENABLE_BUSY_HANDLING_FOR_OPERATIONAL_SESSION_SETUP
404417
cb->mCall(cb->mContext, failureInfo);
405418
}
406419
}
@@ -482,9 +495,9 @@ void OperationalSessionSetup::OnSessionEstablishmentError(CHIP_ERROR error, Sess
482495

483496
void OperationalSessionSetup::OnResponderBusy(System::Clock::Milliseconds16 requestedDelay)
484497
{
485-
#if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
498+
#if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES || CHIP_CONFIG_ENABLE_BUSY_HANDLING_FOR_OPERATIONAL_SESSION_SETUP
486499
// Store the requested delay, so that we can use it for scheduling our
487-
// retry.
500+
// retry or communicate it to our API consumer.
488501
mRequestedBusyDelay = requestedDelay;
489502
#endif
490503
}

src/app/OperationalSessionSetup.h

+18-3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
#pragma once
2828

29+
#include <app/AppConfig.h>
2930
#include <app/CASEClient.h>
3031
#include <app/CASEClientPool.h>
3132
#include <app/DeviceProxy.h>
@@ -161,6 +162,13 @@ class DLL_EXPORT OperationalSessionSetup : public SessionEstablishmentDelegate,
161162
CHIP_ERROR error;
162163
SessionEstablishmentStage sessionStage;
163164

165+
// When the response was BUSY, error will be CHIP_ERROR_BUSY and
166+
// requestedBusyDelay will be set, if handling of BUSY responses is
167+
// enabled.
168+
#if CHIP_CONFIG_ENABLE_BUSY_HANDLING_FOR_OPERATIONAL_SESSION_SETUP
169+
Optional<System::Clock::Milliseconds16> requestedBusyDelay;
170+
#endif // CHIP_CONFIG_ENABLE_BUSY_HANDLING_FOR_OPERATIONAL_SESSION_SETUP
171+
164172
ConnnectionFailureInfo(const ScopedNodeId & peer, CHIP_ERROR err, SessionEstablishmentStage stage) :
165173
peerId(peer), error(err), sessionStage(stage)
166174
{}
@@ -306,6 +314,10 @@ class DLL_EXPORT OperationalSessionSetup : public SessionEstablishmentDelegate,
306314

307315
bool mPerformingAddressUpdate = false;
308316

317+
#if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES || CHIP_CONFIG_ENABLE_BUSY_HANDLING_FOR_OPERATIONAL_SESSION_SETUP
318+
System::Clock::Milliseconds16 mRequestedBusyDelay = System::Clock::kZero;
319+
#endif // CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES || CHIP_CONFIG_ENABLE_BUSY_HANDLING_FOR_OPERATIONAL_SESSION_SETUP
320+
309321
#if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
310322
// When we TryNextResult on the resolver, it will synchronously call back
311323
// into our OnNodeAddressResolved when it succeeds. We need to track
@@ -320,8 +332,6 @@ class DLL_EXPORT OperationalSessionSetup : public SessionEstablishmentDelegate,
320332

321333
uint8_t mResolveAttemptsAllowed = 0;
322334

323-
System::Clock::Milliseconds16 mRequestedBusyDelay = System::Clock::kZero;
324-
325335
Callback::CallbackDeque mConnectionRetry;
326336
#endif // CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES
327337

@@ -385,7 +395,12 @@ class DLL_EXPORT OperationalSessionSetup : public SessionEstablishmentDelegate,
385395
Callback::Cancelable & successReady, CHIP_ERROR error, SessionEstablishmentStage stage,
386396
const ScopedNodeId & peerId, bool performingAddressUpdate,
387397
Messaging::ExchangeManager * exchangeMgr,
388-
const Optional<SessionHandle> & optionalSessionHandle);
398+
const Optional<SessionHandle> & optionalSessionHandle,
399+
// requestedBusyDelay will be 0 if not
400+
// CHIP_CONFIG_ENABLE_BUSY_HANDLING_FOR_OPERATIONAL_SESSION_SETUP,
401+
// and only has a meaningful value
402+
// when the error is CHIP_ERROR_BUSY.
403+
System::Clock::Milliseconds16 requestedBusyDelay);
389404

390405
/**
391406
* Triggers a DNSSD lookup to find a usable peer address.

src/app/ReadClient.cpp

+26-3
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,11 @@ uint32_t ReadClient::ComputeTimeTillNextSubscription()
135135
waitTimeInMsec = minWaitTimeInMsec + (Crypto::GetRandU32() % (maxWaitTimeInMsec - minWaitTimeInMsec));
136136
}
137137

138+
if (mMinimalResubscribeDelay.count() > waitTimeInMsec)
139+
{
140+
waitTimeInMsec = mMinimalResubscribeDelay.count();
141+
}
142+
138143
return waitTimeInMsec;
139144
}
140145

@@ -1058,6 +1063,10 @@ CHIP_ERROR ReadClient::ProcessSubscribeResponse(System::PacketBufferHandle && aP
10581063

10591064
CHIP_ERROR ReadClient::SendAutoResubscribeRequest(ReadPrepareParams && aReadPrepareParams)
10601065
{
1066+
// Make sure we don't use minimal resubscribe delays from previous attempts
1067+
// for this one.
1068+
mMinimalResubscribeDelay = System::Clock::kZero;
1069+
10611070
mReadPrepareParams = std::move(aReadPrepareParams);
10621071
CHIP_ERROR err = SendSubscribeRequest(mReadPrepareParams);
10631072
if (err != CHIP_NO_ERROR)
@@ -1239,14 +1248,28 @@ void ReadClient::HandleDeviceConnected(void * context, Messaging::ExchangeManage
12391248
}
12401249
}
12411250

1242-
void ReadClient::HandleDeviceConnectionFailure(void * context, const ScopedNodeId & peerId, CHIP_ERROR err)
1251+
void ReadClient::HandleDeviceConnectionFailure(void * context, const OperationalSessionSetup::ConnnectionFailureInfo & failureInfo)
12431252
{
12441253
ReadClient * const _this = static_cast<ReadClient *>(context);
12451254
VerifyOrDie(_this != nullptr);
12461255

1247-
ChipLogError(DataManagement, "Failed to establish CASE for re-subscription with error '%" CHIP_ERROR_FORMAT "'", err.Format());
1256+
ChipLogError(DataManagement, "Failed to establish CASE for re-subscription with error '%" CHIP_ERROR_FORMAT "'",
1257+
failureInfo.error.Format());
1258+
1259+
#if CHIP_CONFIG_ENABLE_BUSY_HANDLING_FOR_OPERATIONAL_SESSION_SETUP
1260+
#if CHIP_DETAIL_LOGGING
1261+
if (failureInfo.requestedBusyDelay.HasValue())
1262+
{
1263+
ChipLogDetail(DataManagement, "Will delay resubscription by %u ms due to BUSY response",
1264+
failureInfo.requestedBusyDelay.Value().count());
1265+
}
1266+
#endif // CHIP_DETAIL_LOGGING
1267+
_this->mMinimalResubscribeDelay = failureInfo.requestedBusyDelay.ValueOr(System::Clock::kZero);
1268+
#else
1269+
_this->mMinimalResubscribeDelay = System::Clock::kZero;
1270+
#endif // CHIP_CONFIG_ENABLE_BUSY_HANDLING_FOR_OPERATIONAL_SESSION_SETUP
12481271

1249-
_this->Close(err);
1272+
_this->Close(failureInfo.error);
12501273
}
12511274

12521275
void ReadClient::OnResubscribeTimerCallback(System::Layer * /* If this starts being used, fix callers that pass nullptr */,

src/app/ReadClient.h

+6-2
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,7 @@ class ReadClient : public Messaging::ExchangeDelegate
612612

613613
static void HandleDeviceConnected(void * context, Messaging::ExchangeManager & exchangeMgr,
614614
const SessionHandle & sessionHandle);
615-
static void HandleDeviceConnectionFailure(void * context, const ScopedNodeId & peerId, CHIP_ERROR error);
615+
static void HandleDeviceConnectionFailure(void * context, const OperationalSessionSetup::ConnnectionFailureInfo & failureInfo);
616616

617617
CHIP_ERROR GetMinEventNumber(const ReadPrepareParams & aReadPrepareParams, Optional<EventNumber> & aEventMin);
618618

@@ -642,8 +642,12 @@ class ReadClient : public Messaging::ExchangeDelegate
642642
bool mForceCaseOnNextResub = true;
643643
bool mIsResubscriptionScheduled = false;
644644

645+
// mMinimalResubscribeDelay is used to store the delay returned with a BUSY
646+
// response to a Sigma1 message.
647+
System::Clock::Milliseconds16 mMinimalResubscribeDelay = System::Clock::kZero;
648+
645649
chip::Callback::Callback<OnDeviceConnected> mOnConnectedCallback;
646-
chip::Callback::Callback<OnDeviceConnectionFailure> mOnConnectionFailureCallback;
650+
chip::Callback::Callback<OperationalSessionSetup::OnSetupFailure> mOnConnectionFailureCallback;
647651

648652
ReadClient * mpNext = nullptr;
649653
InteractionModelEngine * mpImEngine = nullptr;

src/app/common_flags.gni

+4
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,8 @@ declare_args() {
1717
chip_app_use_echo = false
1818
chip_enable_read_client = true
1919
chip_build_controller_dynamic_server = false
20+
21+
# Flag that controls whether the time-to-wait from BUSY responses is
22+
# communicated to OperationalSessionSetup API consumers.
23+
chip_enable_busy_handling_for_operational_session_setup = true
2024
}

0 commit comments

Comments
 (0)