LCOV - code coverage report
Current view: top level - protocols/bdx - BdxTransferSession.h (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 2 13 15.4 %
Date: 2024-02-15 08:20:41 Functions: 2 11 18.2 %

          Line data    Source code
       1             : /**
       2             :  *    @file
       3             :  *      This file defines a TransferSession state machine that contains the main logic governing a Bulk Data Transfer session. It
       4             :  *      provides APIs for starting a transfer or preparing to receive a transfer request, providing input to be processed, and
       5             :  *      accessing output data (including messages to be sent, message data received by the TransferSession, or state information).
       6             :  */
       7             : 
       8             : #pragma once
       9             : 
      10             : #include <lib/core/CHIPError.h>
      11             : #include <protocols/bdx/BdxMessages.h>
      12             : #include <system/SystemClock.h>
      13             : #include <system/SystemPacketBuffer.h>
      14             : #include <transport/raw/MessageHeader.h>
      15             : 
      16             : #include <type_traits>
      17             : 
      18             : namespace chip {
      19             : namespace bdx {
      20             : 
      21             : enum class TransferRole : uint8_t
      22             : {
      23             :     kReceiver = 0,
      24             :     kSender   = 1,
      25             : };
      26             : 
      27             : class DLL_EXPORT TransferSession
      28             : {
      29             : public:
      30             :     enum class OutputEventType : uint16_t
      31             :     {
      32             :         kNone = 0,
      33             :         kMsgToSend,
      34             :         kInitReceived,
      35             :         kAcceptReceived,
      36             :         kBlockReceived,
      37             :         kQueryReceived,
      38             :         kQueryWithSkipReceived,
      39             :         kAckReceived,
      40             :         kAckEOFReceived,
      41             :         kStatusReceived,
      42             :         kInternalError,
      43             :         kTransferTimeout
      44             :     };
      45             : 
      46             :     struct TransferInitData
      47             :     {
      48             :         TransferControlFlags TransferCtlFlags;
      49             : 
      50             :         uint16_t MaxBlockSize = 0;
      51             :         uint64_t StartOffset  = 0;
      52             :         uint64_t Length       = 0;
      53             : 
      54             :         const uint8_t * FileDesignator = nullptr;
      55             :         uint16_t FileDesLength         = 0;
      56             : 
      57             :         // Additional metadata (optional, TLV format)
      58             :         const uint8_t * Metadata = nullptr;
      59             :         size_t MetadataLength    = 0;
      60             :     };
      61             : 
      62             :     struct TransferAcceptData
      63             :     {
      64             :         TransferControlFlags ControlMode;
      65             : 
      66             :         uint16_t MaxBlockSize = 0;
      67             :         uint64_t StartOffset  = 0; ///< Not used for SendAccept message
      68             :         uint64_t Length       = 0; ///< Not used for SendAccept message
      69             : 
      70             :         // Additional metadata (optional, TLV format)
      71             :         const uint8_t * Metadata = nullptr;
      72             :         size_t MetadataLength    = 0;
      73             :     };
      74             : 
      75             :     struct StatusReportData
      76             :     {
      77             :         StatusCode statusCode;
      78             :     };
      79             : 
      80             :     struct BlockData
      81             :     {
      82             :         const uint8_t * Data  = nullptr;
      83             :         size_t Length         = 0;
      84             :         bool IsEof            = false;
      85             :         uint32_t BlockCounter = 0;
      86             :     };
      87             : 
      88             :     struct MessageTypeData
      89             :     {
      90             :         Protocols::Id ProtocolId; // Should only ever be SecureChannel or BDX
      91             :         uint8_t MessageType;
      92             : 
      93           9 :         MessageTypeData() : ProtocolId(Protocols::NotSpecified), MessageType(0) {}
      94             : 
      95           0 :         bool HasProtocol(Protocols::Id protocol) const { return ProtocolId == protocol; }
      96           0 :         bool HasMessageType(uint8_t type) const { return MessageType == type; }
      97             :         template <typename TMessageType, typename = std::enable_if_t<std::is_enum<TMessageType>::value>>
      98           0 :         bool HasMessageType(TMessageType type) const
      99             :         {
     100           0 :             return HasProtocol(Protocols::MessageTypeTraits<TMessageType>::ProtocolId()) && HasMessageType(to_underlying(type));
     101             :         }
     102             :     };
     103             : 
     104             :     struct TransferSkipData
     105             :     {
     106             :         uint64_t BytesToSkip = 0;
     107             :     };
     108             : 
     109             :     /**
     110             :      * @brief
     111             :      *   All output data processed by the TransferSession object will be passed to the caller using this struct via PollOutput().
     112             :      *
     113             :      *   NOTE: Some sub-structs may contain pointers to data in a PacketBuffer (see Blockdata). In this case, the MsgData field MUST
     114             :      *   be populated with a PacketBufferHandle that encapsulates the respective PacketBuffer, in order to ensure valid memory
     115             :      *   access.
     116             :      *
     117             :      *   NOTE: MsgData can contain messages that have been received or messages that should be sent by the caller. The underlying
     118             :      *   buffer will always start at the data, never at the payload header. Outgoing messages do not have a header prepended.
     119             :      */
     120             :     struct OutputEvent
     121             :     {
     122             :         OutputEventType EventType;
     123             :         System::PacketBufferHandle MsgData;
     124             :         union
     125             :         {
     126             :             TransferInitData transferInitData;
     127             :             TransferAcceptData transferAcceptData;
     128             :             BlockData blockdata;
     129             :             StatusReportData statusData;
     130             :             MessageTypeData msgTypeData;
     131             :             TransferSkipData bytesToSkip;
     132             :         };
     133             : 
     134           0 :         OutputEvent() : EventType(OutputEventType::kNone) { statusData = { StatusCode::kUnknown }; }
     135         368 :         OutputEvent(OutputEventType type) : EventType(type) { statusData = { StatusCode::kUnknown }; }
     136             : 
     137             :         const char * ToString(OutputEventType outputEventType);
     138             : 
     139             :         static OutputEvent TransferInitEvent(TransferInitData data, System::PacketBufferHandle msg);
     140             :         static OutputEvent TransferAcceptEvent(TransferAcceptData data);
     141             :         static OutputEvent TransferAcceptEvent(TransferAcceptData data, System::PacketBufferHandle msg);
     142             :         static OutputEvent BlockDataEvent(BlockData data, System::PacketBufferHandle msg);
     143             :         static OutputEvent StatusReportEvent(OutputEventType type, StatusReportData data);
     144             :         static OutputEvent MsgToSendEvent(MessageTypeData typeData, System::PacketBufferHandle msg);
     145             :         static OutputEvent QueryWithSkipEvent(TransferSkipData bytesToSkip);
     146             :     };
     147             : 
     148             :     /**
     149             :      * @brief
     150             :      *   Indicates the presence of pending output and includes any data for the caller to take action on.
     151             :      *
     152             :      *   This method should be called frequently in order to be notified about any messages received. It should also be called after
     153             :      *   most other methods in order to notify the user of any message that needs to be sent, or errors that occurred internally.
     154             :      *
     155             :      *   It is possible that consecutive calls to this method may emit different outputs depending on the state of the
     156             :      *   TransferSession object.
     157             :      *
     158             :      *   Note that if the type outputted is kMsgToSend, the caller is expected to send the message immediately, and the session
     159             :      *   timeout timer will begin at curTime.
     160             :      *
     161             :      *   See OutputEventType for all possible output event types.
     162             :      *
     163             :      * @param event     Reference to an OutputEvent struct that will be filled out with any pending output data
     164             :      * @param curTime   Current time
     165             :      */
     166             :     void PollOutput(OutputEvent & event, System::Clock::Timestamp curTime);
     167             : 
     168             :     /**
     169             :      * @brief
     170             :      *   Initializes the TransferSession object and prepares a TransferInit message (emitted via PollOutput()).
     171             :      *
     172             :      *   A TransferSession object must be initialized with either StartTransfer() or WaitForTransfer().
     173             :      *
     174             :      * @param role      Inidcates whether this object will be sending or receiving data
     175             :      * @param initData  Data for initializing this object and for populating a TransferInit message
     176             :      *                  The role parameter will determine whether to populate a ReceiveInit or SendInit
     177             :      * @param timeout   The amount of time to wait for a response before considering the transfer failed
     178             :      *
     179             :      * @return CHIP_ERROR Result of initialization and preparation of a TransferInit message. May also indicate if the
     180             :      *                    TransferSession object is unable to handle this request.
     181             :      */
     182             :     CHIP_ERROR StartTransfer(TransferRole role, const TransferInitData & initData, System::Clock::Timeout timeout);
     183             : 
     184             :     /**
     185             :      * @brief
     186             :      *   Initialize the TransferSession object and prepare to receive a TransferInit message at some point.
     187             :      *
     188             :      *   A TransferSession object must be initialized with either StartTransfer() or WaitForTransfer().
     189             :      *
     190             :      * @param role            Inidcates whether this object will be sending or receiving data
     191             :      * @param xferControlOpts Indicates all supported control modes. Used to respond to a TransferInit message
     192             :      * @param maxBlockSize    The max Block size that this object supports.
     193             :      * @param timeout         The amount of time to wait for a response before considering the transfer failed
     194             :      *
     195             :      * @return CHIP_ERROR Result of initialization. May also indicate if the TransferSession object is unable to handle this
     196             :      *                    request.
     197             :      */
     198             :     CHIP_ERROR WaitForTransfer(TransferRole role, BitFlags<TransferControlFlags> xferControlOpts, uint16_t maxBlockSize,
     199             :                                System::Clock::Timeout timeout);
     200             : 
     201             :     /**
     202             :      * @brief
     203             :      *   Indicate that all transfer parameters are acceptable and prepare a SendAccept or ReceiveAccept message (depending on role).
     204             :      *
     205             :      * @param acceptData Data used to populate an Accept message (some fields may differ from the original Init message)
     206             :      *
     207             :      * @return CHIP_ERROR Result of preparation of an Accept message. May also indicate if the TransferSession object is unable to
     208             :      *                    handle this request.
     209             :      */
     210             :     CHIP_ERROR AcceptTransfer(const TransferAcceptData & acceptData);
     211             : 
     212             :     /**
     213             :      * @brief
     214             :      *   Reject a TransferInit message. Use Reset() to prepare this object for another transfer.
     215             :      *
     216             :      * @param reason A StatusCode indicating the reason for rejecting the transfer
     217             :      *
     218             :      * @return CHIP_ERROR The result of the preparation of a StatusReport message. May also indicate if the TransferSession object
     219             :      *                    is unable to handle this request.
     220             :      */
     221             :     CHIP_ERROR RejectTransfer(StatusCode reason);
     222             : 
     223             :     /**
     224             :      * @brief
     225             :      *   Prepare a BlockQuery message. The Block counter will be populated automatically.
     226             :      *
     227             :      * @return CHIP_ERROR The result of the preparation of a BlockQuery message. May also indicate if the TransferSession object
     228             :      *                    is unable to handle this request.
     229             :      */
     230             :     CHIP_ERROR PrepareBlockQuery();
     231             : 
     232             :     /**
     233             :      * @brief
     234             :      *   Prepare a BlockQueryWithSkip message. The Block counter will be populated automatically.
     235             :      *
     236             :      * @param bytesToSkip Number of bytes to seek skip
     237             :      *
     238             :      * @return CHIP_ERROR The result of the preparation of a BlockQueryWithSkip message. May also indicate if the TransferSession
     239             :      * object is unable to handle this request.
     240             :      */
     241             :     CHIP_ERROR PrepareBlockQueryWithSkip(const uint64_t & bytesToSkip);
     242             : 
     243             :     /**
     244             :      * @brief
     245             :      *   Prepare a Block message. The Block counter will be populated automatically.
     246             :      *
     247             :      * @param inData Contains data for filling out the Block message
     248             :      *
     249             :      * @return CHIP_ERROR The result of the preparation of a Block message. May also indicate if the TransferSession object
     250             :      *                    is unable to handle this request.
     251             :      */
     252             :     CHIP_ERROR PrepareBlock(const BlockData & inData);
     253             : 
     254             :     /**
     255             :      * @brief
     256             :      *   Prepare a BlockAck message. The Block counter will be populated automatically.
     257             :      *
     258             :      * @return CHIP_ERROR The result of the preparation of a BlockAck message. May also indicate if the TransferSession object
     259             :      *                    is unable to handle this request.
     260             :      */
     261             :     CHIP_ERROR PrepareBlockAck();
     262             : 
     263             :     /**
     264             :      * @brief
     265             :      *   Prematurely end a transfer with a StatusReport. Must still call Reset() to prepare the TransferSession for another
     266             :      *   transfer.
     267             :      *
     268             :      * @param reason The StatusCode reason for ending the transfer.
     269             :      *
     270             :      * @return CHIP_ERROR May return an error if there is no transfer in progress.
     271             :      */
     272             :     CHIP_ERROR AbortTransfer(StatusCode reason);
     273             : 
     274             :     /**
     275             :      * @brief
     276             :      *   Reset all TransferSession parameters. The TransferSession object must then be re-initialized with StartTransfer() or
     277             :      *   WaitForTransfer().
     278             :      */
     279             :     void Reset();
     280             : 
     281             :     /**
     282             :      * @brief
     283             :      *   Process a message intended for this TransferSession object.
     284             :      *
     285             :      * @param payloadHeader A PayloadHeader containing the Protocol type and Message Type
     286             :      * @param msg           A PacketBufferHandle pointing to the message buffer to process. May be BDX or StatusReport protocol.
     287             :      *                      Buffer is expected to start at data (not header).
     288             :      * @param curTime       Current time
     289             :      *
     290             :      * @return CHIP_ERROR Indicates any problems in decoding the message, or if the message is not of the BDX or StatusReport
     291             :      *                    protocols.
     292             :      */
     293             :     CHIP_ERROR HandleMessageReceived(const PayloadHeader & payloadHeader, System::PacketBufferHandle msg,
     294             :                                      System::Clock::Timestamp curTime);
     295             : 
     296             :     TransferControlFlags GetControlMode() const { return mControlMode; }
     297           0 :     uint64_t GetStartOffset() const { return mStartOffset; }
     298           0 :     uint64_t GetTransferLength() const { return mTransferLength; }
     299           0 :     uint16_t GetTransferBlockSize() const { return mTransferMaxBlockSize; }
     300             :     uint32_t GetNextBlockNum() const { return mNextBlockNum; }
     301             :     uint32_t GetNextQueryNum() const { return mNextQueryNum; }
     302             :     size_t GetNumBytesProcessed() const { return mNumBytesProcessed; }
     303           0 :     const uint8_t * GetFileDesignator(uint16_t & fileDesignatorLen) const
     304             :     {
     305           0 :         fileDesignatorLen = mTransferRequestData.FileDesLength;
     306           0 :         return mTransferRequestData.FileDesignator;
     307             :     }
     308             : 
     309             :     TransferSession();
     310             : 
     311             : private:
     312             :     enum class TransferState : uint8_t
     313             :     {
     314             :         kUnitialized,
     315             :         kAwaitingInitMsg,
     316             :         kAwaitingAccept,
     317             :         kNegotiateTransferParams,
     318             :         kTransferInProgress,
     319             :         kAwaitingEOFAck,
     320             :         kReceivedEOF,
     321             :         kTransferDone,
     322             :         kErrorState,
     323             :     };
     324             : 
     325             :     // Incoming message handlers
     326             :     CHIP_ERROR HandleBdxMessage(const PayloadHeader & header, System::PacketBufferHandle msg);
     327             :     CHIP_ERROR HandleStatusReportMessage(const PayloadHeader & header, System::PacketBufferHandle msg);
     328             :     void HandleTransferInit(MessageType msgType, System::PacketBufferHandle msgData);
     329             :     void HandleReceiveAccept(System::PacketBufferHandle msgData);
     330             :     void HandleSendAccept(System::PacketBufferHandle msgData);
     331             :     void HandleBlockQuery(System::PacketBufferHandle msgData);
     332             :     void HandleBlockQueryWithSkip(System::PacketBufferHandle msgData);
     333             :     void HandleBlock(System::PacketBufferHandle msgData);
     334             :     void HandleBlockEOF(System::PacketBufferHandle msgData);
     335             :     void HandleBlockAck(System::PacketBufferHandle msgData);
     336             :     void HandleBlockAckEOF(System::PacketBufferHandle msgData);
     337             : 
     338             :     /**
     339             :      * @brief
     340             :      *   Used when handling a TransferInit message. Determines if there are any compatible Transfer control modes between the two
     341             :      *   transfer peers.
     342             :      */
     343             :     void ResolveTransferControlOptions(const BitFlags<TransferControlFlags> & proposed);
     344             : 
     345             :     /**
     346             :      * @brief
     347             :      *   Used when handling an Accept message. Verifies that the chosen control mode is compatible with the orignal supported modes.
     348             :      */
     349             :     CHIP_ERROR VerifyProposedMode(const BitFlags<TransferControlFlags> & proposed);
     350             : 
     351             :     void PrepareStatusReport(StatusCode code);
     352             :     bool IsTransferLengthDefinite() const;
     353             : 
     354             :     OutputEventType mPendingOutput = OutputEventType::kNone;
     355             :     TransferState mState           = TransferState::kUnitialized;
     356             :     TransferRole mRole;
     357             : 
     358             :     // Indicate supported options pre- transfer accept
     359             :     BitFlags<TransferControlFlags> mSuppportedXferOpts;
     360             :     uint16_t mMaxSupportedBlockSize = 0;
     361             : 
     362             :     // Used to govern transfer once it has been accepted
     363             :     TransferControlFlags mControlMode;
     364             :     uint8_t mTransferVersion       = 0;
     365             :     uint64_t mStartOffset          = 0; ///< 0 represents no offset
     366             :     uint64_t mTransferLength       = 0; ///< 0 represents indefinite length
     367             :     uint16_t mTransferMaxBlockSize = 0;
     368             : 
     369             :     // Used to store event data before it is emitted via PollOutput()
     370             :     System::PacketBufferHandle mPendingMsgHandle;
     371             :     StatusReportData mStatusReportData;
     372             :     TransferInitData mTransferRequestData;
     373             :     TransferAcceptData mTransferAcceptData;
     374             :     BlockData mBlockEventData;
     375             :     MessageTypeData mMsgTypeData;
     376             :     TransferSkipData mBytesToSkip;
     377             : 
     378             :     size_t mNumBytesProcessed = 0;
     379             : 
     380             :     uint32_t mLastBlockNum = 0;
     381             :     uint32_t mNextBlockNum = 0;
     382             :     uint32_t mLastQueryNum = 0;
     383             :     uint32_t mNextQueryNum = 0;
     384             : 
     385             :     System::Clock::Timeout mTimeout            = System::Clock::kZero;
     386             :     System::Clock::Timestamp mTimeoutStartTime = System::Clock::kZero;
     387             :     bool mShouldInitTimeoutStart               = true;
     388             :     bool mAwaitingResponse                     = false;
     389             : };
     390             : 
     391             : } // namespace bdx
     392             : } // namespace chip

Generated by: LCOV version 1.14