Skip to content

Commit

Permalink
Add intelligence to the exchange context
Browse files Browse the repository at this point in the history
  • Loading branch information
mkardous-silabs committed Oct 5, 2023
1 parent 0b39434 commit 5b2ad6c
Show file tree
Hide file tree
Showing 11 changed files with 306 additions and 87 deletions.
1 change: 1 addition & 0 deletions src/app/clusters/ota-requestor/DefaultOTARequestor.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ class DefaultOTARequestor : public OTARequestorInterface, public BDXDownloader::
if (!payloadHeader.HasMessageType(chip::Protocols::SecureChannel::MsgType::StatusReport))
{
ec->WillSendMessage();
ec->SetShouldPeerBeActive(true);
}

return CHIP_NO_ERROR;
Expand Down
24 changes: 23 additions & 1 deletion src/messaging/ExchangeContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,10 @@ CHIP_ERROR ExchangeContext::HandleMessage(uint32_t messageCounter, const Payload
// layer has completed its work on the ExchangeContext.
ExchangeHandle ref(*this);

// If we received a message from the Peer and we are still expecting a response, we know the peer is active
// If we receive a message from the Peer but we are not expecting a response, we don't know if the peer is still active
SetShouldPeerBeActive(IsResponseExpected());

bool isStandaloneAck = payloadHeader.HasMessageType(Protocols::SecureChannel::MsgType::StandaloneAck);
bool isDuplicate = msgFlags.Has(MessageFlagValues::kDuplicateMessage);

Expand Down Expand Up @@ -565,7 +569,6 @@ CHIP_ERROR ExchangeContext::HandleMessage(uint32_t messageCounter, const Payload
if (payloadHeader.NeedsAck())
{
// An acknowledgment needs to be sent back to the peer for this message on this exchange,

HandleNeedsAck(messageCounter, msgFlags);
}
}
Expand Down Expand Up @@ -628,6 +631,9 @@ CHIP_ERROR ExchangeContext::HandleMessage(uint32_t messageCounter, const Payload
// If the context was expecting a response to a previously sent message, this message
// is implicitly that response.
SetResponseExpected(false);

// If we received the expected response, we don't if the peer is still active after having sent the response
SetShouldPeerBeActive(false);
}

// Don't send messages on to our delegate if our dispatch does not allow
Expand Down Expand Up @@ -689,5 +695,21 @@ void ExchangeContext::ExchangeSessionHolder::GrabExpiredSession(const SessionHan
GrabUnchecked(session);
}

bool ExchangeContext::ShouldPeerBeActive()
{
// If we are not the initiator, it means the peer sent the first message.
// This means our peer is active if we are sending a message to them.
if (!IsInitiator())
return true;

// If we create an Ephemeral Exchange, it was just to generate a StandaloneAck
// Since we are sending an ack, we know the peer is active
if (IsEphemeralExchange())
return true;

// Return previously stored state if we have no absolute answer
return mFlags.Has(Flags::kPeerShouldBeActive);
}

} // namespace Messaging
} // namespace chip
60 changes: 41 additions & 19 deletions src/messaging/ExchangeContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,47 @@ class DLL_EXPORT ExchangeContext : public ReliableMessageContext,
*/
bool IsSendExpected() const { return mFlags.Has(Flags::kFlagWillSendMessage); }

/**
* Notifies the exchange that our consummer is going to send a message where it knows the peer (receiver) should be active
*
* This API is used to set the ShouldPeerBeActive flag.
* The ShouldPeerBeActive flag allows the consummer of the exchange to notify the exchange that the peer (receiver)
* will be active for the next message the consummer will send.
* This allows the consummer to notify the exchange on the state of the peer with the context of the messages being sent.
*
* The ShouldPeerBeActive flag is only used when calculating the next retransmission time in the ReliableMessageMgr.
* If the ShouldPeerBeActive flag is true, we will used the Active Retransmission timeout when calculating the next
* retransmission time. If the ShouldPeerBeActive flag is false, we will rely on other information to determine which
* retransmission timeout should be used. See the ShouldPeerBeActive API for the alternative means to determine if the Peer
* (receiver) is active.
*
* The first message of the exchange set as the initiator should never have the ShouldPeerBeActive flag to true.
* The API should only called after receiving a message from the peer and after calling the WillSendMessage API.
* The next message sent will then use the active retransmission time out.
* The flag is set to false each time we receive the response from our peer (receiver).
* As such, the API needs to be called each time we send another message over the exchange.
*
* The API call is not mandatory for the communication to be successful.
* If the call is not done, we will rely on information within the exchange context.
*
* @param shouldPeerBeActive true if the peer should be active, false if we don't know or it should not be
*/
void SetShouldPeerBeActive(bool shouldPeerBeActive) { mFlags.Set(Flags::kPeerShouldBeActive, shouldPeerBeActive); }

/**
* Function checks with information available in the ExchangeContext if the peer should be active or not
* API should only be used when we are determining if we need to use the Active or Idle retransmission timeout
*
* If we are not initiator -> peer is active
* If ephemeral context -> peer is active
* else we default to information provided by the consummer
*
* @return true Based on available information, Peer should be active
* @return false We weren't able to determine if the peer is active.
* We don't know in which state the peer is.
*/
bool ShouldPeerBeActive();

#if CONFIG_BUILD_FOR_HOST_UNIT_TEST
SessionHolder & GetSessionHolder() { return mSession; }

Expand Down Expand Up @@ -292,25 +333,6 @@ class DLL_EXPORT ExchangeContext : public ReliableMessageContext,
*/
void MessageHandled();

/**
* Updates Sleepy End Device intervals mode in the following way:
* - does nothing for exchanges over Bluetooth LE
* - requests active mode if there are more messages,
* including MRP acknowledgements, expected to be sent or received on
* this exchange.
* - withdraws the request for active mode, otherwise.
*/
void UpdateSEDIntervalMode();

/**
* Requests or withdraws the request for Sleepy End Device active mode
* based on the argument value.
*
* Note that the device switches to the idle mode if no
* exchange nor other component requests the active mode.
*/
void UpdateSEDIntervalMode(bool activeMode);

static ExchangeMessageDispatch & GetMessageDispatch(bool isEphemeralExchange, ExchangeDelegate * delegate);

// If SetAutoReleaseSession() is called, this exchange must be using a SecureSession, and should
Expand Down
1 change: 0 additions & 1 deletion src/messaging/ReliableMessageContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ void ReliableMessageContext::HandleRcvdAck(uint32_t ackMessageCounter)
}

CHIP_ERROR ReliableMessageContext::HandleNeedsAck(uint32_t messageCounter, BitFlags<MessageFlagValues> messageFlags)

{
CHIP_ERROR err = HandleNeedsAckInner(messageCounter, messageFlags);

Expand Down
38 changes: 20 additions & 18 deletions src/messaging/ReliableMessageContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,6 @@ class ReliableMessageContext
/// Set if this exchange is requesting Sleepy End Device active mode
void SetRequestingActiveMode(bool activeMode);

/// Determine whether this exchange is requesting Sleepy End Device active mode
bool IsRequestingActiveMode() const;

/// Determine whether this exchange is a EphemeralExchange for replying a StandaloneAck
bool IsEphemeralExchange() const;

Expand Down Expand Up @@ -164,18 +161,33 @@ class ReliableMessageContext
/// When set, we have had Close() or Abort() called on us already.
kFlagClosed = (1u << 7),

/// When set, signifies that the exchange is requesting Sleepy End Device active mode.
kFlagActiveMode = (1u << 8),

/// When set, signifies that the exchange created sorely for replying a StandaloneAck
kFlagEphemeralExchange = (1u << 9),
kFlagEphemeralExchange = (1u << 8),

/// When set, ignore session being released, because we are releasing it ourselves.
kFlagIgnoreSessionRelease = (1u << 10),
kFlagIgnoreSessionRelease = (1u << 9),

// When set, sender knows that the peer (receiver) should currently be active
// When bit is not set, we don't know if the peer (receiver) is active or not
kPeerShouldBeActive = (1u << 10)
};

BitFlags<Flags> mFlags; // Internal state flags

/**
* Function checks with information available in the ExchangeContext if the peer should be active or not
* API should only be used when we are determining if we need to use the Active or Idle retransmission timeout
*
* If we are not initiator -> peer is active
* If ephemeral context -> peer is active
* else we default to information provided by the consummer
*
* @return true Based on available information, Peer should be active
* @return false We weren't able to determine if the peer is active.
* We don't know in which state the peer is.
*/
bool ShouldPeerBeActive();

private:
void HandleRcvdAck(uint32_t ackMessageCounter);
CHIP_ERROR HandleNeedsAck(uint32_t messageCounter, BitFlags<MessageFlagValues> messageFlags);
Expand Down Expand Up @@ -226,11 +238,6 @@ inline bool ReliableMessageContext::HasPiggybackAckPending() const
return mFlags.Has(Flags::kFlagAckMessageCounterIsValid);
}

inline bool ReliableMessageContext::IsRequestingActiveMode() const
{
return mFlags.Has(Flags::kFlagActiveMode);
}

inline void ReliableMessageContext::SetAutoRequestAck(bool autoReqAck)
{
mFlags.Set(Flags::kFlagAutoRequestAck, autoReqAck);
Expand All @@ -241,11 +248,6 @@ inline void ReliableMessageContext::SetAckPending(bool inAckPending)
mFlags.Set(Flags::kFlagAckPending, inAckPending);
}

inline void ReliableMessageContext::SetRequestingActiveMode(bool activeMode)
{
mFlags.Set(Flags::kFlagActiveMode, activeMode);
}

inline bool ReliableMessageContext::IsEphemeralExchange() const
{
return mFlags.Has(Flags::kFlagEphemeralExchange);
Expand Down
30 changes: 22 additions & 8 deletions src/messaging/ReliableMessageMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,10 +173,7 @@ void ReliableMessageMgr::ExecuteActions()
" Send Cnt %d",
messageCounter, ChipLogValueExchange(&entry->ec.Get()), entry->sendCount);

// Choose active/idle timeout from PeerActiveMode of session per 4.11.2.1. Retransmissions.
System::Clock::Timestamp baseTimeout = entry->ec->GetSessionHandle()->GetMRPBaseTimeout();
System::Clock::Timestamp backoff = ReliableMessageMgr::GetBackoff(baseTimeout, entry->sendCount);
entry->nextRetransTime = System::SystemClock().GetMonotonicTimestamp() + backoff;
CalculateNextRetransTime(entry);
SendFromRetransTable(entry);

return Loop::Continue;
Expand Down Expand Up @@ -277,10 +274,7 @@ System::Clock::Timestamp ReliableMessageMgr::GetBackoff(System::Clock::Timestamp

void ReliableMessageMgr::StartRetransmision(RetransTableEntry * entry)
{
// Choose active/idle timeout from PeerActiveMode of session per 4.11.2.1. Retransmissions.
System::Clock::Timestamp baseTimeout = entry->ec->GetSessionHandle()->GetMRPBaseTimeout();
System::Clock::Timestamp backoff = ReliableMessageMgr::GetBackoff(baseTimeout, entry->sendCount);
entry->nextRetransTime = System::SystemClock().GetMonotonicTimestamp() + backoff;
CalculateNextRetransTime(entry);
StartTimer();
}

Expand Down Expand Up @@ -471,6 +465,26 @@ CHIP_ERROR ReliableMessageMgr::MapSendError(CHIP_ERROR error, uint16_t exchangeI
return error;
}

void ReliableMessageMgr::CalculateNextRetransTime(RetransTableEntry * entry)
{
System::Clock::Timestamp baseTimeout = System::Clock::Milliseconds64(0);

if (entry->ec->ShouldPeerBeActive())
{
// If we know the peer is active with the exchangeContext, use the Active Retrans timeout
baseTimeout = entry->ec->GetSessionHandle()->GetRemoteMRPConfig().mActiveRetransTimeout;
}
else
{
// If the exchange context doesn't know if the peer is active or not.
// Choose active/idle timeout from PeerActiveMode of session per 4.11.2.1. Retransmissions.
baseTimeout = entry->ec->GetSessionHandle()->GetMRPBaseTimeout();
}

System::Clock::Timestamp backoff = ReliableMessageMgr::GetBackoff(baseTimeout, entry->sendCount);
entry->nextRetransTime = System::SystemClock().GetMonotonicTimestamp() + backoff;
}

#if CHIP_CONFIG_TEST
int ReliableMessageMgr::TestGetCountRetransTable()
{
Expand Down
8 changes: 8 additions & 0 deletions src/messaging/ReliableMessageMgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,14 @@ class ReliableMessageMgr
#endif // CHIP_CONFIG_TEST

private:
/**
* Calculates the next retransmission time for the entry
* Function sets the nextRetransTime of the entry
*
* @param[in/out] entry RetransTableEntry for which we need to calculate the nextRetransTime
*/
void CalculateNextRetransTime(RetransTableEntry * entry);

ObjectPool<ExchangeContext, CHIP_CONFIG_MAX_EXCHANGE_CONTEXTS> & mContextPool;
chip::System::Layer * mSystemLayer;

Expand Down
Loading

0 comments on commit 5b2ad6c

Please sign in to comment.