Skip to content

Commit

Permalink
[IM] Calculate interaction model timeout accoring to RMP timeouts (#1…
Browse files Browse the repository at this point in the history
…8744)

* [IM] Calculate interaction model timeout accoring to CRMP timeouts

* Apply suggestions from code review

Co-authored-by: Boris Zbarsky <[email protected]>

* Add more generialized timeout calculation API

* Address comments

* Fix

Co-authored-by: Boris Zbarsky <[email protected]>
  • Loading branch information
2 people authored and pull[bot] committed Jun 14, 2022
1 parent 03d93bd commit 1594044
Show file tree
Hide file tree
Showing 16 changed files with 75 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@
#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE 20202021
#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR 0xF00

#define CHIP_DEVICE_CONFIG_SED_IDLE_INTERVAL 2000_ms32
#define CHIP_DEVICE_CONFIG_SED_IDLE_INTERVAL 20000_ms32
2 changes: 1 addition & 1 deletion src/app/CommandSender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ CHIP_ERROR CommandSender::SendCommandRequest(const SessionHandle & session, Opti
VerifyOrReturnError(mpExchangeCtx != nullptr, CHIP_ERROR_NO_MEMORY);
VerifyOrReturnError(!mpExchangeCtx->IsGroupExchangeContext(), CHIP_ERROR_INVALID_MESSAGE_TYPE);

mpExchangeCtx->SetResponseTimeout(timeout.ValueOr(kImMessageTimeout));
mpExchangeCtx->SetResponseTimeout(timeout.ValueOr(session->ComputeRoundTripTimeout(app::kExpectedIMProcessingTime)));

if (mTimedInvokeTimeoutMs.HasValue())
{
Expand Down
6 changes: 5 additions & 1 deletion src/app/InteractionModelTimeout.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,15 @@
#pragma once

#include <system/SystemClock.h>
#include <transport/Session.h>
#include <transport/SessionHandle.h>

namespace chip {
namespace app {

static constexpr System::Clock::Timeout kImMessageTimeout = System::Clock::Seconds16(12);
// This is an expected upper bound of time-to-first-byte for IM transactions, the actual processing time should never exceed this
// value unless specified elsewhere (e.g. async command handling for some clusters).
static constexpr System::Clock::Timeout kExpectedIMProcessingTime = System::Clock::Seconds16(2);

} // namespace app
} // namespace chip
19 changes: 17 additions & 2 deletions src/app/ReadClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,14 @@ CHIP_ERROR ReadClient::SendReadRequest(ReadPrepareParams & aReadPrepareParams)
mpExchangeCtx = mpExchangeMgr->NewContext(aReadPrepareParams.mSessionHolder.Get().Value(), this);
VerifyOrReturnError(mpExchangeCtx != nullptr, err = CHIP_ERROR_NO_MEMORY);

mpExchangeCtx->SetResponseTimeout(aReadPrepareParams.mTimeout);
if (aReadPrepareParams.mTimeout == System::Clock::kZero)
{
mpExchangeCtx->UseSuggestedResponseTimeout(app::kExpectedIMProcessingTime);
}
else
{
mpExchangeCtx->SetResponseTimeout(aReadPrepareParams.mTimeout);
}

ReturnErrorOnFailure(mpExchangeCtx->SendMessage(Protocols::InteractionModel::MsgType::ReadRequest, std::move(msgBuf),
Messaging::SendFlags(Messaging::SendMessageFlags::kExpectResponse)));
Expand Down Expand Up @@ -921,7 +928,15 @@ CHIP_ERROR ReadClient::SendSubscribeRequestImpl(const ReadPrepareParams & aReadP

mpExchangeCtx = mpExchangeMgr->NewContext(aReadPrepareParams.mSessionHolder.Get().Value(), this);
VerifyOrReturnError(mpExchangeCtx != nullptr, CHIP_ERROR_NO_MEMORY);
mpExchangeCtx->SetResponseTimeout(kImMessageTimeout);

if (aReadPrepareParams.mTimeout == System::Clock::kZero)
{
mpExchangeCtx->UseSuggestedResponseTimeout(app::kExpectedIMProcessingTime);
}
else
{
mpExchangeCtx->SetResponseTimeout(aReadPrepareParams.mTimeout);
}

ReturnErrorOnFailure(mpExchangeCtx->SendMessage(Protocols::InteractionModel::MsgType::SubscribeRequest, std::move(msgBuf),
Messaging::SendFlags(Messaging::SendMessageFlags::kExpectResponse)));
Expand Down
3 changes: 2 additions & 1 deletion src/app/ReadHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,8 @@ CHIP_ERROR ReadHandler::SendReportData(System::PacketBufferHandle && aPayload, b
{
MoveToState(HandlerState::AwaitingReportResponse);
}
mpExchangeCtx->SetResponseTimeout(kImMessageTimeout);

mpExchangeCtx->UseSuggestedResponseTimeout(app::kExpectedIMProcessingTime);
CHIP_ERROR err =
mpExchangeCtx->SendMessage(Protocols::InteractionModel::MsgType::ReportData, std::move(aPayload),
Messaging::SendFlags(noResponseExpected ? Messaging::SendMessageFlags::kNone
Expand Down
4 changes: 3 additions & 1 deletion src/app/ReadPrepareParams.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ struct ReadPrepareParams
DataVersionFilter * mpDataVersionFilterList = nullptr;
size_t mDataVersionFilterListSize = 0;
Optional<EventNumber> mEventNumber;
System::Clock::Timeout mTimeout = kImMessageTimeout;
// The timeout for waiting for the response or System::Clock::kZero to let the interaction model decide the timeout based on the
// MRP timeouts of the session.
System::Clock::Timeout mTimeout = System::Clock::kZero;
uint16_t mMinIntervalFloorSeconds = 0;
uint16_t mMaxIntervalCeilingSeconds = 0;
bool mKeepSubscriptions = false;
Expand Down
2 changes: 1 addition & 1 deletion src/app/StatusResponse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ CHIP_ERROR StatusResponse::Send(Protocols::InteractionModel::Status aStatus, Mes
response.Status(aStatus);
ReturnErrorOnFailure(response.GetError());
ReturnErrorOnFailure(writer.Finalize(&msgBuf));
apExchangeContext->SetResponseTimeout(kImMessageTimeout);
apExchangeContext->UseSuggestedResponseTimeout(app::kExpectedIMProcessingTime);
ReturnErrorOnFailure(apExchangeContext->SendMessage(Protocols::InteractionModel::MsgType::StatusResponse, std::move(msgBuf),
aExpectResponse ? Messaging::SendMessageFlags::kExpectResponse
: Messaging::SendMessageFlags::kNone));
Expand Down
3 changes: 2 additions & 1 deletion src/app/TimedHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@ CHIP_ERROR TimedHandler::HandleTimedRequestAction(Messaging::ExchangeContext * a
// will send nothing and the other side will have to time out to realize
// it's missed its window).
auto delay = System::Clock::Milliseconds32(timeoutMs);
aExchangeContext->SetResponseTimeout(std::max(delay, kImMessageTimeout));
aExchangeContext->SetResponseTimeout(
std::max(delay, aExchangeContext->GetSessionHandle()->ComputeRoundTripTimeout(app::kExpectedIMProcessingTime)));
ReturnErrorOnFailure(StatusResponse::Send(Status::Success, aExchangeContext, /* aExpectResponse = */ true));

// Now just wait for the client.
Expand Down
10 changes: 9 additions & 1 deletion src/app/WriteClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,15 @@ CHIP_ERROR WriteClient::SendWriteRequest(const SessionHandle & session, System::
mpExchangeCtx = mpExchangeMgr->NewContext(session, this);
VerifyOrExit(mpExchangeCtx != nullptr, err = CHIP_ERROR_NO_MEMORY);
VerifyOrReturnError(!(mpExchangeCtx->IsGroupExchangeContext() && mHasDataVersion), CHIP_ERROR_INVALID_MESSAGE_TYPE);
mpExchangeCtx->SetResponseTimeout(timeout);

if (timeout == System::Clock::kZero)
{
mpExchangeCtx->UseSuggestedResponseTimeout(app::kExpectedIMProcessingTime);
}
else
{
mpExchangeCtx->SetResponseTimeout(timeout);
}

if (mTimedWriteTimeoutMs.HasValue())
{
Expand Down
4 changes: 2 additions & 2 deletions src/app/WriteClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,11 +214,11 @@ class WriteClient : public Messaging::ExchangeDelegate
* handle calling Shutdown on itself once it decides it's done with waiting
* for a response (i.e. times out or gets a response). Client can specify
* the maximum time to wait for response (in milliseconds) via timeout parameter.
* Default timeout value will be used otherwise.
* If the timeout is missing or is set to System::Clock::kZero, a value based on the MRP timeouts of the session will be used.
* If SendWriteRequest is never called, or the call fails, the API
* consumer is responsible for calling Shutdown on the WriteClient.
*/
CHIP_ERROR SendWriteRequest(const SessionHandle & session, System::Clock::Timeout timeout = kImMessageTimeout);
CHIP_ERROR SendWriteRequest(const SessionHandle & session, System::Clock::Timeout timeout = System::Clock::kZero);

/**
* Shutdown the WriteClient. This terminates this instance
Expand Down
2 changes: 1 addition & 1 deletion src/app/WriteHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ CHIP_ERROR WriteHandler::SendWriteResponse(System::PacketBufferTLVWriter && aMes
SuccessOrExit(err);

VerifyOrExit(mpExchangeCtx != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
mpExchangeCtx->SetResponseTimeout(kImMessageTimeout);
mpExchangeCtx->UseSuggestedResponseTimeout(app::kExpectedIMProcessingTime);
err = mpExchangeCtx->SendMessage(Protocols::InteractionModel::MsgType::WriteResponse, std::move(packet),
mHasMoreChunks ? Messaging::SendMessageFlags::kExpectResponse
: Messaging::SendMessageFlags::kNone);
Expand Down
3 changes: 2 additions & 1 deletion src/controller/tests/TestWriteChunking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,8 @@ void RunTest(nlTestSuite * apSuite, TestContext & ctx, Instructions instructions
err = writeClient->SendWriteRequest(sessionHandle);
NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR);

ctx.GetIOContext().DriveIOUntil(System::Clock::Seconds16(15),
ctx.GetIOContext().DriveIOUntil(sessionHandle->ComputeRoundTripTimeout(app::kExpectedIMProcessingTime) +
System::Clock::Seconds16(1),
[&]() { return ctx.GetExchangeManager().GetNumActiveExchanges() == 0; });

NL_TEST_ASSERT(apSuite, onGoingPath == app::ConcreteAttributePath());
Expand Down
5 changes: 5 additions & 0 deletions src/messaging/ExchangeContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ void ExchangeContext::SetResponseExpected(bool inResponseExpected)
mFlags.Set(Flags::kFlagResponseExpected, inResponseExpected);
}

void ExchangeContext::UseSuggestedResponseTimeout(Timeout applicationProcessingTimeout)
{
SetResponseTimeout(mSession->ComputeRoundTripTimeout(applicationProcessingTimeout));
}

void ExchangeContext::SetResponseTimeout(Timeout timeout)
{
mResponseTimeout = timeout;
Expand Down
9 changes: 9 additions & 0 deletions src/messaging/ExchangeContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,15 @@ class DLL_EXPORT ExchangeContext : public ReliableMessageContext,
void Close();
void Abort();

// Applies a suggested response timeout value based on the session type and the given upper layer processing time for
// the next message to the exchange. The exchange context must have a valid session when calling this function.
//
// This function is an equivalent of SetResponseTimeout(mSession->ComputeRoundTripTimeout(applicationProcessingTimeout))
void UseSuggestedResponseTimeout(Timeout applicationProcessingTimeout);

// Set the response timeout for the exchange context, regardless of the underlying session type. Using
// UseSuggestedResponseTimeout to set a timeout based on the type of the session and the application processing time instead of
// using this function is recommended.
void SetResponseTimeout(Timeout timeout);

private:
Expand Down
9 changes: 9 additions & 0 deletions src/transport/Session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,14 @@ OutgoingGroupSession * Session::AsOutgoingGroupSession()
return static_cast<OutgoingGroupSession *>(this);
}

System::Clock::Timeout Session::ComputeRoundTripTimeout(System::Clock::Timeout upperlayerProcessingTimeout)
{
if (IsGroupSession())
{
return System::Clock::kZero;
}
return GetAckTimeout() + upperlayerProcessingTimeout;
}

} // namespace Transport
} // namespace chip
6 changes: 6 additions & 0 deletions src/transport/Session.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ class Session
virtual System::Clock::Timestamp GetMRPBaseTimeout() = 0;
virtual System::Clock::Milliseconds32 GetAckTimeout() const = 0;

// Returns a suggested timeout value based on the round-trip time it takes for the peer at the other end of the session to
// receive a message, process it and send it back. This is computed based on the session type, the type of transport, sleepy
// characteristics of the target and a caller-provided value for the time it takes to process a message at the upper layer on
// the target For group sessions, this function will always return 0.
System::Clock::Timeout ComputeRoundTripTimeout(System::Clock::Timeout upperlayerProcessingTimeout);

FabricIndex GetFabricIndex() const { return mFabricIndex; }

SecureSession * AsSecureSession();
Expand Down

0 comments on commit 1594044

Please sign in to comment.