diff --git a/src/messaging/ExchangeContext.cpp b/src/messaging/ExchangeContext.cpp index ac4a620a7ee66a..1b93bff5a62e62 100644 --- a/src/messaging/ExchangeContext.cpp +++ b/src/messaging/ExchangeContext.cpp @@ -542,7 +542,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); } } @@ -590,6 +589,9 @@ CHIP_ERROR ExchangeContext::HandleMessage(uint32_t messageCounter, const Payload app::ICDNotifier::GetInstance().BroadcastNetworkActivityNotification(); #endif // CHIP_CONFIG_ENABLE_ICD_SERVER + // Set kFlagReceivedAtLeastOneMessage to true since we have received at least one new application level message + SetHasReceivedAtLeastOneMessage(true); + if (IsResponseExpected()) { // Since we got the response, cancel the response timer. diff --git a/src/messaging/ExchangeContext.h b/src/messaging/ExchangeContext.h index e30cf0593b3ed9..fc20a5aace5273 100644 --- a/src/messaging/ExchangeContext.h +++ b/src/messaging/ExchangeContext.h @@ -214,6 +214,14 @@ class DLL_EXPORT ExchangeContext : public ReliableMessageContext, */ bool IsSendExpected() const { return mFlags.Has(Flags::kFlagWillSendMessage); } + /** + * Tracks whether we have received at least one application level message + * during the life-time of this exchange + * + * @return Returns 'true' if we have received at least one message, else 'false' + */ + inline bool HasReceivedAtLeastOneMessage() { return mFlags.Has(Flags::kFlagReceivedAtLeastOneMessage); } + #if CONFIG_BUILD_FOR_HOST_UNIT_TEST SessionHolder & GetSessionHolder() { return mSession; } @@ -292,42 +300,19 @@ 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 // evict it when the exchange is done with all its work (including any MRP traffic). - inline void SetIgnoreSessionRelease(bool ignore); - inline bool ShouldIgnoreSessionRelease(); -}; + inline void SetIgnoreSessionRelease(bool ignore) { mFlags.Set(Flags::kFlagIgnoreSessionRelease, ignore); } -inline void ExchangeContext::SetIgnoreSessionRelease(bool ignore) -{ - mFlags.Set(Flags::kFlagIgnoreSessionRelease, ignore); -} + inline bool ShouldIgnoreSessionRelease() { return mFlags.Has(Flags::kFlagIgnoreSessionRelease); } -inline bool ExchangeContext::ShouldIgnoreSessionRelease() -{ - return mFlags.Has(Flags::kFlagIgnoreSessionRelease); -} + inline void SetHasReceivedAtLeastOneMessage(bool hasReceivedMessage) + { + mFlags.Set(Flags::kFlagReceivedAtLeastOneMessage, hasReceivedMessage); + } +}; } // namespace Messaging } // namespace chip diff --git a/src/messaging/ReliableMessageContext.cpp b/src/messaging/ReliableMessageContext.cpp index ece92063ffff69..30f00a67814a25 100644 --- a/src/messaging/ReliableMessageContext.cpp +++ b/src/messaging/ReliableMessageContext.cpp @@ -107,7 +107,6 @@ void ReliableMessageContext::HandleRcvdAck(uint32_t ackMessageCounter) } CHIP_ERROR ReliableMessageContext::HandleNeedsAck(uint32_t messageCounter, BitFlags messageFlags) - { CHIP_ERROR err = HandleNeedsAckInner(messageCounter, messageFlags); diff --git a/src/messaging/ReliableMessageContext.h b/src/messaging/ReliableMessageContext.h index 7fb90bfcd54c36..7e8f725cbed15b 100644 --- a/src/messaging/ReliableMessageContext.h +++ b/src/messaging/ReliableMessageContext.h @@ -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; @@ -169,14 +166,17 @@ 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), + + // This flag is used to determine if the peer (receiver) should be considered active or not. + // When set, sender knows it has received at least one application-level message + // from the peer and can assume the peer (receiver) is active. + // If the flag is not set, we don't know if the peer (receiver) is active or not. + kFlagReceivedAtLeastOneMessage = (1u << 10), /// When set: /// @@ -238,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); @@ -253,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); diff --git a/src/messaging/ReliableMessageMgr.cpp b/src/messaging/ReliableMessageMgr.cpp index f0ee9f380092fe..e22bd4db24a517 100644 --- a/src/messaging/ReliableMessageMgr.cpp +++ b/src/messaging/ReliableMessageMgr.cpp @@ -168,10 +168,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; @@ -272,10 +269,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(); } @@ -456,6 +450,27 @@ 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); + + // Check if we have received at least one application-level message + if (entry.ec->HasReceivedAtLeastOneMessage()) + { + // If we have received at least one message, assume peer is active and use ActiveRetransTimeout + baseTimeout = entry.ec->GetSessionHandle()->GetRemoteMRPConfig().mActiveRetransTimeout; + } + else + { + // If we haven't received at least one message + // 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() { diff --git a/src/messaging/ReliableMessageMgr.h b/src/messaging/ReliableMessageMgr.h index ea31e46f4df066..934094c83d4259 100644 --- a/src/messaging/ReliableMessageMgr.h +++ b/src/messaging/ReliableMessageMgr.h @@ -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 & mContextPool; chip::System::Layer * mSystemLayer; diff --git a/src/messaging/tests/TestReliableMessageProtocol.cpp b/src/messaging/tests/TestReliableMessageProtocol.cpp index c8b318e3bd6c30..325f27c782832c 100644 --- a/src/messaging/tests/TestReliableMessageProtocol.cpp +++ b/src/messaging/tests/TestReliableMessageProtocol.cpp @@ -296,7 +296,36 @@ struct BackoffComplianceTestVector theBackoffComplianceTestVector[] = { }, }; -void CheckAddClearRetrans(nlTestSuite * inSuite, void * inContext) +} // namespace + +class TestReliableMessageProtocol +{ +public: + static void CheckAddClearRetrans(nlTestSuite * inSuite, void * inContext); + static void CheckResendApplicationMessage(nlTestSuite * inSuite, void * inContext); + static void CheckCloseExchangeAndResendApplicationMessage(nlTestSuite * inSuite, void * inContext); + static void CheckFailedMessageRetainOnSend(nlTestSuite * inSuite, void * inContext); + static void CheckResendApplicationMessageWithPeerExchange(nlTestSuite * inSuite, void * inContext); + static void CheckResendSessionEstablishmentMessageWithPeerExchange(nlTestSuite * inSuite, void * inContext); + static void CheckDuplicateMessage(nlTestSuite * inSuite, void * inContext); + static void CheckDuplicateMessageClosedExchange(nlTestSuite * inSuite, void * inContext); + static void CheckDuplicateOldMessageClosedExchange(nlTestSuite * inSuite, void * inContext); + static void CheckReceiveAfterStandaloneAck(nlTestSuite * inSuite, void * inContext); + static void CheckPiggybackAfterPiggyback(nlTestSuite * inSuite, void * inContext); + static void CheckSendUnsolicitedStandaloneAckMessage(nlTestSuite * inSuite, void * inContext); + static void CheckSendStandaloneAckMessage(nlTestSuite * inSuite, void * inContext); + static void CheckMessageAfterClosed(nlTestSuite * inSuite, void * inContext); + static void CheckUnencryptedMessageReceiveFailure(nlTestSuite * inSuite, void * inContext); + static void CheckLostResponseWithPiggyback(nlTestSuite * inSuite, void * inContext); + static void CheckLostStandaloneAck(nlTestSuite * inSuite, void * inContext); + static void CheckIsPeerActiveNotInitiator(nlTestSuite * inSuite, void * inContext); + static void CheckGetBackoff(nlTestSuite * inSuite, void * inContext); + static void CheckApplicationResponseDelayed(nlTestSuite * inSuite, void * inContext); + static void CheckApplicationResponseNeverComes(nlTestSuite * inSuite, void * inContext); + static int InitializeTestCase(void * inContext); +}; + +void TestReliableMessageProtocol::CheckAddClearRetrans(nlTestSuite * inSuite, void * inContext) { TestContext & ctx = *reinterpret_cast(inContext); @@ -345,7 +374,7 @@ void CheckAddClearRetrans(nlTestSuite * inSuite, void * inContext) * - PEER to acknowledge message * - Observe DUT signal successful reliable transmission */ -void CheckResendApplicationMessage(nlTestSuite * inSuite, void * inContext) +void TestReliableMessageProtocol::CheckResendApplicationMessage(nlTestSuite * inSuite, void * inContext) { TestContext & ctx = *reinterpret_cast(inContext); BackoffComplianceTestVector * expectedBackoff; @@ -462,7 +491,7 @@ void CheckResendApplicationMessage(nlTestSuite * inSuite, void * inContext) exchange->Close(); } -void CheckCloseExchangeAndResendApplicationMessage(nlTestSuite * inSuite, void * inContext) +void TestReliableMessageProtocol::CheckCloseExchangeAndResendApplicationMessage(nlTestSuite * inSuite, void * inContext) { TestContext & ctx = *reinterpret_cast(inContext); @@ -522,7 +551,7 @@ void CheckCloseExchangeAndResendApplicationMessage(nlTestSuite * inSuite, void * NL_TEST_ASSERT(inSuite, rm->TestGetCountRetransTable() == 0); } -void CheckFailedMessageRetainOnSend(nlTestSuite * inSuite, void * inContext) +void TestReliableMessageProtocol::CheckFailedMessageRetainOnSend(nlTestSuite * inSuite, void * inContext) { TestContext & ctx = *reinterpret_cast(inContext); @@ -567,7 +596,7 @@ void CheckFailedMessageRetainOnSend(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, rm->TestGetCountRetransTable() == 0); } -void CheckUnencryptedMessageReceiveFailure(nlTestSuite * inSuite, void * inContext) +void TestReliableMessageProtocol::CheckUnencryptedMessageReceiveFailure(nlTestSuite * inSuite, void * inContext) { TestContext & ctx = *reinterpret_cast(inContext); @@ -606,7 +635,7 @@ void CheckUnencryptedMessageReceiveFailure(nlTestSuite * inSuite, void * inConte NL_TEST_ASSERT(inSuite, rm->TestGetCountRetransTable() == 0); } -void CheckResendApplicationMessageWithPeerExchange(nlTestSuite * inSuite, void * inContext) +void TestReliableMessageProtocol::CheckResendApplicationMessageWithPeerExchange(nlTestSuite * inSuite, void * inContext) { TestContext & ctx = *reinterpret_cast(inContext); @@ -668,7 +697,7 @@ void CheckResendApplicationMessageWithPeerExchange(nlTestSuite * inSuite, void * NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); } -void CheckDuplicateMessageClosedExchange(nlTestSuite * inSuite, void * inContext) +void TestReliableMessageProtocol::CheckDuplicateMessageClosedExchange(nlTestSuite * inSuite, void * inContext) { TestContext & ctx = *reinterpret_cast(inContext); @@ -735,7 +764,7 @@ void CheckDuplicateMessageClosedExchange(nlTestSuite * inSuite, void * inContext NL_TEST_ASSERT(inSuite, rm->TestGetCountRetransTable() == 0); } -void CheckDuplicateOldMessageClosedExchange(nlTestSuite * inSuite, void * inContext) +void TestReliableMessageProtocol::CheckDuplicateOldMessageClosedExchange(nlTestSuite * inSuite, void * inContext) { TestContext & ctx = *reinterpret_cast(inContext); @@ -832,7 +861,7 @@ void CheckDuplicateOldMessageClosedExchange(nlTestSuite * inSuite, void * inCont NL_TEST_ASSERT(inSuite, rm->TestGetCountRetransTable() == 0); } -void CheckResendSessionEstablishmentMessageWithPeerExchange(nlTestSuite * inSuite, void * inContext) +void TestReliableMessageProtocol::CheckResendSessionEstablishmentMessageWithPeerExchange(nlTestSuite * inSuite, void * inContext) { // Making this static to reduce stack usage, as some platforms have limits on stack size. static Test::MessagingContext ctx; @@ -900,7 +929,7 @@ void CheckResendSessionEstablishmentMessageWithPeerExchange(nlTestSuite * inSuit ctx.ShutdownAndRestoreExisting(inctx); } -void CheckDuplicateMessage(nlTestSuite * inSuite, void * inContext) +void TestReliableMessageProtocol::CheckDuplicateMessage(nlTestSuite * inSuite, void * inContext) { TestContext & ctx = *reinterpret_cast(inContext); @@ -970,7 +999,7 @@ void CheckDuplicateMessage(nlTestSuite * inSuite, void * inContext) mockReceiver.CloseExchangeIfNeeded(); } -void CheckReceiveAfterStandaloneAck(nlTestSuite * inSuite, void * inContext) +void TestReliableMessageProtocol::CheckReceiveAfterStandaloneAck(nlTestSuite * inSuite, void * inContext) { TestContext & ctx = *reinterpret_cast(inContext); @@ -1060,7 +1089,7 @@ void CheckReceiveAfterStandaloneAck(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, rm->TestGetCountRetransTable() == 0); } -void CheckPiggybackAfterPiggyback(nlTestSuite * inSuite, void * inContext) +void TestReliableMessageProtocol::CheckPiggybackAfterPiggyback(nlTestSuite * inSuite, void * inContext) { TestContext & ctx = *reinterpret_cast(inContext); @@ -1191,7 +1220,7 @@ void CheckPiggybackAfterPiggyback(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, rm->TestGetCountRetransTable() == 0); } -void CheckSendUnsolicitedStandaloneAckMessage(nlTestSuite * inSuite, void * inContext) +void TestReliableMessageProtocol::CheckSendUnsolicitedStandaloneAckMessage(nlTestSuite * inSuite, void * inContext) { /** * Tests sending a standalone ack message that is: @@ -1242,7 +1271,7 @@ void CheckSendUnsolicitedStandaloneAckMessage(nlTestSuite * inSuite, void * inCo NL_TEST_ASSERT(inSuite, rm->TestGetCountRetransTable() == 0); } -void CheckSendStandaloneAckMessage(nlTestSuite * inSuite, void * inContext) +void TestReliableMessageProtocol::CheckSendStandaloneAckMessage(nlTestSuite * inSuite, void * inContext) { TestContext & ctx = *reinterpret_cast(inContext); @@ -1262,7 +1291,7 @@ void CheckSendStandaloneAckMessage(nlTestSuite * inSuite, void * inContext) exchange->Close(); } -void CheckMessageAfterClosed(nlTestSuite * inSuite, void * inContext) +void TestReliableMessageProtocol::CheckMessageAfterClosed(nlTestSuite * inSuite, void * inContext) { /** * This test performs the following sequence of actions, where all messages @@ -1387,7 +1416,7 @@ void CheckMessageAfterClosed(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, rm->TestGetCountRetransTable() == 0); } -void CheckLostResponseWithPiggyback(nlTestSuite * inSuite, void * inContext) +void TestReliableMessageProtocol::CheckLostResponseWithPiggyback(nlTestSuite * inSuite, void * inContext) { /** * This tests the following scenario: @@ -1541,7 +1570,125 @@ void CheckLostResponseWithPiggyback(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, rm->TestGetCountRetransTable() == 0); } -void CheckLostStandaloneAck(nlTestSuite * inSuite, void * inContext) +void TestReliableMessageProtocol::CheckIsPeerActiveNotInitiator(nlTestSuite * inSuite, void * inContext) +{ + /** + * This tests the following scenario: + * 1) A reliable message expecting a response is sent from the initiator to responder which is lost + * 2) Initiator resends the message at the IdleRetrans interval + * 3) Responder receives the message and sends a standalone ack + * 4) Responder sends a response and fails + * 5) Responder retries at the ActiveRestrans interval + * 6) Initiator receives the response + */ + + TestContext & ctx = *reinterpret_cast(inContext); + + chip::System::PacketBufferHandle buffer = chip::MessagePacketBuffer::NewWithData(PAYLOAD, sizeof(PAYLOAD)); + NL_TEST_ASSERT(inSuite, !buffer.IsNull()); + + CHIP_ERROR err = CHIP_NO_ERROR; + + MockAppDelegate mockReceiver(ctx); + err = ctx.GetExchangeManager().RegisterUnsolicitedMessageHandlerForType(Echo::MsgType::EchoRequest, &mockReceiver); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + + mockReceiver.mTestSuite = inSuite; + + MockAppDelegate mockSender(ctx); + ExchangeContext * exchange = ctx.NewExchangeToAlice(&mockSender); + NL_TEST_ASSERT(inSuite, exchange != nullptr); + + mockSender.mTestSuite = inSuite; + + exchange->GetSessionHandle()->AsSecureSession()->SetRemoteMRPConfig({ + 1000_ms32, // CHIP_CONFIG_MRP_LOCAL_IDLE_RETRY_INTERVAL + 1000_ms32, // CHIP_CONFIG_MRP_LOCAL_ACTIVE_RETRY_INTERVAL + }); + + ReliableMessageMgr * rm = ctx.GetExchangeManager().GetReliableMessageMgr(); + NL_TEST_ASSERT(inSuite, rm != nullptr); + + // Ensure the retransmit table is empty right now + NL_TEST_ASSERT(inSuite, rm->TestGetCountRetransTable() == 0); + + auto & loopback = ctx.GetLoopback(); + loopback.mSentMessageCount = 0; + loopback.mNumMessagesToDrop = 1; + loopback.mDroppedMessageCount = 0; + + mockReceiver.mRetainExchange = true; + mockSender.mRetainExchange = true; + + NL_TEST_ASSERT(inSuite, !exchange->HasReceivedAtLeastOneMessage()); + + err = exchange->SendMessage(Echo::MsgType::EchoRequest, std::move(buffer), SendFlags(SendMessageFlags::kExpectResponse)); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + ctx.DrainAndServiceIO(); + + // Verify that the first message is dropped + NL_TEST_ASSERT(inSuite, loopback.mDroppedMessageCount == 1); + NL_TEST_ASSERT(inSuite, loopback.mSentMessageCount == 1); + NL_TEST_ASSERT(inSuite, loopback.mNumMessagesToDrop == 0); + + // Make sure retransmit was not done before the idle restrans interval hits + ctx.GetIOContext().DriveIOUntil(500_ms32, [&] { return loopback.mSentMessageCount >= 1; }); + ctx.DrainAndServiceIO(); + + NL_TEST_ASSERT(inSuite, !exchange->HasReceivedAtLeastOneMessage()); + + // // Make sure nothing happened + NL_TEST_ASSERT(inSuite, loopback.mSentMessageCount == 1); + NL_TEST_ASSERT(inSuite, !mockReceiver.IsOnMessageReceivedCalled); + + // // Retrasnmit message + ctx.GetIOContext().DriveIOUntil(2000_ms32, [&] { return loopback.mSentMessageCount >= 2; }); + ctx.DrainAndServiceIO(); + + NL_TEST_ASSERT(inSuite, !exchange->HasReceivedAtLeastOneMessage()); + + // // Make sure nothing happened + NL_TEST_ASSERT(inSuite, loopback.mSentMessageCount == 2); + NL_TEST_ASSERT(inSuite, mockReceiver.IsOnMessageReceivedCalled); + + // // Verify that the receiver considers the sender is active + NL_TEST_ASSERT(inSuite, !exchange->HasReceivedAtLeastOneMessage()); + NL_TEST_ASSERT(inSuite, mockReceiver.mExchange->HasReceivedAtLeastOneMessage()); + + mockReceiver.mExchange->GetSessionHandle()->AsSecureSession()->SetRemoteMRPConfig({ + 1000_ms32, // CHIP_CONFIG_MRP_LOCAL_IDLE_RETRY_INTERVAL + 100_ms32, // CHIP_CONFIG_MRP_LOCAL_ACTIVE_RETRY_INTERVAL + }); + + mockReceiver.mRetainExchange = false; + mockSender.mRetainExchange = false; + + // Now send a message from the other side. + buffer = chip::MessagePacketBuffer::NewWithData(PAYLOAD, sizeof(PAYLOAD)); + NL_TEST_ASSERT(inSuite, !buffer.IsNull()); + + // Make receiver message fail once + loopback.mNumMessagesToDrop = 1; + + err = mockReceiver.mExchange->SendMessage(Echo::MsgType::EchoResponse, std::move(buffer)); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + ctx.DrainAndServiceIO(); + + // Make sure nothing happened + NL_TEST_ASSERT(inSuite, loopback.mDroppedMessageCount == 2); + NL_TEST_ASSERT(inSuite, loopback.mNumMessagesToDrop == 0); + NL_TEST_ASSERT(inSuite, loopback.mSentMessageCount == 3); + NL_TEST_ASSERT(inSuite, !mockSender.IsOnMessageReceivedCalled); + + // // Retrasnmit message + ctx.GetIOContext().DriveIOUntil(150_ms32, [&] { return loopback.mSentMessageCount >= 4; }); + ctx.DrainAndServiceIO(); + + NL_TEST_ASSERT(inSuite, mockSender.IsOnMessageReceivedCalled); + NL_TEST_ASSERT(inSuite, loopback.mSentMessageCount == 5); +} + +void TestReliableMessageProtocol::CheckLostStandaloneAck(nlTestSuite * inSuite, void * inContext) { /** * This tests the following scenario: @@ -1669,7 +1816,7 @@ void CheckLostStandaloneAck(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, rm->TestGetCountRetransTable() == 0); } -void CheckGetBackoff(nlTestSuite * inSuite, void * inContext) +void TestReliableMessageProtocol::CheckGetBackoff(nlTestSuite * inSuite, void * inContext) { // Run 3x iterations to thoroughly test random jitter always results in backoff within bounds. for (uint32_t j = 0; j < 3; j++) @@ -1686,7 +1833,7 @@ void CheckGetBackoff(nlTestSuite * inSuite, void * inContext) } } -void CheckApplicationResponseDelayed(nlTestSuite * inSuite, void * inContext) +void TestReliableMessageProtocol::CheckApplicationResponseDelayed(nlTestSuite * inSuite, void * inContext) { TestContext & ctx = *reinterpret_cast(inContext); @@ -1849,7 +1996,7 @@ void CheckApplicationResponseDelayed(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); } -void CheckApplicationResponseNeverComes(nlTestSuite * inSuite, void * inContext) +void TestReliableMessageProtocol::CheckApplicationResponseNeverComes(nlTestSuite * inSuite, void * inContext) { TestContext & ctx = *reinterpret_cast(inContext); @@ -1977,7 +2124,7 @@ void CheckApplicationResponseNeverComes(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); } -int InitializeTestCase(void * inContext) +int TestReliableMessageProtocol::InitializeTestCase(void * inContext) { TestContext & ctx = *static_cast(inContext); ctx.GetSessionAliceToBob()->AsSecureSession()->SetRemoteMRPConfig(GetLocalMRPConfig().ValueOr(GetDefaultMRPConfig())); @@ -2001,34 +2148,44 @@ int InitializeTestCase(void * inContext) */ const nlTest sTests[] = { - NL_TEST_DEF("Test ReliableMessageMgr::CheckAddClearRetrans", CheckAddClearRetrans), - NL_TEST_DEF("Test ReliableMessageMgr::CheckResendApplicationMessage", CheckResendApplicationMessage), + NL_TEST_DEF("Test ReliableMessageMgr::CheckAddClearRetrans", TestReliableMessageProtocol::CheckAddClearRetrans), + NL_TEST_DEF("Test ReliableMessageMgr::CheckResendApplicationMessage", + TestReliableMessageProtocol::CheckResendApplicationMessage), NL_TEST_DEF("Test ReliableMessageMgr::CheckCloseExchangeAndResendApplicationMessage", - CheckCloseExchangeAndResendApplicationMessage), - NL_TEST_DEF("Test ReliableMessageMgr::CheckFailedMessageRetainOnSend", CheckFailedMessageRetainOnSend), + TestReliableMessageProtocol::CheckCloseExchangeAndResendApplicationMessage), + NL_TEST_DEF("Test ReliableMessageMgr::CheckFailedMessageRetainOnSend", + TestReliableMessageProtocol::CheckFailedMessageRetainOnSend), NL_TEST_DEF("Test ReliableMessageMgr::CheckResendApplicationMessageWithPeerExchange", - CheckResendApplicationMessageWithPeerExchange), + TestReliableMessageProtocol::CheckResendApplicationMessageWithPeerExchange), NL_TEST_DEF("Test ReliableMessageMgr::CheckResendSessionEstablishmentMessageWithPeerExchange", - CheckResendSessionEstablishmentMessageWithPeerExchange), - NL_TEST_DEF("Test ReliableMessageMgr::CheckDuplicateMessage", CheckDuplicateMessage), - NL_TEST_DEF("Test ReliableMessageMgr::CheckDuplicateMessageClosedExchange", CheckDuplicateMessageClosedExchange), - NL_TEST_DEF("Test ReliableMessageMgr::CheckDuplicateOldMessageClosedExchange", CheckDuplicateOldMessageClosedExchange), - NL_TEST_DEF("Test that a reply after a standalone ack comes through correctly", CheckReceiveAfterStandaloneAck), + TestReliableMessageProtocol::CheckResendSessionEstablishmentMessageWithPeerExchange), + NL_TEST_DEF("Test ReliableMessageMgr::CheckDuplicateMessage", TestReliableMessageProtocol::CheckDuplicateMessage), + NL_TEST_DEF("Test ReliableMessageMgr::CheckDuplicateMessageClosedExchange", + TestReliableMessageProtocol::CheckDuplicateMessageClosedExchange), + NL_TEST_DEF("Test ReliableMessageMgr::CheckDuplicateOldMessageClosedExchange", + TestReliableMessageProtocol::CheckDuplicateOldMessageClosedExchange), + NL_TEST_DEF("Test that a reply after a standalone ack comes through correctly", + TestReliableMessageProtocol::CheckReceiveAfterStandaloneAck), NL_TEST_DEF("Test that a reply to a non-MRP message piggybacks an ack if there were MRP things happening on the context before", - CheckPiggybackAfterPiggyback), - NL_TEST_DEF("Test sending an unsolicited ack-soliciting 'standalone ack' message", CheckSendUnsolicitedStandaloneAckMessage), - NL_TEST_DEF("Test ReliableMessageMgr::CheckSendStandaloneAckMessage", CheckSendStandaloneAckMessage), + TestReliableMessageProtocol::CheckPiggybackAfterPiggyback), + NL_TEST_DEF("Test sending an unsolicited ack-soliciting 'standalone ack' message", + TestReliableMessageProtocol::CheckSendUnsolicitedStandaloneAckMessage), + NL_TEST_DEF("Test ReliableMessageMgr::CheckSendStandaloneAckMessage", + TestReliableMessageProtocol::CheckSendStandaloneAckMessage), NL_TEST_DEF("Test command, response, default response, with receiver closing exchange after sending response", - CheckMessageAfterClosed), - NL_TEST_DEF("Test that unencrypted message is dropped if exchange requires encryption", CheckUnencryptedMessageReceiveFailure), + TestReliableMessageProtocol::CheckMessageAfterClosed), + NL_TEST_DEF("Test that unencrypted message is dropped if exchange requires encryption", + TestReliableMessageProtocol::CheckUnencryptedMessageReceiveFailure), NL_TEST_DEF("Test that dropping an application-level message with a piggyback ack works ok once both sides retransmit", - CheckLostResponseWithPiggyback), + TestReliableMessageProtocol::CheckLostResponseWithPiggyback), NL_TEST_DEF("Test that an application-level response-to-response after a lost standalone ack to the initial message works", - CheckLostStandaloneAck), - NL_TEST_DEF("Test MRP backoff algorithm", CheckGetBackoff), - NL_TEST_DEF("Test an application response that comes after MRP retransmits run out", CheckApplicationResponseDelayed), + TestReliableMessageProtocol::CheckLostStandaloneAck), + NL_TEST_DEF("Test Is Peer Active Retry logic", TestReliableMessageProtocol::CheckIsPeerActiveNotInitiator), + NL_TEST_DEF("Test MRP backoff algorithm", TestReliableMessageProtocol::CheckGetBackoff), + NL_TEST_DEF("Test an application response that comes after MRP retransmits run out", + TestReliableMessageProtocol::CheckApplicationResponseDelayed), NL_TEST_DEF("Test an application response that never comes, so MRP retransmits run out and then exchange times out", - CheckApplicationResponseNeverComes), + TestReliableMessageProtocol::CheckApplicationResponseNeverComes), NL_TEST_SENTINEL(), }; @@ -2038,15 +2195,13 @@ nlTestSuite sSuite = { &sTests[0], TestContext::Initialize, TestContext::Finalize, - InitializeTestCase, + TestReliableMessageProtocol::InitializeTestCase, }; // clang-format on -} // namespace - -int TestReliableMessageProtocol() +int TestReliableMessageProtocolSuite() { return chip::ExecuteTestsWithContext(&sSuite); } -CHIP_REGISTER_TEST_SUITE(TestReliableMessageProtocol) +CHIP_REGISTER_TEST_SUITE(TestReliableMessageProtocolSuite)