diff --git a/src/protocols/bdx/BdxMessages.cpp b/src/protocols/bdx/BdxMessages.cpp index 32e5db4b4534d0..3ac30d50912998 100644 --- a/src/protocols/bdx/BdxMessages.cpp +++ b/src/protocols/bdx/BdxMessages.cpp @@ -575,3 +575,48 @@ bool DataBlock::operator==(const DataBlock & another) const return ((BlockCounter == another.BlockCounter) && dataMatches); } + +// WARNING: this function should never return early, since MessageSize() relies on it to calculate +// the size of the message (even if the message is incomplete or filled out incorrectly). +Encoding::LittleEndian::BufferWriter & BlockQueryWithSkip::WriteToBuffer(Encoding::LittleEndian::BufferWriter & aBuffer) const +{ + aBuffer.Put32(BlockCounter); + aBuffer.Put64(BytesToSkip); + return aBuffer; +} + +CHIP_ERROR BlockQueryWithSkip::Parse(System::PacketBufferHandle aBuffer) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + uint8_t * bufStart = aBuffer->Start(); + Reader bufReader(bufStart, aBuffer->DataLength()); + SuccessOrExit(bufReader.Read32(&BlockCounter).StatusCode()); + SuccessOrExit(bufReader.Read64(&BytesToSkip).StatusCode()); + +exit: + if (bufReader.StatusCode() != CHIP_NO_ERROR) + { + err = bufReader.StatusCode(); + } + return err; +} + +size_t BlockQueryWithSkip::MessageSize() const +{ + BufferWriter emptyBuf(nullptr, 0); + return WriteToBuffer(emptyBuf).Needed(); +} + +bool BlockQueryWithSkip::operator==(const BlockQueryWithSkip & another) const +{ + return (BlockCounter == another.BlockCounter && BytesToSkip == another.BytesToSkip); +} + +#if CHIP_AUTOMATION_LOGGING +void BlockQueryWithSkip::LogMessage(bdx::MessageType messageType) const +{ + ChipLogAutomation("BlockQueryWithSkip"); + ChipLogAutomation(" Block Counter: %" PRIu32, BlockCounter); + ChipLogAutomation(" Bytes To Skip: %" PRIu64, BytesToSkip); +} +#endif // CHIP_AUTOMATION_LOGGING diff --git a/src/protocols/bdx/BdxMessages.h b/src/protocols/bdx/BdxMessages.h index 880008b6956f24..b9203f2ff114cc 100644 --- a/src/protocols/bdx/BdxMessages.h +++ b/src/protocols/bdx/BdxMessages.h @@ -34,15 +34,16 @@ namespace bdx { enum class MessageType : uint8_t { - SendInit = 0x01, - SendAccept = 0x02, - ReceiveInit = 0x04, - ReceiveAccept = 0x05, - BlockQuery = 0x10, - Block = 0x11, - BlockEOF = 0x12, - BlockAck = 0x13, - BlockAckEOF = 0x14, + SendInit = 0x01, + SendAccept = 0x02, + ReceiveInit = 0x04, + ReceiveAccept = 0x05, + BlockQuery = 0x10, + Block = 0x11, + BlockEOF = 0x12, + BlockAck = 0x13, + BlockAckEOF = 0x14, + BlockQueryWithSkip = 0x15, }; enum class StatusCode : uint16_t @@ -309,6 +310,28 @@ struct DataBlock : public BdxMessage using Block = DataBlock; using BlockEOF = DataBlock; +/** + * A struct for representing BlockQueryWithSkip messages + */ +struct BlockQueryWithSkip : public BdxMessage +{ + /** + * @brief + * Equality check method. + */ + bool operator==(const BlockQueryWithSkip &) const; + + uint32_t BlockCounter = 0; + uint64_t BytesToSkip = 0; + + CHIP_ERROR Parse(System::PacketBufferHandle aBuffer) override; + Encoding::LittleEndian::BufferWriter & WriteToBuffer(Encoding::LittleEndian::BufferWriter & aBuffer) const override; + size_t MessageSize() const override; +#if CHIP_AUTOMATION_LOGGING + void LogMessage(bdx::MessageType messageType) const override; +#endif // CHIP_AUTOMATION_LOGGING +}; + } // namespace bdx namespace Protocols { diff --git a/src/protocols/bdx/BdxTransferSession.cpp b/src/protocols/bdx/BdxTransferSession.cpp index f27f653ae4e4a5..33665bb9a740c0 100644 --- a/src/protocols/bdx/BdxTransferSession.cpp +++ b/src/protocols/bdx/BdxTransferSession.cpp @@ -106,6 +106,9 @@ void TransferSession::PollOutput(OutputEvent & event, System::Clock::Timestamp c case OutputEventType::kQueryReceived: event = OutputEvent(OutputEventType::kQueryReceived); break; + case OutputEventType::kQueryWithSkipReceived: + event = OutputEvent::QueryWithSkipEvent(mBytesToSkip); + break; case OutputEventType::kBlockReceived: event = OutputEvent::BlockDataEvent(mBlockEventData, std::move(mPendingMsgHandle)); break; @@ -285,6 +288,34 @@ CHIP_ERROR TransferSession::PrepareBlockQuery() return CHIP_NO_ERROR; } +CHIP_ERROR TransferSession::PrepareBlockQueryWithSkip(const uint64_t & bytesToSkip) +{ + const MessageType msgType = MessageType::BlockQueryWithSkip; + + VerifyOrReturnError(mState == TransferState::kTransferInProgress, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(mRole == TransferRole::kReceiver, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(mPendingOutput == OutputEventType::kNone, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(!mAwaitingResponse, CHIP_ERROR_INCORRECT_STATE); + + BlockQueryWithSkip queryMsg; + queryMsg.BlockCounter = mNextQueryNum; + queryMsg.BytesToSkip = bytesToSkip; + + ReturnErrorOnFailure(WriteToPacketBuffer(queryMsg, mPendingMsgHandle)); + +#if CHIP_AUTOMATION_LOGGING + ChipLogAutomation("Sending BDX Message"); + queryMsg.LogMessage(msgType); +#endif // CHIP_AUTOMATION_LOGGING + + mAwaitingResponse = true; + mLastQueryNum = mNextQueryNum++; + + PrepareOutgoingMessageEvent(msgType, mPendingOutput, mMsgTypeData); + + return CHIP_NO_ERROR; +} + CHIP_ERROR TransferSession::PrepareBlock(const BlockData & inData) { VerifyOrReturnError(mState == TransferState::kTransferInProgress, CHIP_ERROR_INCORRECT_STATE); @@ -447,6 +478,9 @@ CHIP_ERROR TransferSession::HandleBdxMessage(const PayloadHeader & header, Syste case MessageType::BlockQuery: HandleBlockQuery(std::move(msg)); break; + case MessageType::BlockQueryWithSkip: + HandleBlockQueryWithSkip(std::move(msg)); + break; case MessageType::Block: HandleBlock(std::move(msg)); break; @@ -628,6 +662,29 @@ void TransferSession::HandleBlockQuery(System::PacketBufferHandle msgData) #endif // CHIP_AUTOMATION_LOGGING } +void TransferSession::HandleBlockQueryWithSkip(System::PacketBufferHandle msgData) +{ + VerifyOrReturn(mRole == TransferRole::kSender, PrepareStatusReport(StatusCode::kUnexpectedMessage)); + VerifyOrReturn(mState == TransferState::kTransferInProgress, PrepareStatusReport(StatusCode::kUnexpectedMessage)); + VerifyOrReturn(mAwaitingResponse, PrepareStatusReport(StatusCode::kUnexpectedMessage)); + + BlockQueryWithSkip query; + const CHIP_ERROR err = query.Parse(std::move(msgData)); + VerifyOrReturn(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents)); + + VerifyOrReturn(query.BlockCounter == mNextBlockNum, PrepareStatusReport(StatusCode::kBadBlockCounter)); + + mPendingOutput = OutputEventType::kQueryWithSkipReceived; + + mAwaitingResponse = false; + mLastQueryNum = query.BlockCounter; + mBytesToSkip.BytesToSkip = query.BytesToSkip; + +#if CHIP_AUTOMATION_LOGGING + query.LogMessage(MessageType::BlockQueryWithSkip); +#endif // CHIP_AUTOMATION_LOGGING +} + void TransferSession::HandleBlock(System::PacketBufferHandle msgData) { VerifyOrReturn(mRole == TransferRole::kReceiver, PrepareStatusReport(StatusCode::kUnexpectedMessage)); @@ -858,6 +915,8 @@ const char * TransferSession::OutputEvent::ToString(OutputEventType outputEventT return "BlockReceived"; case OutputEventType::kQueryReceived: return "QueryReceived"; + case OutputEventType::kQueryWithSkipReceived: + return "QueryWithSkipReceived"; case OutputEventType::kAckReceived: return "AckReceived"; case OutputEventType::kAckEOFReceived: @@ -930,5 +989,12 @@ TransferSession::OutputEvent TransferSession::OutputEvent::MsgToSendEvent(Messag return event; } +TransferSession::OutputEvent TransferSession::OutputEvent::QueryWithSkipEvent(TransferSkipData bytesToSkip) +{ + OutputEvent event(OutputEventType::kQueryWithSkipReceived); + event.bytesToSkip = bytesToSkip; + return event; +} + } // namespace bdx } // namespace chip diff --git a/src/protocols/bdx/BdxTransferSession.h b/src/protocols/bdx/BdxTransferSession.h index 4082cc446fd2a3..de94c67fbd6a12 100644 --- a/src/protocols/bdx/BdxTransferSession.h +++ b/src/protocols/bdx/BdxTransferSession.h @@ -34,6 +34,7 @@ class DLL_EXPORT TransferSession kAcceptReceived, kBlockReceived, kQueryReceived, + kQueryWithSkipReceived, kAckReceived, kAckEOFReceived, kStatusReceived, @@ -99,6 +100,11 @@ class DLL_EXPORT TransferSession } }; + struct TransferSkipData + { + uint64_t BytesToSkip = 0; + }; + /** * @brief * All output data processed by the TransferSession object will be passed to the caller using this struct via PollOutput(). @@ -121,6 +127,7 @@ class DLL_EXPORT TransferSession BlockData blockdata; StatusReportData statusData; MessageTypeData msgTypeData; + TransferSkipData bytesToSkip; }; OutputEvent() : EventType(OutputEventType::kNone) { statusData = { StatusCode::kNone }; } @@ -134,6 +141,7 @@ class DLL_EXPORT TransferSession static OutputEvent BlockDataEvent(BlockData data, System::PacketBufferHandle msg); static OutputEvent StatusReportEvent(OutputEventType type, StatusReportData data); static OutputEvent MsgToSendEvent(MessageTypeData typeData, System::PacketBufferHandle msg); + static OutputEvent QueryWithSkipEvent(TransferSkipData bytesToSkip); }; /** @@ -314,6 +322,7 @@ class DLL_EXPORT TransferSession void HandleReceiveAccept(System::PacketBufferHandle msgData); void HandleSendAccept(System::PacketBufferHandle msgData); void HandleBlockQuery(System::PacketBufferHandle msgData); + void HandleBlockQueryWithSkip(System::PacketBufferHandle msgData); void HandleBlock(System::PacketBufferHandle msgData); void HandleBlockEOF(System::PacketBufferHandle msgData); void HandleBlockAck(System::PacketBufferHandle msgData); @@ -357,6 +366,7 @@ class DLL_EXPORT TransferSession TransferAcceptData mTransferAcceptData; BlockData mBlockEventData; MessageTypeData mMsgTypeData; + TransferSkipData mBytesToSkip; size_t mNumBytesProcessed = 0; diff --git a/src/protocols/bdx/tests/TestBdxMessages.cpp b/src/protocols/bdx/tests/TestBdxMessages.cpp index 1ae246c8b5c2db..1a6d2c4643fb2e 100644 --- a/src/protocols/bdx/tests/TestBdxMessages.cpp +++ b/src/protocols/bdx/tests/TestBdxMessages.cpp @@ -119,6 +119,16 @@ void TestDataBlockMessage(nlTestSuite * inSuite, void * inContext) TestHelperWrittenAndParsedMatch(inSuite, inContext, testMsg); } +void TestBlockQueryWithSkipMessage(nlTestSuite * inSuite, void * inContext) +{ + BlockQueryWithSkip testMsg; + + testMsg.BlockCounter = 5; + testMsg.BytesToSkip = 16; + + TestHelperWrittenAndParsedMatch(inSuite, inContext, testMsg); +} + // Test Suite /** @@ -132,6 +142,7 @@ static const nlTest sTests[] = NL_TEST_DEF("TestReceiveAcceptMessage", TestReceiveAcceptMessage), NL_TEST_DEF("TestCounterMessage", TestCounterMessage), NL_TEST_DEF("TestDataBlockMessage", TestDataBlockMessage), + NL_TEST_DEF("TestBlockQueryWithSkipMessage", TestBlockQueryWithSkipMessage), NL_TEST_SENTINEL() };