From 15465809cfe2da69db97b2ff6d0573ad9e02410f Mon Sep 17 00:00:00 2001 From: "Irene Siu (Apple)" Date: Mon, 18 Apr 2022 09:40:02 -0700 Subject: [PATCH] Revert PR 16743 (#17427) * Revert "Issue #12520 Remove BDX timeout tracking from TransferSession" This reverts commit b3528c5f8f3bff7f199a0280a63676b5ee19cdab. * Revert "- Removed timeout from TransferSession::StartTransfer() and TransferSession::WaitForTransfer()" This reverts commit 7a4061a5b14b6e1f5260cb6ae4a3ab8e0c11a971. --- .../clusters/ota-requestor/BDXDownloader.cpp | 9 +- src/protocols/bdx/BdxTransferSession.cpp | 37 +++++++-- src/protocols/bdx/BdxTransferSession.h | 20 +++-- src/protocols/bdx/TransferFacilitator.cpp | 9 +- .../bdx/tests/TestBdxTransferSession.cpp | 83 ++++++++++++++----- 5 files changed, 119 insertions(+), 39 deletions(-) diff --git a/src/app/clusters/ota-requestor/BDXDownloader.cpp b/src/app/clusters/ota-requestor/BDXDownloader.cpp index 90f1ecd8e9255c..8c1edbf8765040 100644 --- a/src/app/clusters/ota-requestor/BDXDownloader.cpp +++ b/src/app/clusters/ota-requestor/BDXDownloader.cpp @@ -25,6 +25,7 @@ #include #include #include +#include /* TODO:(#12520) remove */ #include #include @@ -80,7 +81,8 @@ bool BDXDownloader::HasTransferTimedOut() void BDXDownloader::OnMessageReceived(const chip::PayloadHeader & payloadHeader, chip::System::PacketBufferHandle msg) { VerifyOrReturn(mState == State::kInProgress, ChipLogError(BDX, "Can't accept messages, no transfer in progress")); - CHIP_ERROR err = mBdxTransfer.HandleMessageReceived(payloadHeader, std::move(msg)); + CHIP_ERROR err = + mBdxTransfer.HandleMessageReceived(payloadHeader, std::move(msg), /* TODO:(#12520) */ chip::System::Clock::Seconds16(0)); if (err != CHIP_NO_ERROR) { ChipLogError(BDX, "unable to handle message: %" CHIP_ERROR_FORMAT, err.Format()); @@ -102,7 +104,8 @@ CHIP_ERROR BDXDownloader::SetBDXParams(const chip::bdx::TransferSession::Transfe // Must call StartTransfer() here to store the the pointer data contained in bdxInitData in the TransferSession object. // Otherwise it could be freed before we can use it. - ReturnErrorOnFailure(mBdxTransfer.StartTransfer(chip::bdx::TransferRole::kReceiver, bdxInitData)); + ReturnErrorOnFailure(mBdxTransfer.StartTransfer(chip::bdx::TransferRole::kReceiver, bdxInitData, + /* TODO:(#12520) */ chip::System::Clock::Seconds16(30))); return CHIP_NO_ERROR; } @@ -217,7 +220,7 @@ void BDXDownloader::PollTransferSession() // allow that? do { - mBdxTransfer.PollOutput(outEvent); + mBdxTransfer.PollOutput(outEvent, /* TODO:(#12520) */ chip::System::Clock::Seconds16(0)); CHIP_ERROR err = HandleBdxEvent(outEvent); VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(BDX, "HandleBDXEvent: %" CHIP_ERROR_FORMAT, err.Format())); } while (outEvent.EventType != TransferSession::OutputEventType::kNone); diff --git a/src/protocols/bdx/BdxTransferSession.cpp b/src/protocols/bdx/BdxTransferSession.cpp index 47121bf2887ce0..945381e2fefa2c 100644 --- a/src/protocols/bdx/BdxTransferSession.cpp +++ b/src/protocols/bdx/BdxTransferSession.cpp @@ -64,10 +64,24 @@ TransferSession::TransferSession() mSuppportedXferOpts.ClearAll(); } -void TransferSession::PollOutput(OutputEvent & event) +void TransferSession::PollOutput(OutputEvent & event, System::Clock::Timestamp curTime) { event = OutputEvent(OutputEventType::kNone); + if (mShouldInitTimeoutStart) + { + mTimeoutStartTime = curTime; + mShouldInitTimeoutStart = false; + } + + if (mAwaitingResponse && ((curTime - mTimeoutStartTime) >= mTimeout)) + { + event = OutputEvent(OutputEventType::kTransferTimeout); + mState = TransferState::kErrorState; + mAwaitingResponse = false; + return; + } + switch (mPendingOutput) { case OutputEventType::kNone: @@ -80,7 +94,8 @@ void TransferSession::PollOutput(OutputEvent & event) event = OutputEvent::StatusReportEvent(OutputEventType::kStatusReceived, mStatusReportData); break; case OutputEventType::kMsgToSend: - event = OutputEvent::MsgToSendEvent(mMsgTypeData, std::move(mPendingMsgHandle)); + event = OutputEvent::MsgToSendEvent(mMsgTypeData, std::move(mPendingMsgHandle)); + mTimeoutStartTime = curTime; break; case OutputEventType::kInitReceived: event = OutputEvent::TransferInitEvent(mTransferRequestData, std::move(mPendingMsgHandle)); @@ -119,11 +134,12 @@ void TransferSession::PollOutput(OutputEvent & event) mPendingOutput = OutputEventType::kNone; } -CHIP_ERROR TransferSession::StartTransfer(TransferRole role, const TransferInitData & initData) +CHIP_ERROR TransferSession::StartTransfer(TransferRole role, const TransferInitData & initData, System::Clock::Timeout timeout) { VerifyOrReturnError(mState == TransferState::kUnitialized, CHIP_ERROR_INCORRECT_STATE); - mRole = role; + mRole = role; + mTimeout = timeout; // Set transfer parameters. They may be overridden later by an Accept message mSuppportedXferOpts = initData.TransferCtlFlags; @@ -161,12 +177,13 @@ CHIP_ERROR TransferSession::StartTransfer(TransferRole role, const TransferInitD } CHIP_ERROR TransferSession::WaitForTransfer(TransferRole role, BitFlags xferControlOpts, - uint16_t maxBlockSize) + uint16_t maxBlockSize, System::Clock::Timeout timeout) { VerifyOrReturnError(mState == TransferState::kUnitialized, CHIP_ERROR_INCORRECT_STATE); // Used to determine compatibility with any future TransferInit parameters mRole = role; + mTimeout = timeout; mSuppportedXferOpts = xferControlOpts; mMaxSupportedBlockSize = maxBlockSize; @@ -405,16 +422,22 @@ void TransferSession::Reset() mLastQueryNum = 0; mNextQueryNum = 0; - mAwaitingResponse = false; + mTimeout = System::Clock::kZero; + mTimeoutStartTime = System::Clock::kZero; + mShouldInitTimeoutStart = true; + mAwaitingResponse = false; } -CHIP_ERROR TransferSession::HandleMessageReceived(const PayloadHeader & payloadHeader, System::PacketBufferHandle msg) +CHIP_ERROR TransferSession::HandleMessageReceived(const PayloadHeader & payloadHeader, System::PacketBufferHandle msg, + System::Clock::Timestamp curTime) { VerifyOrReturnError(!msg.IsNull(), CHIP_ERROR_INVALID_ARGUMENT); if (payloadHeader.HasProtocol(Protocols::BDX::Id)) { ReturnErrorOnFailure(HandleBdxMessage(payloadHeader, std::move(msg))); + + mTimeoutStartTime = curTime; } else if (payloadHeader.HasMessageType(Protocols::SecureChannel::MsgType::StatusReport)) { diff --git a/src/protocols/bdx/BdxTransferSession.h b/src/protocols/bdx/BdxTransferSession.h index d39ad5011d9f2f..7696d0473c9dc8 100644 --- a/src/protocols/bdx/BdxTransferSession.h +++ b/src/protocols/bdx/BdxTransferSession.h @@ -160,8 +160,9 @@ class DLL_EXPORT TransferSession * See OutputEventType for all possible output event types. * * @param event Reference to an OutputEvent struct that will be filled out with any pending output data + * @param curTime Current time */ - void PollOutput(OutputEvent & event); + void PollOutput(OutputEvent & event, System::Clock::Timestamp curTime); /** * @brief @@ -172,11 +173,13 @@ class DLL_EXPORT TransferSession * @param role Inidcates whether this object will be sending or receiving data * @param initData Data for initializing this object and for populating a TransferInit message * The role parameter will determine whether to populate a ReceiveInit or SendInit + * @param timeout The amount of time to wait for a response before considering the transfer failed + * @param curTime The current time since epoch. Needed to set a start time for the transfer timeout. * * @return CHIP_ERROR Result of initialization and preparation of a TransferInit message. May also indicate if the * TransferSession object is unable to handle this request. */ - CHIP_ERROR StartTransfer(TransferRole role, const TransferInitData & initData); + CHIP_ERROR StartTransfer(TransferRole role, const TransferInitData & initData, System::Clock::Timeout timeout); /** * @brief @@ -187,11 +190,13 @@ class DLL_EXPORT TransferSession * @param role Inidcates whether this object will be sending or receiving data * @param xferControlOpts Indicates all supported control modes. Used to respond to a TransferInit message * @param maxBlockSize The max Block size that this object supports. + * @param timeout The amount of time to wait for a response before considering the transfer failed * * @return CHIP_ERROR Result of initialization. May also indicate if the TransferSession object is unable to handle this * request. */ - CHIP_ERROR WaitForTransfer(TransferRole role, BitFlags xferControlOpts, uint16_t maxBlockSize); + CHIP_ERROR WaitForTransfer(TransferRole role, BitFlags xferControlOpts, uint16_t maxBlockSize, + System::Clock::Timeout timeout); /** * @brief @@ -280,11 +285,13 @@ class DLL_EXPORT TransferSession * @param payloadHeader A PayloadHeader containing the Protocol type and Message Type * @param msg A PacketBufferHandle pointing to the message buffer to process. May be BDX or StatusReport protocol. * Buffer is expected to start at data (not header). + * @param curTime Current time * * @return CHIP_ERROR Indicates any problems in decoding the message, or if the message is not of the BDX or StatusReport * protocols. */ - CHIP_ERROR HandleMessageReceived(const PayloadHeader & payloadHeader, System::PacketBufferHandle msg); + CHIP_ERROR HandleMessageReceived(const PayloadHeader & payloadHeader, System::PacketBufferHandle msg, + System::Clock::Timestamp curTime); TransferControlFlags GetControlMode() const { return mControlMode; } uint64_t GetStartOffset() const { return mStartOffset; } @@ -375,7 +382,10 @@ class DLL_EXPORT TransferSession uint32_t mLastQueryNum = 0; uint32_t mNextQueryNum = 0; - bool mAwaitingResponse = false; + System::Clock::Timeout mTimeout = System::Clock::kZero; + System::Clock::Timestamp mTimeoutStartTime = System::Clock::kZero; + bool mShouldInitTimeoutStart = true; + bool mAwaitingResponse = false; }; } // namespace bdx diff --git a/src/protocols/bdx/TransferFacilitator.cpp b/src/protocols/bdx/TransferFacilitator.cpp index 1100a400b314af..5a9ce8ef66b92f 100644 --- a/src/protocols/bdx/TransferFacilitator.cpp +++ b/src/protocols/bdx/TransferFacilitator.cpp @@ -42,7 +42,8 @@ CHIP_ERROR TransferFacilitator::OnMessageReceived(chip::Messaging::ExchangeConte ChipLogDetail(BDX, "%s: message " ChipLogFormatMessageType " protocol " ChipLogFormatProtocolId, __FUNCTION__, payloadHeader.GetMessageType(), ChipLogValueProtocolId(payloadHeader.GetProtocolID())); - CHIP_ERROR err = mTransfer.HandleMessageReceived(payloadHeader, std::move(payload)); + CHIP_ERROR err = + mTransfer.HandleMessageReceived(payloadHeader, std::move(payload), System::SystemClock().GetMonotonicTimestamp()); if (err != CHIP_NO_ERROR) { ChipLogError(BDX, "failed to handle message: %s", ErrorStr(err)); @@ -73,7 +74,7 @@ void TransferFacilitator::PollTimerHandler(chip::System::Layer * systemLayer, vo void TransferFacilitator::PollForOutput() { TransferSession::OutputEvent outEvent; - mTransfer.PollOutput(outEvent); + mTransfer.PollOutput(outEvent, System::SystemClock().GetMonotonicTimestamp()); HandleTransferSessionOutput(outEvent); VerifyOrReturn(mSystemLayer != nullptr, ChipLogError(BDX, "%s mSystemLayer is null", __FUNCTION__)); @@ -94,7 +95,7 @@ CHIP_ERROR Responder::PrepareForTransfer(System::Layer * layer, TransferRole rol mPollFreq = pollFreq; mSystemLayer = layer; - ReturnErrorOnFailure(mTransfer.WaitForTransfer(role, xferControlOpts, maxBlockSize)); + ReturnErrorOnFailure(mTransfer.WaitForTransfer(role, xferControlOpts, maxBlockSize, timeout)); mSystemLayer->StartTimer(mPollFreq, PollTimerHandler, this); return CHIP_NO_ERROR; @@ -108,7 +109,7 @@ CHIP_ERROR Initiator::InitiateTransfer(System::Layer * layer, TransferRole role, mPollFreq = pollFreq; mSystemLayer = layer; - ReturnErrorOnFailure(mTransfer.StartTransfer(role, initData)); + ReturnErrorOnFailure(mTransfer.StartTransfer(role, initData, timeout)); mSystemLayer->StartTimer(mPollFreq, PollTimerHandler, this); return CHIP_NO_ERROR; diff --git a/src/protocols/bdx/tests/TestBdxTransferSession.cpp b/src/protocols/bdx/tests/TestBdxTransferSession.cpp index fe3dbcc0c03efe..f18487e2373af2 100644 --- a/src/protocols/bdx/tests/TestBdxTransferSession.cpp +++ b/src/protocols/bdx/tests/TestBdxTransferSession.cpp @@ -20,6 +20,8 @@ using namespace ::chip::bdx; using namespace ::chip::Protocols; namespace { +// Use this as a timestamp if not needing to test BDX timeouts. +constexpr System::Clock::Timestamp kNoAdvanceTime = System::Clock::kZero; const TLV::Tag tlvStrTag = TLV::ContextTag(4); const TLV::Tag tlvListTag = TLV::ProfileTag(7777, 8888); @@ -84,7 +86,7 @@ CHIP_ERROR AttachHeaderAndSend(TransferSession::MessageTypeData typeData, chip:: chip::PayloadHeader payloadHeader; payloadHeader.SetMessageType(typeData.ProtocolId, typeData.MessageType); - ReturnErrorOnFailure(receiver.HandleMessageReceived(payloadHeader, std::move(msgBuf))); + ReturnErrorOnFailure(receiver.HandleMessageReceived(payloadHeader, std::move(msgBuf), kNoAdvanceTime)); return CHIP_NO_ERROR; } @@ -129,7 +131,7 @@ void VerifyStatusReport(nlTestSuite * inSuite, void * inContext, const System::P void VerifyNoMoreOutput(nlTestSuite * inSuite, void * inContext, TransferSession & transferSession) { TransferSession::OutputEvent event; - transferSession.PollOutput(event); + transferSession.PollOutput(event, kNoAdvanceTime); NL_TEST_ASSERT(inSuite, event.EventType == TransferSession::OutputEventType::kNone); } @@ -145,14 +147,14 @@ void SendAndVerifyTransferInit(nlTestSuite * inSuite, void * inContext, Transfer MessageType expectedInitMsg = (initiatorRole == TransferRole::kSender) ? MessageType::SendInit : MessageType::ReceiveInit; // Initializer responder to wait for transfer - err = responder.WaitForTransfer(responderRole, responderControlOpts, responderMaxBlock); + err = responder.WaitForTransfer(responderRole, responderControlOpts, responderMaxBlock, timeout); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); VerifyNoMoreOutput(inSuite, inContext, responder); // Verify initiator outputs respective Init message (depending on role) after StartTransfer() - err = initiator.StartTransfer(initiatorRole, initData); + err = initiator.StartTransfer(initiatorRole, initData, timeout); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); - initiator.PollOutput(outEvent); + initiator.PollOutput(outEvent, kNoAdvanceTime); NL_TEST_ASSERT(inSuite, outEvent.EventType == TransferSession::OutputEventType::kMsgToSend); VerifyBdxMessageToSend(inSuite, inContext, outEvent, expectedInitMsg); VerifyNoMoreOutput(inSuite, inContext, initiator); @@ -160,7 +162,7 @@ void SendAndVerifyTransferInit(nlTestSuite * inSuite, void * inContext, Transfer // Verify that all parsed TransferInit fields match what was sent by the initiator err = AttachHeaderAndSend(outEvent.msgTypeData, std::move(outEvent.MsgData), responder); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); - responder.PollOutput(outEvent); + responder.PollOutput(outEvent, kNoAdvanceTime); VerifyNoMoreOutput(inSuite, inContext, responder); NL_TEST_ASSERT(inSuite, outEvent.EventType == TransferSession::OutputEventType::kInitReceived); NL_TEST_ASSERT(inSuite, outEvent.transferInitData.TransferCtlFlags == initData.TransferCtlFlags); @@ -213,7 +215,7 @@ void SendAndVerifyAcceptMsg(nlTestSuite * inSuite, void * inContext, TransferSes NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); // Verify Sender emits ReceiveAccept message for sending - acceptSender.PollOutput(outEvent); + acceptSender.PollOutput(outEvent, kNoAdvanceTime); VerifyNoMoreOutput(inSuite, inContext, acceptSender); NL_TEST_ASSERT(inSuite, outEvent.EventType == TransferSession::OutputEventType::kMsgToSend); VerifyBdxMessageToSend(inSuite, inContext, outEvent, expectedMsg); @@ -225,7 +227,7 @@ void SendAndVerifyAcceptMsg(nlTestSuite * inSuite, void * inContext, TransferSes // Verify received ReceiveAccept. // Client may want to inspect TransferControl, MaxBlockSize, StartOffset, Length, and Metadata, and may choose to reject the // Transfer at this point. - acceptReceiver.PollOutput(outEvent); + acceptReceiver.PollOutput(outEvent, kNoAdvanceTime); VerifyNoMoreOutput(inSuite, inContext, acceptReceiver); NL_TEST_ASSERT(inSuite, outEvent.EventType == TransferSession::OutputEventType::kAcceptReceived); NL_TEST_ASSERT(inSuite, outEvent.transferAcceptData.ControlMode == acceptData.ControlMode); @@ -260,7 +262,7 @@ void SendAndVerifyQuery(nlTestSuite * inSuite, void * inContext, TransferSession // Verify that querySender emits BlockQuery message CHIP_ERROR err = querySender.PrepareBlockQuery(); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); - querySender.PollOutput(outEvent); + querySender.PollOutput(outEvent, kNoAdvanceTime); NL_TEST_ASSERT(inSuite, outEvent.EventType == TransferSession::OutputEventType::kMsgToSend); VerifyBdxMessageToSend(inSuite, inContext, outEvent, MessageType::BlockQuery); VerifyNoMoreOutput(inSuite, inContext, querySender); @@ -268,7 +270,7 @@ void SendAndVerifyQuery(nlTestSuite * inSuite, void * inContext, TransferSession // Pass BlockQuery to queryReceiver and verify queryReceiver emits QueryReceived event err = AttachHeaderAndSend(outEvent.msgTypeData, std::move(outEvent.MsgData), queryReceiver); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); - queryReceiver.PollOutput(outEvent); + queryReceiver.PollOutput(outEvent, kNoAdvanceTime); NL_TEST_ASSERT(inSuite, outEvent.EventType == TransferSession::OutputEventType::kQueryReceived); VerifyNoMoreOutput(inSuite, inContext, queryReceiver); } @@ -303,7 +305,7 @@ void SendAndVerifyArbitraryBlock(nlTestSuite * inSuite, void * inContext, Transf // Provide Block data and verify sender emits Block message err = sender.PrepareBlock(blockData); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); - sender.PollOutput(outEvent); + sender.PollOutput(outEvent, kNoAdvanceTime); NL_TEST_ASSERT(inSuite, outEvent.EventType == TransferSession::OutputEventType::kMsgToSend); VerifyBdxMessageToSend(inSuite, inContext, outEvent, expected); VerifyNoMoreOutput(inSuite, inContext, sender); @@ -311,7 +313,7 @@ void SendAndVerifyArbitraryBlock(nlTestSuite * inSuite, void * inContext, Transf // Pass Block message to receiver and verify matching Block is received err = AttachHeaderAndSend(outEvent.msgTypeData, std::move(outEvent.MsgData), receiver); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); - receiver.PollOutput(outEvent); + receiver.PollOutput(outEvent, kNoAdvanceTime); NL_TEST_ASSERT(inSuite, outEvent.EventType == TransferSession::OutputEventType::kBlockReceived); NL_TEST_ASSERT(inSuite, outEvent.blockdata.Data != nullptr); if (outEvent.EventType == TransferSession::OutputEventType::kBlockReceived && outEvent.blockdata.Data != nullptr) @@ -333,7 +335,7 @@ void SendAndVerifyBlockAck(nlTestSuite * inSuite, void * inContext, TransferSess // Verify PrepareBlockAck() outputs message to send CHIP_ERROR err = ackSender.PrepareBlockAck(); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); - ackSender.PollOutput(outEvent); + ackSender.PollOutput(outEvent, kNoAdvanceTime); NL_TEST_ASSERT(inSuite, outEvent.EventType == TransferSession::OutputEventType::kMsgToSend); VerifyBdxMessageToSend(inSuite, inContext, outEvent, expectedMsgType); VerifyNoMoreOutput(inSuite, inContext, ackSender); @@ -341,7 +343,7 @@ void SendAndVerifyBlockAck(nlTestSuite * inSuite, void * inContext, TransferSess // Pass BlockAck to ackReceiver and verify it was received err = AttachHeaderAndSend(outEvent.msgTypeData, std::move(outEvent.MsgData), ackReceiver); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); - ackReceiver.PollOutput(outEvent); + ackReceiver.PollOutput(outEvent, kNoAdvanceTime); NL_TEST_ASSERT(inSuite, outEvent.EventType == expectedEventType); VerifyNoMoreOutput(inSuite, inContext, ackReceiver); } @@ -574,6 +576,46 @@ void TestBadAcceptMessageFields(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, err != CHIP_NO_ERROR); } +// Test that a TransferSession will emit kTransferTimeout if the specified timeout is exceeded while waiting for a response. +void TestTimeout(nlTestSuite * inSuite, void * inContext) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + TransferSession initiator; + TransferSession::OutputEvent outEvent; + + System::Clock::Timeout timeout = System::Clock::Milliseconds32(24); + System::Clock::Timestamp startTime = System::Clock::Milliseconds64(100); + System::Clock::Timestamp endTime = System::Clock::Milliseconds64(124); + + // Initialize struct with arbitrary TransferInit parameters + TransferSession::TransferInitData initOptions; + initOptions.TransferCtlFlags = TransferControlFlags::kReceiverDrive; + initOptions.MaxBlockSize = 64; + initOptions.StartOffset = 0; + initOptions.Length = 0; + char testFileDes[9] = { "test.txt" }; // arbitrary file designator + initOptions.FileDesLength = static_cast(strlen(testFileDes)); + initOptions.FileDesignator = reinterpret_cast(testFileDes); + initOptions.Metadata = nullptr; + initOptions.MetadataLength = 0; + + TransferRole role = TransferRole::kReceiver; + + // Verify initiator outputs respective Init message (depending on role) after StartTransfer() + err = initiator.StartTransfer(role, initOptions, timeout); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + + // First PollOutput() should output the TransferInit message + initiator.PollOutput(outEvent, startTime); + NL_TEST_ASSERT(inSuite, outEvent.EventType == TransferSession::OutputEventType::kMsgToSend); + MessageType expectedInitMsg = (role == TransferRole::kSender) ? MessageType::SendInit : MessageType::ReceiveInit; + VerifyBdxMessageToSend(inSuite, inContext, outEvent, expectedInitMsg); + + // Second PollOutput() with no call to HandleMessageReceived() should result in a timeout. + initiator.PollOutput(outEvent, endTime); + NL_TEST_ASSERT(inSuite, outEvent.EventType == TransferSession::OutputEventType::kTransferTimeout); +} + // Test that sending the same block twice (with same block counter) results in a StatusReport message with BadBlockCounter. Also // test that receiving the StatusReport ends the transfer on the other node. void TestDuplicateBlockError(nlTestSuite * inSuite, void * inContext) @@ -633,7 +675,7 @@ void TestDuplicateBlockError(nlTestSuite * inSuite, void * inContext) // Provide Block data and verify sender emits Block message err = respondingSender.PrepareBlock(blockData); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); - respondingSender.PollOutput(eventWithBlock); + respondingSender.PollOutput(eventWithBlock, kNoAdvanceTime); NL_TEST_ASSERT(inSuite, eventWithBlock.EventType == TransferSession::OutputEventType::kMsgToSend); VerifyBdxMessageToSend(inSuite, inContext, eventWithBlock, MessageType::Block); VerifyNoMoreOutput(inSuite, inContext, respondingSender); @@ -643,7 +685,7 @@ void TestDuplicateBlockError(nlTestSuite * inSuite, void * inContext) // Pass Block message to receiver and verify matching Block is received err = AttachHeaderAndSend(eventWithBlock.msgTypeData, std::move(eventWithBlock.MsgData), initiatingReceiver); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); - initiatingReceiver.PollOutput(outEvent); + initiatingReceiver.PollOutput(outEvent, kNoAdvanceTime); NL_TEST_ASSERT(inSuite, outEvent.EventType == TransferSession::OutputEventType::kBlockReceived); NL_TEST_ASSERT(inSuite, outEvent.blockdata.Data != nullptr); VerifyNoMoreOutput(inSuite, inContext, initiatingReceiver); @@ -653,7 +695,7 @@ void TestDuplicateBlockError(nlTestSuite * inSuite, void * inContext) // Verify receiving same Block twice fails and results in StatusReport event, and then InternalError event err = AttachHeaderAndSend(eventWithBlock.msgTypeData, std::move(blockCopy), initiatingReceiver); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); - initiatingReceiver.PollOutput(outEvent); + initiatingReceiver.PollOutput(outEvent, kNoAdvanceTime); NL_TEST_ASSERT(inSuite, outEvent.EventType == TransferSession::OutputEventType::kMsgToSend); System::PacketBufferHandle statusReportMsg = outEvent.MsgData.Retain(); TransferSession::MessageTypeData statusReportMsgTypeData = outEvent.msgTypeData; @@ -662,21 +704,21 @@ void TestDuplicateBlockError(nlTestSuite * inSuite, void * inContext) // All subsequent PollOutput() calls should return kInternalError for (int i = 0; i < 5; ++i) { - initiatingReceiver.PollOutput(outEvent); + initiatingReceiver.PollOutput(outEvent, kNoAdvanceTime); NL_TEST_ASSERT(inSuite, outEvent.EventType == TransferSession::OutputEventType::kInternalError); NL_TEST_ASSERT(inSuite, outEvent.statusData.statusCode == StatusCode::kBadBlockCounter); } err = AttachHeaderAndSend(statusReportMsgTypeData, std::move(statusReportMsg), respondingSender); NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); - respondingSender.PollOutput(outEvent); + respondingSender.PollOutput(outEvent, kNoAdvanceTime); NL_TEST_ASSERT(inSuite, outEvent.EventType == TransferSession::OutputEventType::kStatusReceived); NL_TEST_ASSERT(inSuite, outEvent.statusData.statusCode == StatusCode::kBadBlockCounter); // All subsequent PollOutput() calls should return kInternalError for (int i = 0; i < 5; ++i) { - respondingSender.PollOutput(outEvent); + respondingSender.PollOutput(outEvent, kNoAdvanceTime); NL_TEST_ASSERT(inSuite, outEvent.EventType == TransferSession::OutputEventType::kInternalError); NL_TEST_ASSERT(inSuite, outEvent.statusData.statusCode == StatusCode::kBadBlockCounter); } @@ -693,6 +735,7 @@ static const nlTest sTests[] = NL_TEST_DEF("TestInitiatingReceiverReceiverDrive", TestInitiatingReceiverReceiverDrive), NL_TEST_DEF("TestInitiatingSenderSenderDrive", TestInitiatingSenderSenderDrive), NL_TEST_DEF("TestBadAcceptMessageFields", TestBadAcceptMessageFields), + NL_TEST_DEF("TestTimeout", TestTimeout), NL_TEST_DEF("TestDuplicateBlockError", TestDuplicateBlockError), NL_TEST_SENTINEL() };