e3b583146511e026ded16710a2ea7666799df5d7
[platform/upstream/connectedhomeip.git] / src / protocols / bdx / BdxTransferSession.h
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 <core/CHIPError.h>
11 #include <protocols/bdx/BdxMessages.h>
12 #include <system/SystemPacketBuffer.h>
13 #include <transport/raw/MessageHeader.h>
14
15 namespace chip {
16 namespace bdx {
17
18 enum TransferRole : uint8_t
19 {
20     kRole_Receiver = 0,
21     kRole_Sender   = 1,
22 };
23
24 class DLL_EXPORT TransferSession
25 {
26 public:
27     enum OutputEventType : uint16_t
28     {
29         kNone = 0,
30         kMsgToSend,
31         kInitReceived,
32         kAcceptReceived,
33         kBlockReceived,
34         kQueryReceived,
35         kAckReceived,
36         kAckEOFReceived,
37         kStatusReceived,
38         kInternalError,
39         kTransferTimeout
40     };
41
42     struct TransferInitData
43     {
44         uint8_t TransferCtlFlagsRaw = 0;
45
46         uint16_t MaxBlockSize = 0;
47         uint64_t StartOffset  = 0;
48         uint64_t Length       = 0;
49
50         const uint8_t * FileDesignator = nullptr;
51         uint16_t FileDesLength         = 0;
52
53         // Additional metadata (optional, TLV format)
54         const uint8_t * Metadata = nullptr;
55         uint16_t MetadataLength  = 0;
56     };
57
58     struct TransferAcceptData
59     {
60         TransferControlFlags ControlMode;
61
62         uint16_t MaxBlockSize = 0;
63         uint64_t StartOffset  = 0; ///< Not used for SendAccept message
64         uint64_t Length       = 0; ///< Not used for SendAccept message
65
66         // Additional metadata (optional, TLV format)
67         const uint8_t * Metadata = nullptr;
68         uint16_t MetadataLength  = 0;
69     };
70
71     struct StatusReportData
72     {
73         uint16_t StatusCode;
74     };
75
76     struct BlockData
77     {
78         const uint8_t * Data = nullptr;
79         uint16_t Length      = 0;
80         bool IsEof           = false;
81     };
82
83     /**
84      * @brief
85      *   All output data processed by the TransferSession object will be passed to the caller using this struct via PollOutput().
86      *
87      *   NOTE: Some sub-structs may contain pointers to data in a PacketBuffer. In this case, the MsgData field MUST be populated
88      *         with a PacketBufferHandle that encapsulates the respective PacketBuffer, in order to ensure valid memory access.
89      */
90     struct OutputEvent
91     {
92         OutputEventType EventType;
93         System::PacketBufferHandle MsgData;
94         union
95         {
96             TransferInitData transferInitData;
97             TransferAcceptData transferAcceptData;
98             BlockData blockdata;
99             StatusReportData statusData;
100         };
101
102         OutputEvent() : EventType(kNone) { statusData = { kStatus_None }; }
103         OutputEvent(OutputEventType type) : EventType(type) { statusData = { kStatus_None }; }
104
105         static OutputEvent TransferInitEvent(TransferInitData data, System::PacketBufferHandle msg);
106         static OutputEvent TransferAcceptEvent(TransferAcceptData data);
107         static OutputEvent TransferAcceptEvent(TransferAcceptData data, System::PacketBufferHandle msg);
108         static OutputEvent BlockDataEvent(BlockData data, System::PacketBufferHandle msg);
109         static OutputEvent StatusReportEvent(OutputEventType type, StatusReportData data);
110     };
111
112     /**
113      * @brief
114      *   Indicates the presence of pending output and includes any data for the caller to take action on.
115      *
116      *   This method should be called frequently in order to be notified about any messages received. It should also be called after
117      *   most other methods in order to notify the user of any message that needs to be sent, or errors that occurred internally.
118      *
119      *   It is possible that consecutive calls to this method may emit different outputs depending on the state of the
120      *   TransferSession object.
121      *
122      *   Note that if the type outputted is kMsgToSend, it is assumed that the message will be send immediately, and the
123      *   session timeout timer will begin at curTimeMs.
124      *
125      *   See OutputEventType for all possible output event types.
126      *
127      * @param event     Reference to an OutputEvent struct that will be filled out with any pending output data
128      * @param curTimeMs Current time indicated by the number of milliseconds since some epoch defined by the platform
129      */
130     void PollOutput(OutputEvent & event, uint64_t curTimeMs);
131
132     /**
133      * @brief
134      *   Initializes the TransferSession object and prepares a TransferInit message (emitted via PollOutput()).
135      *
136      *   A TransferSession object must be initialized with either StartTransfer() or WaitForTransfer().
137      *
138      * @param role      Inidcates whether this object will be sending or receiving data
139      * @param initData  Data for initializing this object and for populating a TransferInit message
140      *                  The role parameter will determine whether to populate a ReceiveInit or SendInit
141      * @param timeoutMs The amount of time to wait for a response before considering the transfer failed (milliseconds)
142      * @param curTimeMs The current time since epoch in milliseconds. Needed to set a start time for the transfer timeout.
143      *
144      * @return CHIP_ERROR Result of initialization and preparation of a TransferInit message. May also indicate if the
145      *                    TransferSession object is unable to handle this request.
146      */
147     CHIP_ERROR StartTransfer(TransferRole role, const TransferInitData & initData, uint32_t timeoutMs);
148
149     /**
150      * @brief
151      *   Initialize the TransferSession object and prepare to receive a TransferInit message at some point.
152      *
153      *   A TransferSession object must be initialized with either StartTransfer() or WaitForTransfer().
154      *
155      * @param role            Inidcates whether this object will be sending or receiving data
156      * @param xferControlOpts Indicates all supported control modes. Used to respond to a TransferInit message
157      * @param maxBlockSize    The max Block size that this object supports.
158      * @param timeoutMs       The amount of time to wait for a response before considering the transfer failed (milliseconds)
159      *
160      * @return CHIP_ERROR Result of initialization. May also indicate if the TransferSession object is unable to handle this
161      *                    request.
162      */
163     CHIP_ERROR WaitForTransfer(TransferRole role, BitFlags<uint8_t, TransferControlFlags> xferControlOpts, uint16_t maxBlockSize,
164                                uint32_t timeoutMs);
165
166     /**
167      * @brief
168      *   Indicate that all transfer parameters are acceptable and prepare a SendAccept or ReceiveAccept message (depending on role).
169      *
170      * @param acceptData Data used to populate an Accept message (some fields may differ from the original Init message)
171      *
172      * @return CHIP_ERROR Result of preparation of an Accept message. May also indicate if the TransferSession object is unable to
173      *                    handle this request.
174      */
175     CHIP_ERROR AcceptTransfer(const TransferAcceptData & acceptData);
176
177     /**
178      * @brief
179      *   Reject a TransferInit message. Use Reset() to prepare this object for another transfer.
180      *
181      * @param reason A StatusCode indicating the reason for rejecting the transfer
182      *
183      * @return CHIP_ERROR The result of the preparation of a StatusReport message. May also indicate if the TransferSession object
184      *                    is unable to handle this request.
185      */
186     CHIP_ERROR RejectTransfer(StatusCode reason);
187
188     /**
189      * @brief
190      *   Prepare a BlockQuery message. The Block counter will be populated automatically.
191      *
192      * @return CHIP_ERROR The result of the preparation of a BlockQuery message. May also indicate if the TransferSession object
193      *                    is unable to handle this request.
194      */
195     CHIP_ERROR PrepareBlockQuery();
196
197     /**
198      * @brief
199      *   Prepare a Block message. The Block counter will be populated automatically.
200      *
201      * @param inData Contains data for filling out the Block message
202      *
203      * @return CHIP_ERROR The result of the preparation of a Block message. May also indicate if the TransferSession object
204      *                    is unable to handle this request.
205      */
206     CHIP_ERROR PrepareBlock(const BlockData & inData);
207
208     /**
209      * @brief
210      *   Prepare a BlockAck message. The Block counter will be populated automatically.
211      *
212      * @return CHIP_ERROR The result of the preparation of a BlockAck message. May also indicate if the TransferSession object
213      *                    is unable to handle this request.
214      */
215     CHIP_ERROR PrepareBlockAck();
216
217     /**
218      * @brief
219      *   Prematurely end a transfer with a StatusReport. Must still call Reset() to prepare the TransferSession for another
220      *   transfer.
221      *
222      * @param reason The StatusCode reason for ending the transfer.
223      *
224      * @return CHIP_ERROR May return an error if there is no transfer in progress.
225      */
226     CHIP_ERROR AbortTransfer(StatusCode reason);
227
228     /**
229      * @brief
230      *   Reset all TransferSession parameters. The TransferSession object must then be re-initialized with StartTransfer() or
231      *   WaitForTransfer().
232      */
233     void Reset();
234
235     /**
236      * @brief
237      *   Process a message intended for this TransferSession object.
238      *
239      * @param msg       A PacketBufferHandle pointing to the message buffer to process. May be BDX or StatusReport protocol.
240      * @param curTimeMs Current time indicated by the number of milliseconds since some epoch defined by the platform
241      *
242      * @return CHIP_ERROR Indicates any problems in decoding the message, or if the message is not of the BDX or StatusReport
243      *                    protocols.
244      */
245     CHIP_ERROR HandleMessageReceived(System::PacketBufferHandle msg, uint64_t curTimeMs);
246
247     TransferControlFlags GetControlMode() const { return mControlMode; }
248     uint64_t GetStartOffset() const { return mStartOffset; }
249     uint64_t GetTransferLength() const { return mTransferLength; }
250     uint16_t GetTransferBlockSize() const { return mTransferMaxBlockSize; }
251
252     TransferSession();
253
254 private:
255     enum TransferState : uint8_t
256     {
257         kUnitialized,
258         kAwaitingInitMsg,
259         kAwaitingAccept,
260         kNegotiateTransferParams,
261         kTransferInProgress,
262         kAwaitingEOFAck,
263         kReceivedEOF,
264         kTransferDone,
265         kErrorState,
266     };
267
268     // Incoming message handlers
269     CHIP_ERROR HandleBdxMessage(PayloadHeader & header, System::PacketBufferHandle msg);
270     CHIP_ERROR HandleStatusReportMessage(PayloadHeader & header, System::PacketBufferHandle msg);
271     void HandleTransferInit(MessageType msgType, System::PacketBufferHandle msgData);
272     void HandleReceiveAccept(System::PacketBufferHandle msgData);
273     void HandleSendAccept(System::PacketBufferHandle msgData);
274     void HandleBlockQuery(System::PacketBufferHandle msgData);
275     void HandleBlock(System::PacketBufferHandle msgData);
276     void HandleBlockEOF(System::PacketBufferHandle msgData);
277     void HandleBlockAck(System::PacketBufferHandle msgData);
278     void HandleBlockAckEOF(System::PacketBufferHandle msgData);
279
280     /**
281      * @brief
282      *   Used when handling a TransferInit message. Determines if there are any compatible Transfer control modes between the two
283      *   transfer peers.
284      */
285     void ResolveTransferControlOptions(const BitFlags<uint8_t, TransferControlFlags> & proposed);
286
287     /**
288      * @brief
289      *   Used when handling an Accept message. Verifies that the chosen control mode is compatible with the orignal supported modes.
290      */
291     CHIP_ERROR VerifyProposedMode(const BitFlags<uint8_t, TransferControlFlags> & proposed);
292
293     void PrepareStatusReport(StatusCode code);
294     bool IsTransferLengthDefinite();
295
296     OutputEventType mPendingOutput = kNone;
297     TransferState mState           = kUnitialized;
298     TransferRole mRole;
299
300     // Indicate supported options pre- transfer accept
301     BitFlags<uint8_t, TransferControlFlags> mSuppportedXferOpts;
302     uint16_t mMaxSupportedBlockSize = 0;
303
304     // Used to govern transfer once it has been accepted
305     TransferControlFlags mControlMode;
306     uint8_t mTransferVersion       = 0;
307     uint64_t mStartOffset          = 0; ///< 0 represents no offset
308     uint64_t mTransferLength       = 0; ///< 0 represents indefinite length
309     uint16_t mTransferMaxBlockSize = 0;
310
311     System::PacketBufferHandle mPendingMsgHandle;
312     StatusReportData mStatusReportData;
313     TransferInitData mTransferRequestData;
314     TransferAcceptData mTransferAcceptData;
315     BlockData mBlockEventData;
316
317     uint32_t mNumBytesProcessed = 0;
318
319     uint32_t mLastBlockNum = 0;
320     uint32_t mNextBlockNum = 0;
321     uint32_t mLastQueryNum = 0;
322     uint32_t mNextQueryNum = 0;
323
324     uint32_t mTimeoutMs          = 0;
325     uint64_t mTimeoutStartTimeMs = 0;
326     bool mShouldInitTimeoutStart = true;
327     bool mAwaitingResponse       = false;
328 };
329
330 } // namespace bdx
331 } // namespace chip