3 * Implementation for the TransferSession class.
4 * // TODO: Support Asynchronous mode. Currently, only Synchronous mode is supported.
7 #include <protocols/bdx/BdxTransferSession.h>
9 #include <protocols/Protocols.h>
10 #include <protocols/bdx/BdxMessages.h>
11 #include <protocols/common/Constants.h>
12 #include <support/BufferReader.h>
13 #include <support/CodeUtils.h>
14 #include <support/ReturnMacros.h>
15 #include <system/SystemPacketBuffer.h>
16 #include <transport/SecureSessionMgr.h>
19 constexpr uint8_t kBdxVersion = 0; ///< The version of this implementation of the BDX spec
20 constexpr size_t kStatusReportMinSize = 2 + 4 + 2; ///< 16 bits for GeneralCode, 32 bits for ProtocolId, 16 bits for ProtocolCode
24 * Allocate a new PacketBuffer and write data from a BDX message struct.
26 CHIP_ERROR WriteToPacketBuffer(const ::chip::bdx::BdxMessage & msgStruct, ::chip::System::PacketBufferHandle & msgBuf)
28 size_t msgDataSize = msgStruct.MessageSize();
29 ::chip::Encoding::LittleEndian::PacketBufferWriter bbuf(chip::MessagePacketBuffer::New(msgDataSize), msgDataSize);
32 return CHIP_ERROR_NO_MEMORY;
34 msgStruct.WriteToBuffer(bbuf);
35 msgBuf = bbuf.Finalize();
38 return CHIP_ERROR_NO_MEMORY;
43 // We could make this whole method a template, but it's probably smaller code to
44 // share the implementation across all message types.
45 CHIP_ERROR AttachHeader(uint16_t protocolId, uint8_t msgType, ::chip::System::PacketBufferHandle & msgBuf)
47 ::chip::PayloadHeader payloadHeader;
49 payloadHeader.SetMessageType(protocolId, msgType);
51 CHIP_ERROR err = payloadHeader.EncodeBeforeData(msgBuf);
58 template <typename MessageType>
59 inline CHIP_ERROR AttachHeader(MessageType msgType, ::chip::System::PacketBufferHandle & msgBuf)
61 return AttachHeader(chip::Protocols::MessageTypeTraits<MessageType>::ProtocolId, static_cast<uint8_t>(msgType), msgBuf);
63 } // anonymous namespace
68 TransferSession::TransferSession()
70 mSuppportedXferOpts.SetRaw(0);
73 void TransferSession::PollOutput(OutputEvent & event, uint64_t curTimeMs)
75 event = OutputEvent(kNone);
77 if (mShouldInitTimeoutStart)
79 mTimeoutStartTimeMs = curTimeMs;
80 mShouldInitTimeoutStart = false;
83 if (mAwaitingResponse && ((curTimeMs - mTimeoutStartTimeMs) >= mTimeoutMs))
85 event = OutputEvent(kTransferTimeout);
87 mAwaitingResponse = false;
91 switch (mPendingOutput)
94 event = OutputEvent(kNone);
97 event = OutputEvent::StatusReportEvent(kInternalError, mStatusReportData);
100 event = OutputEvent::StatusReportEvent(kStatusReceived, mStatusReportData);
103 event = OutputEvent(kMsgToSend);
104 event.MsgData = std::move(mPendingMsgHandle);
105 mTimeoutStartTimeMs = curTimeMs;
108 event = OutputEvent::TransferInitEvent(mTransferRequestData, std::move(mPendingMsgHandle));
110 case kAcceptReceived:
111 event = OutputEvent::TransferAcceptEvent(mTransferAcceptData, std::move(mPendingMsgHandle));
114 event = OutputEvent(kQueryReceived);
117 event = OutputEvent::BlockDataEvent(mBlockEventData, std::move(mPendingMsgHandle));
120 event = OutputEvent(kAckReceived);
122 case kAckEOFReceived:
123 event = OutputEvent(kAckEOFReceived);
126 event = OutputEvent(kNone);
130 // If there's no other pending output but an error occured or was received, then continue to output the error.
131 // This ensures that when the TransferSession encounters an error and needs to send a StatusReport, both a kMsgToSend and a
132 // kInternalError output event will be emitted.
133 if (event.EventType == kNone && mState == kErrorState)
135 event = OutputEvent::StatusReportEvent(kInternalError, mStatusReportData);
138 mPendingOutput = kNone;
141 CHIP_ERROR TransferSession::StartTransfer(TransferRole role, const TransferInitData & initData, uint32_t timeoutMs)
143 CHIP_ERROR err = CHIP_NO_ERROR;
145 TransferInit initMsg;
147 VerifyOrExit(mState == kUnitialized, err = CHIP_ERROR_INCORRECT_STATE);
150 mTimeoutMs = timeoutMs;
152 // Set transfer parameters. They may be overridden later by an Accept message
153 mSuppportedXferOpts.SetRaw(initData.TransferCtlFlagsRaw);
154 mMaxSupportedBlockSize = initData.MaxBlockSize;
155 mStartOffset = initData.StartOffset;
156 mTransferLength = initData.Length;
158 // Prepare TransferInit message
159 initMsg.TransferCtlOptions.SetRaw(initData.TransferCtlFlagsRaw);
160 initMsg.Version = kBdxVersion;
161 initMsg.MaxBlockSize = mMaxSupportedBlockSize;
162 initMsg.StartOffset = mStartOffset;
163 initMsg.MaxLength = mTransferLength;
164 initMsg.FileDesignator = initData.FileDesignator;
165 initMsg.FileDesLength = initData.FileDesLength;
166 initMsg.Metadata = initData.Metadata;
167 initMsg.MetadataLength = initData.MetadataLength;
169 err = WriteToPacketBuffer(initMsg, mPendingMsgHandle);
172 msgType = (mRole == kRole_Sender) ? MessageType::SendInit : MessageType::ReceiveInit;
173 err = AttachHeader(msgType, mPendingMsgHandle);
176 mState = kAwaitingAccept;
177 mAwaitingResponse = true;
179 mPendingOutput = kMsgToSend;
185 CHIP_ERROR TransferSession::WaitForTransfer(TransferRole role, BitFlags<uint8_t, TransferControlFlags> xferControlOpts,
186 uint16_t maxBlockSize, uint32_t timeoutMs)
188 CHIP_ERROR err = CHIP_NO_ERROR;
190 VerifyOrExit(mState == kUnitialized, err = CHIP_ERROR_INCORRECT_STATE);
192 // Used to determine compatibility with any future TransferInit parameters
194 mTimeoutMs = timeoutMs;
195 mSuppportedXferOpts = xferControlOpts;
196 mMaxSupportedBlockSize = maxBlockSize;
198 mState = kAwaitingInitMsg;
204 CHIP_ERROR TransferSession::AcceptTransfer(const TransferAcceptData & acceptData)
206 CHIP_ERROR err = CHIP_NO_ERROR;
207 System::PacketBufferHandle outMsgBuf;
208 BitFlags<uint8_t, TransferControlFlags> proposedControlOpts;
210 VerifyOrExit(mState == kNegotiateTransferParams, err = CHIP_ERROR_INCORRECT_STATE);
211 VerifyOrExit(mPendingOutput == kNone, err = CHIP_ERROR_INCORRECT_STATE);
213 // Don't allow a Control method that wasn't supported by the initiator
214 // MaxBlockSize can't be larger than the proposed value
215 proposedControlOpts.SetRaw(mTransferRequestData.TransferCtlFlagsRaw);
216 VerifyOrExit(proposedControlOpts.Has(acceptData.ControlMode), err = CHIP_ERROR_INVALID_ARGUMENT);
217 VerifyOrExit(acceptData.MaxBlockSize <= mTransferRequestData.MaxBlockSize, err = CHIP_ERROR_INVALID_ARGUMENT);
219 mTransferMaxBlockSize = acceptData.MaxBlockSize;
221 if (mRole == kRole_Sender)
223 mStartOffset = acceptData.StartOffset;
224 mTransferLength = acceptData.Length;
226 ReceiveAccept acceptMsg;
227 acceptMsg.TransferCtlFlags.Set(acceptData.ControlMode);
228 acceptMsg.Version = mTransferVersion;
229 acceptMsg.MaxBlockSize = acceptData.MaxBlockSize;
230 acceptMsg.StartOffset = acceptData.StartOffset;
231 acceptMsg.Length = acceptData.Length;
232 acceptMsg.Metadata = acceptData.Metadata;
233 acceptMsg.MetadataLength = acceptData.MetadataLength;
235 err = WriteToPacketBuffer(acceptMsg, mPendingMsgHandle);
238 err = AttachHeader(MessageType::ReceiveAccept, mPendingMsgHandle);
243 SendAccept acceptMsg;
244 acceptMsg.TransferCtlFlags.Set(acceptData.ControlMode);
245 acceptMsg.Version = mTransferVersion;
246 acceptMsg.MaxBlockSize = acceptData.MaxBlockSize;
247 acceptMsg.Metadata = acceptData.Metadata;
248 acceptMsg.MetadataLength = acceptData.MetadataLength;
250 err = WriteToPacketBuffer(acceptMsg, mPendingMsgHandle);
253 err = AttachHeader(MessageType::SendAccept, mPendingMsgHandle);
257 mPendingOutput = kMsgToSend;
259 mState = kTransferInProgress;
261 if ((mRole == kRole_Receiver && mControlMode == kControl_SenderDrive) ||
262 (mRole == kRole_Sender && mControlMode == kControl_ReceiverDrive))
264 mAwaitingResponse = true;
271 CHIP_ERROR TransferSession::PrepareBlockQuery()
273 CHIP_ERROR err = CHIP_NO_ERROR;
276 VerifyOrExit(mState == kTransferInProgress, err = CHIP_ERROR_INCORRECT_STATE);
277 VerifyOrExit(mRole == kRole_Receiver, err = CHIP_ERROR_INCORRECT_STATE);
278 VerifyOrExit(mPendingOutput == kNone, err = CHIP_ERROR_INCORRECT_STATE);
279 VerifyOrExit(!mAwaitingResponse, err = CHIP_ERROR_INCORRECT_STATE);
281 queryMsg.BlockCounter = mNextQueryNum;
283 err = WriteToPacketBuffer(queryMsg, mPendingMsgHandle);
286 err = AttachHeader(MessageType::BlockQuery, mPendingMsgHandle);
289 mPendingOutput = kMsgToSend;
291 mAwaitingResponse = true;
292 mLastQueryNum = mNextQueryNum++;
298 CHIP_ERROR TransferSession::PrepareBlock(const BlockData & inData)
300 CHIP_ERROR err = CHIP_NO_ERROR;
304 VerifyOrExit(mState == kTransferInProgress, err = CHIP_ERROR_INCORRECT_STATE);
305 VerifyOrExit(mRole == kRole_Sender, err = CHIP_ERROR_INCORRECT_STATE);
306 VerifyOrExit(mPendingOutput == kNone, err = CHIP_ERROR_INCORRECT_STATE);
307 VerifyOrExit(!mAwaitingResponse, err = CHIP_ERROR_INCORRECT_STATE);
309 // Verify non-zero data is provided and is no longer than MaxBlockSize (BlockEOF may contain 0 length data)
310 VerifyOrExit((inData.Data != nullptr) && (inData.Length <= mTransferMaxBlockSize), err = CHIP_ERROR_INVALID_ARGUMENT);
312 blockMsg.BlockCounter = mNextBlockNum;
313 blockMsg.Data = inData.Data;
314 blockMsg.DataLength = inData.Length;
316 err = WriteToPacketBuffer(blockMsg, mPendingMsgHandle);
319 msgType = inData.IsEof ? MessageType::BlockEOF : MessageType::Block;
320 err = AttachHeader(msgType, mPendingMsgHandle);
323 mPendingOutput = kMsgToSend;
325 if (msgType == MessageType::BlockEOF)
327 mState = kAwaitingEOFAck;
330 mAwaitingResponse = true;
331 mLastBlockNum = mNextBlockNum++;
337 CHIP_ERROR TransferSession::PrepareBlockAck()
339 CHIP_ERROR err = CHIP_NO_ERROR;
340 CounterMessage ackMsg;
343 VerifyOrExit(mRole == kRole_Receiver, err = CHIP_ERROR_INCORRECT_STATE);
344 VerifyOrExit((mState == kTransferInProgress) || (mState == kReceivedEOF), err = CHIP_ERROR_INCORRECT_STATE);
345 VerifyOrExit(mPendingOutput == kNone, err = CHIP_ERROR_INCORRECT_STATE);
347 ackMsg.BlockCounter = mLastBlockNum;
348 msgType = (mState == kReceivedEOF) ? MessageType::BlockAckEOF : MessageType::BlockAck;
350 err = WriteToPacketBuffer(ackMsg, mPendingMsgHandle);
353 err = AttachHeader(msgType, mPendingMsgHandle);
356 if (mState == kTransferInProgress)
358 if (mControlMode == kControl_SenderDrive)
360 // In Sender Drive, a BlockAck is implied to also be a query for the next Block, so expect to receive a Block
362 mLastQueryNum = ackMsg.BlockCounter + 1;
363 mAwaitingResponse = true;
366 else if (mState == kReceivedEOF)
368 mState = kTransferDone;
369 mAwaitingResponse = false;
372 mPendingOutput = kMsgToSend;
378 CHIP_ERROR TransferSession::AbortTransfer(StatusCode reason)
380 CHIP_ERROR err = CHIP_NO_ERROR;
382 VerifyOrExit((mState != kUnitialized) && (mState != kTransferDone) && (mState != kErrorState),
383 err = CHIP_ERROR_INCORRECT_STATE);
385 PrepareStatusReport(reason);
391 void TransferSession::Reset()
393 mPendingOutput = kNone;
394 mState = kUnitialized;
395 mSuppportedXferOpts.SetRaw(0);
396 mTransferVersion = 0;
397 mMaxSupportedBlockSize = 0;
400 mTransferMaxBlockSize = 0;
402 mPendingMsgHandle = nullptr;
404 mNumBytesProcessed = 0;
411 mTimeoutStartTimeMs = 0;
412 mShouldInitTimeoutStart = true;
413 mAwaitingResponse = false;
416 CHIP_ERROR TransferSession::HandleMessageReceived(System::PacketBufferHandle msg, uint64_t curTimeMs)
418 CHIP_ERROR err = CHIP_NO_ERROR;
419 PayloadHeader payloadHeader;
421 VerifyOrExit(!msg.IsNull(), err = CHIP_ERROR_INVALID_ARGUMENT);
423 err = payloadHeader.DecodeAndConsume(msg);
426 if (payloadHeader.GetProtocolID() == Protocols::kProtocol_BDX)
428 err = HandleBdxMessage(payloadHeader, std::move(msg));
431 mTimeoutStartTimeMs = curTimeMs;
433 else if (payloadHeader.GetProtocolID() == Protocols::kProtocol_Protocol_Common &&
434 payloadHeader.GetMessageType() == static_cast<uint8_t>(Protocols::Common::MsgType::StatusReport))
436 err = HandleStatusReportMessage(payloadHeader, std::move(msg));
441 err = CHIP_ERROR_INVALID_MESSAGE_TYPE;
448 // Return CHIP_ERROR only if there was a problem decoding the message. Otherwise, call PrepareStatusReport().
449 CHIP_ERROR TransferSession::HandleBdxMessage(PayloadHeader & header, System::PacketBufferHandle msg)
451 CHIP_ERROR err = CHIP_NO_ERROR;
452 MessageType msgType = static_cast<MessageType>(header.GetMessageType());
454 VerifyOrExit(!msg.IsNull(), err = CHIP_ERROR_INVALID_ARGUMENT);
455 VerifyOrExit(mPendingOutput == kNone, err = CHIP_ERROR_INCORRECT_STATE);
459 case MessageType::SendInit:
460 case MessageType::ReceiveInit:
461 HandleTransferInit(msgType, std::move(msg));
463 case MessageType::SendAccept:
464 HandleSendAccept(std::move(msg));
466 case MessageType::ReceiveAccept:
467 HandleReceiveAccept(std::move(msg));
469 case MessageType::BlockQuery:
470 HandleBlockQuery(std::move(msg));
472 case MessageType::Block:
473 HandleBlock(std::move(msg));
475 case MessageType::BlockEOF:
476 HandleBlockEOF(std::move(msg));
478 case MessageType::BlockAck:
479 HandleBlockAck(std::move(msg));
481 case MessageType::BlockAckEOF:
482 HandleBlockAckEOF(std::move(msg));
485 err = CHIP_ERROR_INVALID_MESSAGE_TYPE;
495 * Parse a StatusReport message and prepare to emit an OutputEvent with the message data.
497 * NOTE: BDX does not currently expect to ever use a "Success" general code, so it will be treated as an error along with any
500 CHIP_ERROR TransferSession::HandleStatusReportMessage(PayloadHeader & header, System::PacketBufferHandle msg)
502 VerifyOrReturnError(!msg.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
504 mState = kErrorState;
505 mAwaitingResponse = false;
507 uint16_t generalCode = 0;
508 uint32_t protocolId = 0;
509 uint16_t protocolCode = 0;
510 Encoding::LittleEndian::Reader reader(msg->Start(), msg->DataLength());
511 ReturnErrorOnFailure(reader.Read16(&generalCode).Read32(&protocolId).Read16(&protocolCode).StatusCode());
512 VerifyOrReturnError((protocolId == Protocols::kProtocol_BDX), CHIP_ERROR_INVALID_MESSAGE_TYPE);
514 mStatusReportData.StatusCode = protocolCode;
516 mPendingOutput = kStatusReceived;
518 return CHIP_NO_ERROR;
521 void TransferSession::HandleTransferInit(MessageType msgType, System::PacketBufferHandle msgData)
523 CHIP_ERROR err = CHIP_NO_ERROR;
524 TransferInit transferInit;
526 VerifyOrExit(mState == kAwaitingInitMsg, PrepareStatusReport(kStatus_ServerBadState));
528 if (mRole == kRole_Sender)
530 VerifyOrExit(msgType == MessageType::ReceiveInit, PrepareStatusReport(kStatus_ServerBadState));
534 VerifyOrExit(msgType == MessageType::SendInit, PrepareStatusReport(kStatus_ServerBadState));
537 err = transferInit.Parse(msgData.Retain());
538 VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(kStatus_BadMessageContents));
540 ResolveTransferControlOptions(transferInit.TransferCtlOptions);
541 mTransferVersion = ::chip::min(kBdxVersion, transferInit.Version);
542 mTransferMaxBlockSize = ::chip::min(mMaxSupportedBlockSize, transferInit.MaxBlockSize);
544 // Accept for now, they may be changed or rejected by the peer if this is a ReceiveInit
545 mStartOffset = transferInit.StartOffset;
546 mTransferLength = transferInit.MaxLength;
548 // Store the Request data to share with the caller for verification
549 mTransferRequestData.TransferCtlFlagsRaw = transferInit.TransferCtlOptions.Raw(),
550 mTransferRequestData.MaxBlockSize = transferInit.MaxBlockSize;
551 mTransferRequestData.StartOffset = transferInit.StartOffset;
552 mTransferRequestData.Length = transferInit.MaxLength;
553 mTransferRequestData.FileDesignator = transferInit.FileDesignator;
554 mTransferRequestData.FileDesLength = transferInit.FileDesLength;
555 mTransferRequestData.Metadata = transferInit.Metadata;
556 mTransferRequestData.MetadataLength = transferInit.MetadataLength;
558 mPendingMsgHandle = std::move(msgData);
559 mPendingOutput = kInitReceived;
561 mState = kNegotiateTransferParams;
567 void TransferSession::HandleReceiveAccept(System::PacketBufferHandle msgData)
569 CHIP_ERROR err = CHIP_NO_ERROR;
570 ReceiveAccept rcvAcceptMsg;
572 VerifyOrExit(mRole == kRole_Receiver, PrepareStatusReport(kStatus_ServerBadState));
573 VerifyOrExit(mState == kAwaitingAccept, PrepareStatusReport(kStatus_ServerBadState));
575 err = rcvAcceptMsg.Parse(msgData.Retain());
576 VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(kStatus_BadMessageContents));
578 // Verify that Accept parameters are compatible with the original proposed parameters
579 err = VerifyProposedMode(rcvAcceptMsg.TransferCtlFlags);
582 mTransferMaxBlockSize = rcvAcceptMsg.MaxBlockSize;
583 mStartOffset = rcvAcceptMsg.StartOffset;
584 mTransferLength = rcvAcceptMsg.Length;
586 // Note: if VerifyProposedMode() returned with no error, then mControlMode must match the proposed mode in the ReceiveAccept
588 mTransferAcceptData.ControlMode = mControlMode;
589 mTransferAcceptData.MaxBlockSize = rcvAcceptMsg.MaxBlockSize;
590 mTransferAcceptData.StartOffset = rcvAcceptMsg.StartOffset;
591 mTransferAcceptData.Length = rcvAcceptMsg.Length;
592 mTransferAcceptData.Metadata = rcvAcceptMsg.Metadata;
593 mTransferAcceptData.MetadataLength = rcvAcceptMsg.MetadataLength;
595 mPendingMsgHandle = std::move(msgData);
596 mPendingOutput = kAcceptReceived;
598 mAwaitingResponse = (mControlMode == kControl_SenderDrive);
599 mState = kTransferInProgress;
605 void TransferSession::HandleSendAccept(System::PacketBufferHandle msgData)
607 CHIP_ERROR err = CHIP_NO_ERROR;
608 SendAccept sendAcceptMsg;
610 VerifyOrExit(mRole == kRole_Sender, PrepareStatusReport(kStatus_ServerBadState));
611 VerifyOrExit(mState == kAwaitingAccept, PrepareStatusReport(kStatus_ServerBadState));
613 err = sendAcceptMsg.Parse(msgData.Retain());
614 VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(kStatus_BadMessageContents));
616 // Verify that Accept parameters are compatible with the original proposed parameters
617 err = VerifyProposedMode(sendAcceptMsg.TransferCtlFlags);
620 // Note: if VerifyProposedMode() returned with no error, then mControlMode must match the proposed mode in the SendAccept
622 mTransferMaxBlockSize = sendAcceptMsg.MaxBlockSize;
624 mTransferAcceptData.ControlMode = mControlMode;
625 mTransferAcceptData.MaxBlockSize = sendAcceptMsg.MaxBlockSize;
626 mTransferAcceptData.StartOffset = mStartOffset; // Not included in SendAccept msg, so use member
627 mTransferAcceptData.Length = mTransferLength; // Not included in SendAccept msg, so use member
628 mTransferAcceptData.Metadata = sendAcceptMsg.Metadata;
629 mTransferAcceptData.MetadataLength = sendAcceptMsg.MetadataLength;
631 mPendingMsgHandle = std::move(msgData);
632 mPendingOutput = kAcceptReceived;
634 mAwaitingResponse = (mControlMode == kControl_ReceiverDrive);
635 mState = kTransferInProgress;
641 void TransferSession::HandleBlockQuery(System::PacketBufferHandle msgData)
643 CHIP_ERROR err = CHIP_NO_ERROR;
646 VerifyOrExit(mRole == kRole_Sender, PrepareStatusReport(kStatus_ServerBadState));
647 VerifyOrExit(mState == kTransferInProgress, PrepareStatusReport(kStatus_ServerBadState));
648 VerifyOrExit(mAwaitingResponse, PrepareStatusReport(kStatus_ServerBadState));
650 err = query.Parse(std::move(msgData));
651 VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(kStatus_BadMessageContents));
653 VerifyOrExit(query.BlockCounter == mNextBlockNum, PrepareStatusReport(kStatus_BadBlockCounter));
655 mPendingOutput = kQueryReceived;
657 mAwaitingResponse = false;
658 mLastQueryNum = query.BlockCounter;
664 void TransferSession::HandleBlock(System::PacketBufferHandle msgData)
666 CHIP_ERROR err = CHIP_NO_ERROR;
669 VerifyOrExit(mRole == kRole_Receiver, PrepareStatusReport(kStatus_ServerBadState));
670 VerifyOrExit(mState == kTransferInProgress, PrepareStatusReport(kStatus_ServerBadState));
671 VerifyOrExit(mAwaitingResponse, PrepareStatusReport(kStatus_ServerBadState));
673 err = blockMsg.Parse(msgData.Retain());
674 VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(kStatus_BadMessageContents));
676 VerifyOrExit(blockMsg.BlockCounter == mLastQueryNum, PrepareStatusReport(kStatus_BadBlockCounter));
677 VerifyOrExit((blockMsg.DataLength > 0) && (blockMsg.DataLength <= mTransferMaxBlockSize),
678 PrepareStatusReport(kStatus_BadMessageContents));
680 if (IsTransferLengthDefinite())
682 VerifyOrExit(mNumBytesProcessed + blockMsg.DataLength <= mTransferLength, PrepareStatusReport(kStatus_LengthMismatch));
685 mBlockEventData.Data = blockMsg.Data;
686 mBlockEventData.Length = blockMsg.DataLength;
687 mBlockEventData.IsEof = false;
689 mPendingMsgHandle = std::move(msgData);
690 mPendingOutput = kBlockReceived;
692 mNumBytesProcessed += blockMsg.DataLength;
693 mLastBlockNum = blockMsg.BlockCounter;
695 mAwaitingResponse = false;
701 void TransferSession::HandleBlockEOF(System::PacketBufferHandle msgData)
703 CHIP_ERROR err = CHIP_NO_ERROR;
704 BlockEOF blockEOFMsg;
706 VerifyOrExit(mRole == kRole_Receiver, PrepareStatusReport(kStatus_ServerBadState));
707 VerifyOrExit(mState == kTransferInProgress, PrepareStatusReport(kStatus_ServerBadState));
708 VerifyOrExit(mAwaitingResponse, PrepareStatusReport(kStatus_ServerBadState));
710 err = blockEOFMsg.Parse(msgData.Retain());
711 VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(kStatus_BadMessageContents));
713 VerifyOrExit(blockEOFMsg.BlockCounter == mLastQueryNum, PrepareStatusReport(kStatus_BadBlockCounter));
714 VerifyOrExit(blockEOFMsg.DataLength <= mTransferMaxBlockSize, PrepareStatusReport(kStatus_BadMessageContents));
716 mBlockEventData.Data = blockEOFMsg.Data;
717 mBlockEventData.Length = blockEOFMsg.DataLength;
718 mBlockEventData.IsEof = true;
720 mPendingMsgHandle = std::move(msgData);
721 mPendingOutput = kBlockReceived;
723 mNumBytesProcessed += blockEOFMsg.DataLength;
724 mLastBlockNum = blockEOFMsg.BlockCounter;
726 mAwaitingResponse = false;
727 mState = kReceivedEOF;
733 void TransferSession::HandleBlockAck(System::PacketBufferHandle msgData)
735 CHIP_ERROR err = CHIP_NO_ERROR;
738 VerifyOrExit(mRole == kRole_Sender, PrepareStatusReport(kStatus_ServerBadState));
739 VerifyOrExit(mState == kTransferInProgress, PrepareStatusReport(kStatus_ServerBadState));
740 VerifyOrExit(mAwaitingResponse, PrepareStatusReport(kStatus_ServerBadState));
742 err = ackMsg.Parse(std::move(msgData));
743 VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(kStatus_BadMessageContents));
744 VerifyOrExit(ackMsg.BlockCounter == mLastBlockNum, PrepareStatusReport(kStatus_BadBlockCounter));
746 mPendingOutput = kAckReceived;
748 // In Receiver Drive, the Receiver can send a BlockAck to indicate receipt of the message and reset the timeout.
749 // In this case, the Sender should wait to receive a BlockQuery next.
750 mAwaitingResponse = (mControlMode == kControl_ReceiverDrive);
756 void TransferSession::HandleBlockAckEOF(System::PacketBufferHandle msgData)
758 CHIP_ERROR err = CHIP_NO_ERROR;
761 VerifyOrExit(mRole == kRole_Sender, PrepareStatusReport(kStatus_ServerBadState));
762 VerifyOrExit(mState == kAwaitingEOFAck, PrepareStatusReport(kStatus_ServerBadState));
763 VerifyOrExit(mAwaitingResponse, PrepareStatusReport(kStatus_ServerBadState));
765 err = ackMsg.Parse(std::move(msgData));
766 VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(kStatus_BadMessageContents));
767 VerifyOrExit(ackMsg.BlockCounter == mLastBlockNum, PrepareStatusReport(kStatus_BadBlockCounter));
769 mPendingOutput = kAckEOFReceived;
771 mAwaitingResponse = false;
773 mState = kTransferDone;
779 void TransferSession::ResolveTransferControlOptions(const BitFlags<uint8_t, TransferControlFlags> & proposed)
781 // Must specify at least one synchronous option
782 if (!proposed.Has(kControl_SenderDrive) && !proposed.Has(kControl_ReceiverDrive))
784 PrepareStatusReport(kStatus_TransferMethodNotSupported);
788 // Ensure there are options supported by both nodes. Async gets priority.
789 // If there is only one common option, choose that one. Otherwise the application must pick.
790 BitFlags<uint8_t, TransferControlFlags> commonOpts;
791 commonOpts.SetRaw(proposed.Raw() & mSuppportedXferOpts.Raw());
792 if (commonOpts.Raw() == 0)
794 PrepareStatusReport(kStatus_TransferMethodNotSupported);
796 else if (commonOpts.HasOnly(kControl_Async))
798 mControlMode = kControl_Async;
800 else if (commonOpts.HasOnly(kControl_ReceiverDrive))
802 mControlMode = kControl_ReceiverDrive;
804 else if (commonOpts.HasOnly(kControl_SenderDrive))
806 mControlMode = kControl_SenderDrive;
810 CHIP_ERROR TransferSession::VerifyProposedMode(const BitFlags<uint8_t, TransferControlFlags> & proposed)
812 TransferControlFlags mode;
814 // Must specify only one mode in Accept messages
815 if (proposed.HasOnly(kControl_Async))
817 mode = kControl_Async;
819 else if (proposed.HasOnly(kControl_ReceiverDrive))
821 mode = kControl_ReceiverDrive;
823 else if (proposed.HasOnly(kControl_SenderDrive))
825 mode = kControl_SenderDrive;
829 PrepareStatusReport(kStatus_BadMessageContents);
830 return CHIP_ERROR_INTERNAL;
833 // Verify the proposed mode is supported by this instance
834 if (mSuppportedXferOpts.Has(mode))
840 PrepareStatusReport(kStatus_TransferMethodNotSupported);
841 return CHIP_ERROR_INTERNAL;
844 return CHIP_NO_ERROR;
847 void TransferSession::PrepareStatusReport(StatusCode code)
849 mStatusReportData.StatusCode = code;
851 Encoding::LittleEndian::PacketBufferWriter bbuf(chip::MessagePacketBuffer::New(kStatusReportMinSize), kStatusReportMinSize);
852 VerifyOrReturn(!bbuf.IsNull());
854 bbuf.Put16(static_cast<uint16_t>(Protocols::Common::StatusCode::Failure));
855 bbuf.Put32(Protocols::kProtocol_BDX);
856 bbuf.Put16(mStatusReportData.StatusCode);
858 mPendingMsgHandle = bbuf.Finalize();
859 if (mPendingMsgHandle.IsNull())
861 mPendingOutput = kInternalError;
865 CHIP_ERROR err = AttachHeader(Protocols::Common::MsgType::StatusReport, mPendingMsgHandle);
866 VerifyOrReturn(err == CHIP_NO_ERROR);
868 mPendingOutput = kMsgToSend;
871 mState = kErrorState;
872 mAwaitingResponse = false; // Prevent triggering timeout
875 bool TransferSession::IsTransferLengthDefinite()
877 return (mTransferLength > 0);
880 TransferSession::OutputEvent TransferSession::OutputEvent::TransferInitEvent(TransferInitData data, System::PacketBufferHandle msg)
882 OutputEvent event(kInitReceived);
883 event.MsgData = std::move(msg);
884 event.transferInitData = data;
890 * Convenience method for constructing an OutputEvent with TransferAcceptData that does not contain Metadata
892 TransferSession::OutputEvent TransferSession::OutputEvent::TransferAcceptEvent(TransferAcceptData data)
894 OutputEvent event(kAcceptReceived);
895 event.transferAcceptData = data;
900 * Convenience method for constructing an OutputEvent with TransferAcceptData that contains Metadata
902 TransferSession::OutputEvent TransferSession::OutputEvent::TransferAcceptEvent(TransferAcceptData data,
903 System::PacketBufferHandle msg)
905 OutputEvent event = TransferAcceptEvent(data);
906 event.MsgData = std::move(msg);
910 TransferSession::OutputEvent TransferSession::OutputEvent::BlockDataEvent(BlockData data, System::PacketBufferHandle msg)
912 OutputEvent event(kBlockReceived);
913 event.MsgData = std::move(msg);
914 event.blockdata = data;
920 * Convenience method for constructing an event with kInternalError or kOutputStatusReceived
922 TransferSession::OutputEvent TransferSession::OutputEvent::StatusReportEvent(OutputEventType type, StatusReportData data)
924 OutputEvent event(type);
925 event.statusData = data;