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.ClearAll();
73 void TransferSession::PollOutput(OutputEvent & event, uint64_t curTimeMs)
75 event = OutputEvent(OutputEventType::kNone);
77 if (mShouldInitTimeoutStart)
79 mTimeoutStartTimeMs = curTimeMs;
80 mShouldInitTimeoutStart = false;
83 if (mAwaitingResponse && ((curTimeMs - mTimeoutStartTimeMs) >= mTimeoutMs))
85 event = OutputEvent(OutputEventType::kTransferTimeout);
86 mState = TransferState::kErrorState;
87 mAwaitingResponse = false;
91 switch (mPendingOutput)
93 case OutputEventType::kNone:
94 event = OutputEvent(OutputEventType::kNone);
96 case OutputEventType::kInternalError:
97 event = OutputEvent::StatusReportEvent(OutputEventType::kInternalError, mStatusReportData);
99 case OutputEventType::kStatusReceived:
100 event = OutputEvent::StatusReportEvent(OutputEventType::kStatusReceived, mStatusReportData);
102 case OutputEventType::kMsgToSend:
103 event = OutputEvent(OutputEventType::kMsgToSend);
104 event.MsgData = std::move(mPendingMsgHandle);
105 mTimeoutStartTimeMs = curTimeMs;
107 case OutputEventType::kInitReceived:
108 event = OutputEvent::TransferInitEvent(mTransferRequestData, std::move(mPendingMsgHandle));
110 case OutputEventType::kAcceptReceived:
111 event = OutputEvent::TransferAcceptEvent(mTransferAcceptData, std::move(mPendingMsgHandle));
113 case OutputEventType::kQueryReceived:
114 event = OutputEvent(OutputEventType::kQueryReceived);
116 case OutputEventType::kBlockReceived:
117 event = OutputEvent::BlockDataEvent(mBlockEventData, std::move(mPendingMsgHandle));
119 case OutputEventType::kAckReceived:
120 event = OutputEvent(OutputEventType::kAckReceived);
122 case OutputEventType::kAckEOFReceived:
123 event = OutputEvent(OutputEventType::kAckEOFReceived);
126 event = OutputEvent(OutputEventType::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 == OutputEventType::kNone && mState == TransferState::kErrorState)
135 event = OutputEvent::StatusReportEvent(OutputEventType::kInternalError, mStatusReportData);
138 mPendingOutput = OutputEventType::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 == TransferState::kUnitialized, err = CHIP_ERROR_INCORRECT_STATE);
150 mTimeoutMs = timeoutMs;
152 // Set transfer parameters. They may be overridden later by an Accept message
153 mSuppportedXferOpts = initData.TransferCtlFlags;
154 mMaxSupportedBlockSize = initData.MaxBlockSize;
155 mStartOffset = initData.StartOffset;
156 mTransferLength = initData.Length;
158 // Prepare TransferInit message
159 initMsg.TransferCtlOptions = initData.TransferCtlFlags;
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 == TransferRole::kSender) ? MessageType::SendInit : MessageType::ReceiveInit;
173 err = AttachHeader(msgType, mPendingMsgHandle);
176 mState = TransferState::kAwaitingAccept;
177 mAwaitingResponse = true;
179 mPendingOutput = OutputEventType::kMsgToSend;
185 CHIP_ERROR TransferSession::WaitForTransfer(TransferRole role, BitFlags<TransferControlFlags> xferControlOpts,
186 uint16_t maxBlockSize, uint32_t timeoutMs)
188 CHIP_ERROR err = CHIP_NO_ERROR;
190 VerifyOrExit(mState == TransferState::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 = TransferState::kAwaitingInitMsg;
204 CHIP_ERROR TransferSession::AcceptTransfer(const TransferAcceptData & acceptData)
206 CHIP_ERROR err = CHIP_NO_ERROR;
207 System::PacketBufferHandle outMsgBuf;
208 const BitFlags<TransferControlFlags> proposedControlOpts(mTransferRequestData.TransferCtlFlags);
210 VerifyOrExit(mState == TransferState::kNegotiateTransferParams, err = CHIP_ERROR_INCORRECT_STATE);
211 VerifyOrExit(mPendingOutput == OutputEventType::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 VerifyOrExit(proposedControlOpts.Has(acceptData.ControlMode), err = CHIP_ERROR_INVALID_ARGUMENT);
216 VerifyOrExit(acceptData.MaxBlockSize <= mTransferRequestData.MaxBlockSize, err = CHIP_ERROR_INVALID_ARGUMENT);
218 mTransferMaxBlockSize = acceptData.MaxBlockSize;
220 if (mRole == TransferRole::kSender)
222 mStartOffset = acceptData.StartOffset;
223 mTransferLength = acceptData.Length;
225 ReceiveAccept acceptMsg;
226 acceptMsg.TransferCtlFlags.Set(acceptData.ControlMode);
227 acceptMsg.Version = mTransferVersion;
228 acceptMsg.MaxBlockSize = acceptData.MaxBlockSize;
229 acceptMsg.StartOffset = acceptData.StartOffset;
230 acceptMsg.Length = acceptData.Length;
231 acceptMsg.Metadata = acceptData.Metadata;
232 acceptMsg.MetadataLength = acceptData.MetadataLength;
234 err = WriteToPacketBuffer(acceptMsg, mPendingMsgHandle);
237 err = AttachHeader(MessageType::ReceiveAccept, mPendingMsgHandle);
242 SendAccept acceptMsg;
243 acceptMsg.TransferCtlFlags.Set(acceptData.ControlMode);
244 acceptMsg.Version = mTransferVersion;
245 acceptMsg.MaxBlockSize = acceptData.MaxBlockSize;
246 acceptMsg.Metadata = acceptData.Metadata;
247 acceptMsg.MetadataLength = acceptData.MetadataLength;
249 err = WriteToPacketBuffer(acceptMsg, mPendingMsgHandle);
252 err = AttachHeader(MessageType::SendAccept, mPendingMsgHandle);
256 mPendingOutput = OutputEventType::kMsgToSend;
258 mState = TransferState::kTransferInProgress;
260 if ((mRole == TransferRole::kReceiver && mControlMode == TransferControlFlags::kSenderDrive) ||
261 (mRole == TransferRole::kSender && mControlMode == TransferControlFlags::kReceiverDrive))
263 mAwaitingResponse = true;
270 CHIP_ERROR TransferSession::PrepareBlockQuery()
272 CHIP_ERROR err = CHIP_NO_ERROR;
275 VerifyOrExit(mState == TransferState::kTransferInProgress, err = CHIP_ERROR_INCORRECT_STATE);
276 VerifyOrExit(mRole == TransferRole::kReceiver, err = CHIP_ERROR_INCORRECT_STATE);
277 VerifyOrExit(mPendingOutput == OutputEventType::kNone, err = CHIP_ERROR_INCORRECT_STATE);
278 VerifyOrExit(!mAwaitingResponse, err = CHIP_ERROR_INCORRECT_STATE);
280 queryMsg.BlockCounter = mNextQueryNum;
282 err = WriteToPacketBuffer(queryMsg, mPendingMsgHandle);
285 err = AttachHeader(MessageType::BlockQuery, mPendingMsgHandle);
288 mPendingOutput = OutputEventType::kMsgToSend;
290 mAwaitingResponse = true;
291 mLastQueryNum = mNextQueryNum++;
297 CHIP_ERROR TransferSession::PrepareBlock(const BlockData & inData)
299 CHIP_ERROR err = CHIP_NO_ERROR;
303 VerifyOrExit(mState == TransferState::kTransferInProgress, err = CHIP_ERROR_INCORRECT_STATE);
304 VerifyOrExit(mRole == TransferRole::kSender, err = CHIP_ERROR_INCORRECT_STATE);
305 VerifyOrExit(mPendingOutput == OutputEventType::kNone, err = CHIP_ERROR_INCORRECT_STATE);
306 VerifyOrExit(!mAwaitingResponse, err = CHIP_ERROR_INCORRECT_STATE);
308 // Verify non-zero data is provided and is no longer than MaxBlockSize (BlockEOF may contain 0 length data)
309 VerifyOrExit((inData.Data != nullptr) && (inData.Length <= mTransferMaxBlockSize), err = CHIP_ERROR_INVALID_ARGUMENT);
311 blockMsg.BlockCounter = mNextBlockNum;
312 blockMsg.Data = inData.Data;
313 blockMsg.DataLength = inData.Length;
315 err = WriteToPacketBuffer(blockMsg, mPendingMsgHandle);
318 msgType = inData.IsEof ? MessageType::BlockEOF : MessageType::Block;
319 err = AttachHeader(msgType, mPendingMsgHandle);
322 mPendingOutput = OutputEventType::kMsgToSend;
324 if (msgType == MessageType::BlockEOF)
326 mState = TransferState::kAwaitingEOFAck;
329 mAwaitingResponse = true;
330 mLastBlockNum = mNextBlockNum++;
336 CHIP_ERROR TransferSession::PrepareBlockAck()
338 CHIP_ERROR err = CHIP_NO_ERROR;
339 CounterMessage ackMsg;
342 VerifyOrExit(mRole == TransferRole::kReceiver, err = CHIP_ERROR_INCORRECT_STATE);
343 VerifyOrExit((mState == TransferState::kTransferInProgress) || (mState == TransferState::kReceivedEOF),
344 err = CHIP_ERROR_INCORRECT_STATE);
345 VerifyOrExit(mPendingOutput == OutputEventType::kNone, err = CHIP_ERROR_INCORRECT_STATE);
347 ackMsg.BlockCounter = mLastBlockNum;
348 msgType = (mState == TransferState::kReceivedEOF) ? MessageType::BlockAckEOF : MessageType::BlockAck;
350 err = WriteToPacketBuffer(ackMsg, mPendingMsgHandle);
353 err = AttachHeader(msgType, mPendingMsgHandle);
356 if (mState == TransferState::kTransferInProgress)
358 if (mControlMode == TransferControlFlags::kSenderDrive)
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 == TransferState::kReceivedEOF)
368 mState = TransferState::kTransferDone;
369 mAwaitingResponse = false;
372 mPendingOutput = OutputEventType::kMsgToSend;
378 CHIP_ERROR TransferSession::AbortTransfer(StatusCode reason)
380 CHIP_ERROR err = CHIP_NO_ERROR;
382 VerifyOrExit((mState != TransferState::kUnitialized) && (mState != TransferState::kTransferDone) &&
383 (mState != TransferState::kErrorState),
384 err = CHIP_ERROR_INCORRECT_STATE);
386 PrepareStatusReport(reason);
392 void TransferSession::Reset()
394 mPendingOutput = OutputEventType::kNone;
395 mState = TransferState::kUnitialized;
396 mSuppportedXferOpts.ClearAll();
397 mTransferVersion = 0;
398 mMaxSupportedBlockSize = 0;
401 mTransferMaxBlockSize = 0;
403 mPendingMsgHandle = nullptr;
405 mNumBytesProcessed = 0;
412 mTimeoutStartTimeMs = 0;
413 mShouldInitTimeoutStart = true;
414 mAwaitingResponse = false;
417 CHIP_ERROR TransferSession::HandleMessageReceived(System::PacketBufferHandle msg, uint64_t curTimeMs)
419 CHIP_ERROR err = CHIP_NO_ERROR;
420 PayloadHeader payloadHeader;
422 VerifyOrExit(!msg.IsNull(), err = CHIP_ERROR_INVALID_ARGUMENT);
424 err = payloadHeader.DecodeAndConsume(msg);
427 if (payloadHeader.GetProtocolID() == Protocols::kProtocol_BDX)
429 err = HandleBdxMessage(payloadHeader, std::move(msg));
432 mTimeoutStartTimeMs = curTimeMs;
434 else if (payloadHeader.GetProtocolID() == Protocols::kProtocol_Protocol_Common &&
435 payloadHeader.GetMessageType() == static_cast<uint8_t>(Protocols::Common::MsgType::StatusReport))
437 err = HandleStatusReportMessage(payloadHeader, std::move(msg));
442 err = CHIP_ERROR_INVALID_MESSAGE_TYPE;
449 // Return CHIP_ERROR only if there was a problem decoding the message. Otherwise, call PrepareStatusReport().
450 CHIP_ERROR TransferSession::HandleBdxMessage(PayloadHeader & header, System::PacketBufferHandle msg)
452 CHIP_ERROR err = CHIP_NO_ERROR;
453 MessageType msgType = static_cast<MessageType>(header.GetMessageType());
455 VerifyOrExit(!msg.IsNull(), err = CHIP_ERROR_INVALID_ARGUMENT);
456 VerifyOrExit(mPendingOutput == OutputEventType::kNone, err = CHIP_ERROR_INCORRECT_STATE);
460 case MessageType::SendInit:
461 case MessageType::ReceiveInit:
462 HandleTransferInit(msgType, std::move(msg));
464 case MessageType::SendAccept:
465 HandleSendAccept(std::move(msg));
467 case MessageType::ReceiveAccept:
468 HandleReceiveAccept(std::move(msg));
470 case MessageType::BlockQuery:
471 HandleBlockQuery(std::move(msg));
473 case MessageType::Block:
474 HandleBlock(std::move(msg));
476 case MessageType::BlockEOF:
477 HandleBlockEOF(std::move(msg));
479 case MessageType::BlockAck:
480 HandleBlockAck(std::move(msg));
482 case MessageType::BlockAckEOF:
483 HandleBlockAckEOF(std::move(msg));
486 err = CHIP_ERROR_INVALID_MESSAGE_TYPE;
496 * Parse a StatusReport message and prepare to emit an OutputEvent with the message data.
498 * NOTE: BDX does not currently expect to ever use a "Success" general code, so it will be treated as an error along with any
501 CHIP_ERROR TransferSession::HandleStatusReportMessage(PayloadHeader & header, System::PacketBufferHandle msg)
503 VerifyOrReturnError(!msg.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
505 mState = TransferState::kErrorState;
506 mAwaitingResponse = false;
508 uint16_t generalCode = 0;
509 uint32_t protocolId = 0;
510 uint16_t protocolCode = 0;
511 Encoding::LittleEndian::Reader reader(msg->Start(), msg->DataLength());
512 ReturnErrorOnFailure(reader.Read16(&generalCode).Read32(&protocolId).Read16(&protocolCode).StatusCode());
513 VerifyOrReturnError((protocolId == Protocols::kProtocol_BDX), CHIP_ERROR_INVALID_MESSAGE_TYPE);
515 mStatusReportData.statusCode = static_cast<StatusCode>(protocolCode);
517 mPendingOutput = OutputEventType::kStatusReceived;
519 return CHIP_NO_ERROR;
522 void TransferSession::HandleTransferInit(MessageType msgType, System::PacketBufferHandle msgData)
524 CHIP_ERROR err = CHIP_NO_ERROR;
525 TransferInit transferInit;
527 VerifyOrExit(mState == TransferState::kAwaitingInitMsg, PrepareStatusReport(StatusCode::kServerBadState));
529 if (mRole == TransferRole::kSender)
531 VerifyOrExit(msgType == MessageType::ReceiveInit, PrepareStatusReport(StatusCode::kServerBadState));
535 VerifyOrExit(msgType == MessageType::SendInit, PrepareStatusReport(StatusCode::kServerBadState));
538 err = transferInit.Parse(msgData.Retain());
539 VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
541 ResolveTransferControlOptions(transferInit.TransferCtlOptions);
542 mTransferVersion = ::chip::min(kBdxVersion, transferInit.Version);
543 mTransferMaxBlockSize = ::chip::min(mMaxSupportedBlockSize, transferInit.MaxBlockSize);
545 // Accept for now, they may be changed or rejected by the peer if this is a ReceiveInit
546 mStartOffset = transferInit.StartOffset;
547 mTransferLength = transferInit.MaxLength;
549 // Store the Request data to share with the caller for verification
550 mTransferRequestData.TransferCtlFlags = transferInit.TransferCtlOptions;
551 mTransferRequestData.MaxBlockSize = transferInit.MaxBlockSize;
552 mTransferRequestData.StartOffset = transferInit.StartOffset;
553 mTransferRequestData.Length = transferInit.MaxLength;
554 mTransferRequestData.FileDesignator = transferInit.FileDesignator;
555 mTransferRequestData.FileDesLength = transferInit.FileDesLength;
556 mTransferRequestData.Metadata = transferInit.Metadata;
557 mTransferRequestData.MetadataLength = transferInit.MetadataLength;
559 mPendingMsgHandle = std::move(msgData);
560 mPendingOutput = OutputEventType::kInitReceived;
562 mState = TransferState::kNegotiateTransferParams;
568 void TransferSession::HandleReceiveAccept(System::PacketBufferHandle msgData)
570 CHIP_ERROR err = CHIP_NO_ERROR;
571 ReceiveAccept rcvAcceptMsg;
573 VerifyOrExit(mRole == TransferRole::kReceiver, PrepareStatusReport(StatusCode::kServerBadState));
574 VerifyOrExit(mState == TransferState::kAwaitingAccept, PrepareStatusReport(StatusCode::kServerBadState));
576 err = rcvAcceptMsg.Parse(msgData.Retain());
577 VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
579 // Verify that Accept parameters are compatible with the original proposed parameters
580 err = VerifyProposedMode(rcvAcceptMsg.TransferCtlFlags);
583 mTransferMaxBlockSize = rcvAcceptMsg.MaxBlockSize;
584 mStartOffset = rcvAcceptMsg.StartOffset;
585 mTransferLength = rcvAcceptMsg.Length;
587 // Note: if VerifyProposedMode() returned with no error, then mControlMode must match the proposed mode in the ReceiveAccept
589 mTransferAcceptData.ControlMode = mControlMode;
590 mTransferAcceptData.MaxBlockSize = rcvAcceptMsg.MaxBlockSize;
591 mTransferAcceptData.StartOffset = rcvAcceptMsg.StartOffset;
592 mTransferAcceptData.Length = rcvAcceptMsg.Length;
593 mTransferAcceptData.Metadata = rcvAcceptMsg.Metadata;
594 mTransferAcceptData.MetadataLength = rcvAcceptMsg.MetadataLength;
596 mPendingMsgHandle = std::move(msgData);
597 mPendingOutput = OutputEventType::kAcceptReceived;
599 mAwaitingResponse = (mControlMode == TransferControlFlags::kSenderDrive);
600 mState = TransferState::kTransferInProgress;
606 void TransferSession::HandleSendAccept(System::PacketBufferHandle msgData)
608 CHIP_ERROR err = CHIP_NO_ERROR;
609 SendAccept sendAcceptMsg;
611 VerifyOrExit(mRole == TransferRole::kSender, PrepareStatusReport(StatusCode::kServerBadState));
612 VerifyOrExit(mState == TransferState::kAwaitingAccept, PrepareStatusReport(StatusCode::kServerBadState));
614 err = sendAcceptMsg.Parse(msgData.Retain());
615 VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
617 // Verify that Accept parameters are compatible with the original proposed parameters
618 err = VerifyProposedMode(sendAcceptMsg.TransferCtlFlags);
621 // Note: if VerifyProposedMode() returned with no error, then mControlMode must match the proposed mode in the SendAccept
623 mTransferMaxBlockSize = sendAcceptMsg.MaxBlockSize;
625 mTransferAcceptData.ControlMode = mControlMode;
626 mTransferAcceptData.MaxBlockSize = sendAcceptMsg.MaxBlockSize;
627 mTransferAcceptData.StartOffset = mStartOffset; // Not included in SendAccept msg, so use member
628 mTransferAcceptData.Length = mTransferLength; // Not included in SendAccept msg, so use member
629 mTransferAcceptData.Metadata = sendAcceptMsg.Metadata;
630 mTransferAcceptData.MetadataLength = sendAcceptMsg.MetadataLength;
632 mPendingMsgHandle = std::move(msgData);
633 mPendingOutput = OutputEventType::kAcceptReceived;
635 mAwaitingResponse = (mControlMode == TransferControlFlags::kReceiverDrive);
636 mState = TransferState::kTransferInProgress;
642 void TransferSession::HandleBlockQuery(System::PacketBufferHandle msgData)
644 CHIP_ERROR err = CHIP_NO_ERROR;
647 VerifyOrExit(mRole == TransferRole::kSender, PrepareStatusReport(StatusCode::kServerBadState));
648 VerifyOrExit(mState == TransferState::kTransferInProgress, PrepareStatusReport(StatusCode::kServerBadState));
649 VerifyOrExit(mAwaitingResponse, PrepareStatusReport(StatusCode::kServerBadState));
651 err = query.Parse(std::move(msgData));
652 VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
654 VerifyOrExit(query.BlockCounter == mNextBlockNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
656 mPendingOutput = OutputEventType::kQueryReceived;
658 mAwaitingResponse = false;
659 mLastQueryNum = query.BlockCounter;
665 void TransferSession::HandleBlock(System::PacketBufferHandle msgData)
667 CHIP_ERROR err = CHIP_NO_ERROR;
670 VerifyOrExit(mRole == TransferRole::kReceiver, PrepareStatusReport(StatusCode::kServerBadState));
671 VerifyOrExit(mState == TransferState::kTransferInProgress, PrepareStatusReport(StatusCode::kServerBadState));
672 VerifyOrExit(mAwaitingResponse, PrepareStatusReport(StatusCode::kServerBadState));
674 err = blockMsg.Parse(msgData.Retain());
675 VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
677 VerifyOrExit(blockMsg.BlockCounter == mLastQueryNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
678 VerifyOrExit((blockMsg.DataLength > 0) && (blockMsg.DataLength <= mTransferMaxBlockSize),
679 PrepareStatusReport(StatusCode::kBadMessageContents));
681 if (IsTransferLengthDefinite())
683 VerifyOrExit(mNumBytesProcessed + blockMsg.DataLength <= mTransferLength, PrepareStatusReport(StatusCode::kLengthMismatch));
686 mBlockEventData.Data = blockMsg.Data;
687 mBlockEventData.Length = blockMsg.DataLength;
688 mBlockEventData.IsEof = false;
690 mPendingMsgHandle = std::move(msgData);
691 mPendingOutput = OutputEventType::kBlockReceived;
693 mNumBytesProcessed += blockMsg.DataLength;
694 mLastBlockNum = blockMsg.BlockCounter;
696 mAwaitingResponse = false;
702 void TransferSession::HandleBlockEOF(System::PacketBufferHandle msgData)
704 CHIP_ERROR err = CHIP_NO_ERROR;
705 BlockEOF blockEOFMsg;
707 VerifyOrExit(mRole == TransferRole::kReceiver, PrepareStatusReport(StatusCode::kServerBadState));
708 VerifyOrExit(mState == TransferState::kTransferInProgress, PrepareStatusReport(StatusCode::kServerBadState));
709 VerifyOrExit(mAwaitingResponse, PrepareStatusReport(StatusCode::kServerBadState));
711 err = blockEOFMsg.Parse(msgData.Retain());
712 VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
714 VerifyOrExit(blockEOFMsg.BlockCounter == mLastQueryNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
715 VerifyOrExit(blockEOFMsg.DataLength <= mTransferMaxBlockSize, PrepareStatusReport(StatusCode::kBadMessageContents));
717 mBlockEventData.Data = blockEOFMsg.Data;
718 mBlockEventData.Length = blockEOFMsg.DataLength;
719 mBlockEventData.IsEof = true;
721 mPendingMsgHandle = std::move(msgData);
722 mPendingOutput = OutputEventType::kBlockReceived;
724 mNumBytesProcessed += blockEOFMsg.DataLength;
725 mLastBlockNum = blockEOFMsg.BlockCounter;
727 mAwaitingResponse = false;
728 mState = TransferState::kReceivedEOF;
734 void TransferSession::HandleBlockAck(System::PacketBufferHandle msgData)
736 CHIP_ERROR err = CHIP_NO_ERROR;
739 VerifyOrExit(mRole == TransferRole::kSender, PrepareStatusReport(StatusCode::kServerBadState));
740 VerifyOrExit(mState == TransferState::kTransferInProgress, PrepareStatusReport(StatusCode::kServerBadState));
741 VerifyOrExit(mAwaitingResponse, PrepareStatusReport(StatusCode::kServerBadState));
743 err = ackMsg.Parse(std::move(msgData));
744 VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
745 VerifyOrExit(ackMsg.BlockCounter == mLastBlockNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
747 mPendingOutput = OutputEventType::kAckReceived;
749 // In Receiver Drive, the Receiver can send a BlockAck to indicate receipt of the message and reset the timeout.
750 // In this case, the Sender should wait to receive a BlockQuery next.
751 mAwaitingResponse = (mControlMode == TransferControlFlags::kReceiverDrive);
757 void TransferSession::HandleBlockAckEOF(System::PacketBufferHandle msgData)
759 CHIP_ERROR err = CHIP_NO_ERROR;
762 VerifyOrExit(mRole == TransferRole::kSender, PrepareStatusReport(StatusCode::kServerBadState));
763 VerifyOrExit(mState == TransferState::kAwaitingEOFAck, PrepareStatusReport(StatusCode::kServerBadState));
764 VerifyOrExit(mAwaitingResponse, PrepareStatusReport(StatusCode::kServerBadState));
766 err = ackMsg.Parse(std::move(msgData));
767 VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
768 VerifyOrExit(ackMsg.BlockCounter == mLastBlockNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
770 mPendingOutput = OutputEventType::kAckEOFReceived;
772 mAwaitingResponse = false;
774 mState = TransferState::kTransferDone;
780 void TransferSession::ResolveTransferControlOptions(const BitFlags<TransferControlFlags> & proposed)
782 // Must specify at least one synchronous option
784 if (!proposed.HasAny(TransferControlFlags::kSenderDrive, TransferControlFlags::kReceiverDrive))
786 PrepareStatusReport(StatusCode::kTransferMethodNotSupported);
790 // Ensure there are options supported by both nodes. Async gets priority.
791 // If there is only one common option, choose that one. Otherwise the application must pick.
792 const BitFlags<TransferControlFlags> commonOpts(proposed & mSuppportedXferOpts);
793 if (!commonOpts.HasAny())
795 PrepareStatusReport(StatusCode::kTransferMethodNotSupported);
797 else if (commonOpts.HasOnly(TransferControlFlags::kAsync))
799 mControlMode = TransferControlFlags::kAsync;
801 else if (commonOpts.HasOnly(TransferControlFlags::kReceiverDrive))
803 mControlMode = TransferControlFlags::kReceiverDrive;
805 else if (commonOpts.HasOnly(TransferControlFlags::kSenderDrive))
807 mControlMode = TransferControlFlags::kSenderDrive;
811 CHIP_ERROR TransferSession::VerifyProposedMode(const BitFlags<TransferControlFlags> & proposed)
813 TransferControlFlags mode;
815 // Must specify only one mode in Accept messages
816 if (proposed.HasOnly(TransferControlFlags::kAsync))
818 mode = TransferControlFlags::kAsync;
820 else if (proposed.HasOnly(TransferControlFlags::kReceiverDrive))
822 mode = TransferControlFlags::kReceiverDrive;
824 else if (proposed.HasOnly(TransferControlFlags::kSenderDrive))
826 mode = TransferControlFlags::kSenderDrive;
830 PrepareStatusReport(StatusCode::kBadMessageContents);
831 return CHIP_ERROR_INTERNAL;
834 // Verify the proposed mode is supported by this instance
835 if (mSuppportedXferOpts.Has(mode))
841 PrepareStatusReport(StatusCode::kTransferMethodNotSupported);
842 return CHIP_ERROR_INTERNAL;
845 return CHIP_NO_ERROR;
848 void TransferSession::PrepareStatusReport(StatusCode code)
850 mStatusReportData.statusCode = code;
852 Encoding::LittleEndian::PacketBufferWriter bbuf(chip::MessagePacketBuffer::New(kStatusReportMinSize), kStatusReportMinSize);
853 VerifyOrReturn(!bbuf.IsNull());
855 bbuf.Put16(static_cast<uint16_t>(Protocols::Common::StatusCode::Failure));
856 bbuf.Put32(Protocols::kProtocol_BDX);
857 bbuf.Put16(static_cast<uint16_t>(mStatusReportData.statusCode));
859 mPendingMsgHandle = bbuf.Finalize();
860 if (mPendingMsgHandle.IsNull())
862 mPendingOutput = OutputEventType::kInternalError;
866 CHIP_ERROR err = AttachHeader(Protocols::Common::MsgType::StatusReport, mPendingMsgHandle);
867 VerifyOrReturn(err == CHIP_NO_ERROR);
869 mPendingOutput = OutputEventType::kMsgToSend;
872 mState = TransferState::kErrorState;
873 mAwaitingResponse = false; // Prevent triggering timeout
876 bool TransferSession::IsTransferLengthDefinite()
878 return (mTransferLength > 0);
881 TransferSession::OutputEvent TransferSession::OutputEvent::TransferInitEvent(TransferInitData data, System::PacketBufferHandle msg)
883 OutputEvent event(OutputEventType::kInitReceived);
884 event.MsgData = std::move(msg);
885 event.transferInitData = data;
891 * Convenience method for constructing an OutputEvent with TransferAcceptData that does not contain Metadata
893 TransferSession::OutputEvent TransferSession::OutputEvent::TransferAcceptEvent(TransferAcceptData data)
895 OutputEvent event(OutputEventType::kAcceptReceived);
896 event.transferAcceptData = data;
901 * Convenience method for constructing an OutputEvent with TransferAcceptData that contains Metadata
903 TransferSession::OutputEvent TransferSession::OutputEvent::TransferAcceptEvent(TransferAcceptData data,
904 System::PacketBufferHandle msg)
906 OutputEvent event = TransferAcceptEvent(data);
907 event.MsgData = std::move(msg);
911 TransferSession::OutputEvent TransferSession::OutputEvent::BlockDataEvent(BlockData data, System::PacketBufferHandle msg)
913 OutputEvent event(OutputEventType::kBlockReceived);
914 event.MsgData = std::move(msg);
915 event.blockdata = data;
921 * Convenience method for constructing an event with kInternalError or kOutputStatusReceived
923 TransferSession::OutputEvent TransferSession::OutputEvent::StatusReportEvent(OutputEventType type, StatusReportData data)
925 OutputEvent event(type);
926 event.statusData = data;