• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "nstackx_dfile_transfer.h"
17 
18 #include "nstackx_dfile_retransmission.h"
19 #include "nstackx_congestion.h"
20 #include "nstackx_dfile.h"
21 #include "nstackx_dfile_frame.h"
22 #include "nstackx_dfile_session.h"
23 #include "nstackx_dfile_mp.h"
24 #include "nstackx_error.h"
25 #include "nstackx_file_manager.h"
26 #include "nstackx_list.h"
27 #include "nstackx_dfile_log.h"
28 #include "nstackx_timer.h"
29 #include "nstackx_util.h"
30 #include "nstackx_dfile_dfx.h"
31 #include "securec.h"
32 
33 #define TAG "nStackXDFile"
34 
35 #define NSTACKX_DFILE_BACKOFF_FACTOR 2
36 #define TRANSFER_DONE_ACK_REPEATED_TIMES 3
37 #define RADIO_DIVISOR 95
38 #define RADIO_DIVIDEND 100
39 
40 static uint64_t GetTotalFrameCount(DFileTrans *dFileTrans);
41 
NstackAdjustAckIntervalRatio(uint64_t num)42 static inline uint64_t NstackAdjustAckIntervalRatio(uint64_t num)
43 {
44     return num * RADIO_DIVISOR / RADIO_DIVIDEND; /* (num) * 9 / 10 means ratio is 0.9 times */
45 }
46 
47 static void ReceiverFsm(DFileTrans *dFileTrans);
48 static void SetSendState(DFileTrans *dFileTrans, DFileSendState nextState);
49 static void SetReceiveState(DFileTrans *dFileTrans, DFileReceiveState nextState);
50 
DFileTransSendFiles(DFileTrans * trans,FileListInfo * fileListInfo)51 int32_t DFileTransSendFiles(DFileTrans *trans, FileListInfo *fileListInfo)
52 {
53     DFILE_LOGI(TAG, "transId %hu, fileNum %u", trans->transId, fileListInfo->fileNum);
54     return FileListSetSendFileList(trans->fileList, fileListInfo);
55 }
56 
DFileTransAddExtraInfo(DFileTrans * trans,uint16_t pathType,uint8_t noticeFileNameType,char * userData)57 int32_t DFileTransAddExtraInfo(DFileTrans *trans, uint16_t pathType, uint8_t noticeFileNameType, char *userData)
58 {
59     DFILE_LOGI(TAG, "transId %hu, pathType %hu", trans->transId, pathType);
60     return FileListAddExtraInfo(trans->fileList, pathType, noticeFileNameType, userData);
61 }
62 
GetSendStateMessage(DFileSendState state)63 static const char *GetSendStateMessage(DFileSendState state)
64 {
65     static const char *message[] = {
66         [STATE_SEND_FILE_INIT] = "send file init",
67         [STATE_SEND_FILE_HEADER_ONGOING] = "send file header ongoing",
68         [STATE_WAIT_FOR_FILE_HEADER_CONFIRM] = "wait for file header confirm",
69         [STATE_SEND_FILE_DATA_ONGOING] = "send file data ongoing",
70         [STATE_WAIT_FOR_FILE_TRANSFER_DONE_FRAME] = "wait for file transfer done frame",
71         [STATE_SEND_FILE_TRANSFER_DONE_ACK] = "send file transfer done ack",
72         [STATE_SEND_FILE_DONE] = "send file done",
73         [STATE_SEND_FILE_FAIL] = "send file fail",
74     };
75 
76     for (uint32_t i = 0; i < sizeof(message) / sizeof(message[0]); i++) {
77         if (state == i) {
78             return message[i];
79         }
80     }
81     return "unknown";
82 }
83 
GetReceiveStateMessage(DFileReceiveState state)84 static const char *GetReceiveStateMessage(DFileReceiveState state)
85 {
86     static const char *message[] = {
87         [STATE_RECEIVE_FILE_INIT] = "receive file init",
88         [STATE_RECEIVE_FILE_HEADER_ONGOING] = "receive file header ongoing",
89         [STATE_SEND_FILE_HEADER_CONFIRM] = "send file header confirm",
90         [STATE_RECEIVE_FILE_DATA_ONGOING] = "receive file data ongoing",
91         [STATE_SEND_FILE_DATA_ACK] = "send file data ack",
92         [STATE_SEND_FILE_TRANSFER_DONE] = "send file transfer done",
93         [STATE_WAIT_FOR_FILE_TRANSFER_DONE_ACK] = "wait for file transfer done ack",
94         [STATE_RECEIVE_FILE_DONE] = "receive file done",
95         [STATE_RECEIVE_FILE_FAIL] = "receive file fail",
96     };
97 
98     for (uint32_t i = 0; i < sizeof(message) / sizeof(message[0]); i++) {
99         if (state == i) {
100             return message[i];
101         }
102     }
103     return "unknown";
104 }
105 
GetErrorMessage(DFileTransErrorCode errorCode)106 static const char *GetErrorMessage(DFileTransErrorCode errorCode)
107 {
108     static const char *message[] = {
109         [DFILE_TRANS_NO_ERROR] = "No error",
110         [DFILE_TRANS_SOCKET_ERROR] = "Socket IO error",
111         [DFILE_TRANS_INTERNAL_ERROR] = "Internal error",
112         [DFILE_TRANS_FILE_HEADER_CONFIRM_TIMEOUT] = "Sender wait for HEADER CONFIRM frame timeout",
113         [DFILE_TRANS_FILE_DATA_ACK_TIMEOUT] = "Sender wait for heart beat (DATA ACK frame) timeout",
114         [DFILE_TRANS_TRANSFER_DONE_TIMEOUT] = "Sender wait for TRANSFER DONE frame timeout",
115         [DFILE_TRANS_FILE_HEADER_TIMEOUT] = "Receiver wait for HEADER frame timeout (partially received)",
116         [DFILE_TRANS_FILE_DATA_TIMEOUT] = "Receive file data timeout (partially received)",
117         [DFILE_TRANS_TRANSFER_DONE_ACK_TIMEOUT] = "Receiver wait for TRANSFER DONE ACK frame timeout",
118         [DFILE_TRANS_FILE_SEND_TASK_ERROR] = "Send task error",
119         [DFILE_TRANS_FILE_RECEIVE_TASK_ERROR] = "Receive task error",
120         [DFILE_TRANS_FILE_WRITE_FAIL] = "Write file list fail",
121         [DFILE_TRANS_FILE_RENAME_FAIL] = "Rename file failed",
122     };
123 
124     for (uint32_t i = 0; i < sizeof(message) / sizeof(message[0]); i++) {
125         if (errorCode == i) {
126             return message[i];
127         }
128     }
129     return "unknown";
130 }
131 
GetElapseTime(const struct timespec * ts)132 static inline uint32_t GetElapseTime(const struct timespec *ts)
133 {
134     struct timespec now;
135     ClockGetTime(CLOCK_MONOTONIC, &now);
136     return GetTimeDiffMs(&now, ts);
137 }
138 
ConvertTransError(DFileTransErrorCode errorCode)139 static int32_t ConvertTransError(DFileTransErrorCode errorCode)
140 {
141     switch (errorCode) {
142         case DFILE_TRANS_NO_ERROR:
143             return NSTACKX_EOK;
144         case DFILE_TRANS_SOCKET_ERROR:
145         case DFILE_TRANS_INTERNAL_ERROR:
146         case DFILE_TRANS_FILE_SEND_TASK_ERROR:
147         case DFILE_TRANS_FILE_RECEIVE_TASK_ERROR:
148         case DFILE_TRANS_FILE_WRITE_FAIL:
149         case DFILE_TRANS_FILE_RENAME_FAIL:
150             return NSTACKX_EFAILED;
151         case DFILE_TRANS_FILE_HEADER_CONFIRM_TIMEOUT:
152         case DFILE_TRANS_FILE_DATA_ACK_TIMEOUT:
153         case DFILE_TRANS_TRANSFER_DONE_TIMEOUT:
154         case DFILE_TRANS_FILE_HEADER_TIMEOUT:
155         case DFILE_TRANS_FILE_DATA_TIMEOUT:
156         case DFILE_TRANS_TRANSFER_DONE_ACK_TIMEOUT:
157             return NSTACKX_ETIMEOUT;
158         default:
159             break;
160     }
161 
162     return NSTACKX_EFAILED;
163 }
164 
165 
ReviewSuccessMsg(const DFileTrans * dFileTrans,DFileTransMsgType * msgType,DFileTransMsg * msg,char * files[])166 void ReviewSuccessMsg(const DFileTrans *dFileTrans, DFileTransMsgType *msgType,
167     DFileTransMsg *msg, char *files[])
168 {
169     if (*msgType != DFILE_TRANS_MSG_FILE_SENT && *msgType != DFILE_TRANS_MSG_FILE_RECEIVED) {
170         return;
171     }
172     if (*msgType == DFILE_TRANS_MSG_FILE_SENT) {
173         if (msg->fileList.fileNum == 0) {
174             msg->fileList.fileNum = NSTACKX_DFILE_MAX_FILE_NUM;
175             FileListGetNames(dFileTrans->fileList, files, &msg->fileList.fileNum,
176                              dFileTrans->fileList->noticeFileNameType);
177             msg->fileList.files = (const char **)files;
178             msg->errorCode = NSTACKX_EFAILED;
179             /*
180              * Both DFILE_TRANS_MSG_FILE_SENT and DFILE_TRANS_MSG_FILE_SEND_FAIL are ending status, which means that
181              * the trans will be destroyed in DTransMsgReceiver(). So DFILE_TRANS_MSG_FILE_SENT can be changed to
182              * DFILE_TRANS_MSG_FILE_SEND_FAIL directly.
183              */
184             *msgType = DFILE_TRANS_MSG_FILE_SEND_FAIL;
185             DFILE_LOGI(TAG, "transId %u: no success file", dFileTrans->transId);
186         }
187     }
188     if (*msgType == DFILE_TRANS_MSG_FILE_RECEIVED) {
189         if (msg->fileList.fileNum == 0) {
190             msg->fileList.fileNum = NSTACKX_DFILE_MAX_FILE_NUM;
191             FileListGetNames(dFileTrans->fileList, files, &msg->fileList.fileNum, NOTICE_FILE_NAME_TYPE);
192             msg->fileList.files = (const char **)files;
193             msg->errorCode = NSTACKX_EFAILED;
194             /*
195              * DFILE_TRANS_MSG_FILE_RECEIVED isn't an ending status, so it can't be changed to the ending status
196              * DFILE_TRANS_MSG_FILE_RECEIVE_FAIL directly.
197              */
198             *msgType = DFILE_TRANS_MSG_FILE_RECEIVED_TO_FAIL;
199             DFILE_LOGI(TAG, "transId %u: no success file", dFileTrans->transId);
200         }
201     }
202 }
203 
NotifyTransProgress(DFileTrans * dFileTrans,uint64_t bytesTransferred)204 static void NotifyTransProgress(DFileTrans *dFileTrans, uint64_t bytesTransferred)
205 {
206     DFileTransMsg transMsg;
207     char *files[NSTACKX_DFILE_MAX_FILE_NUM] = {0};
208     (void)memset_s(&transMsg, sizeof(transMsg), 0, sizeof(transMsg));
209     transMsg.transferUpdate.transId = dFileTrans->transId;
210     transMsg.transferUpdate.totalBytes = dFileTrans->totalBytes;
211     transMsg.transferUpdate.bytesTransferred = bytesTransferred;
212     transMsg.fileList.fileNum = NSTACKX_DFILE_MAX_FILE_NUM;
213     transMsg.fileList.userData = dFileTrans->fileList->userData;
214     transMsg.fileList.transId = dFileTrans->transId;
215     FileListGetNames(dFileTrans->fileList, files, &transMsg.fileList.fileNum, NOTICE_FILE_NAME_TYPE);
216     transMsg.fileList.files = (const char **)files;
217     dFileTrans->msgReceiver(dFileTrans, DFILE_TRANS_MSG_IN_PROGRESS, &transMsg);
218 }
219 
NotifyTransMsg(DFileTrans * dFileTrans,DFileTransMsgType msgType)220 static void NotifyTransMsg(DFileTrans *dFileTrans, DFileTransMsgType msgType)
221 {
222     if (dFileTrans->msgReceiver == NULL) {
223         return;
224     }
225 
226     DFileTransMsg transMsg;
227     char *files[NSTACKX_DFILE_MAX_FILE_NUM] = {0};
228     (void)memset_s(&transMsg, sizeof(transMsg), 0, sizeof(transMsg));
229     transMsg.fileList.fileNum = NSTACKX_DFILE_MAX_FILE_NUM;
230     transMsg.fileList.userData = dFileTrans->fileList->userData;
231     transMsg.fileList.transId = dFileTrans->transId;
232 
233     switch (msgType) {
234         case DFILE_TRANS_MSG_FILE_LIST_RECEIVED:
235             FileListGetNames(dFileTrans->fileList, files, &transMsg.fileList.fileNum, NOTICE_FILE_NAME_TYPE);
236             transMsg.fileList.files = (const char **)files;
237             break;
238         case DFILE_TRANS_MSG_FILE_RECEIVED:
239             FileListGetReceivedFiles(dFileTrans->fileList, files, &transMsg.fileList.fileNum);
240             transMsg.fileList.files = (const char **)files;
241             if (transMsg.fileList.fileNum == dFileTrans->fileList->num) {
242                 NotifyTransProgress(dFileTrans, dFileTrans->totalBytes);
243             }
244             break;
245         case DFILE_TRANS_MSG_FILE_SENT:
246             FileListGetSentFiles(dFileTrans->fileList, files, &transMsg.fileList.fileNum);
247             transMsg.fileList.files = (const char **)files;
248             break;
249         case DFILE_TRANS_MSG_FILE_RECEIVE_FAIL:
250             /*
251              * May encounter failure durinng HEADER stage, and not all the file names are received. In this case, we
252              * don't provide the file list.
253              */
254             transMsg.fileList.fileNum = 0;
255             if (FileListAllFileNameReceived(dFileTrans->fileList)) {
256                 transMsg.fileList.fileNum = NSTACKX_DFILE_MAX_FILE_NUM;
257                 FileListGetNames(dFileTrans->fileList, files, &transMsg.fileList.fileNum, NOTICE_FILE_NAME_TYPE);
258                 transMsg.fileList.files = (const char **)files;
259             }
260             transMsg.errorCode = ConvertTransError(dFileTrans->errorCode);
261             break;
262         case DFILE_TRANS_MSG_FILE_SEND_FAIL:
263             FileListGetNames(dFileTrans->fileList, files, &transMsg.fileList.fileNum,
264                              dFileTrans->fileList->noticeFileNameType);
265             transMsg.fileList.files = (const char **)files;
266             transMsg.errorCode = ConvertTransError(dFileTrans->errorCode);
267             break;
268         default:
269             break;
270     }
271     ReviewSuccessMsg(dFileTrans, &msgType, &transMsg, files);
272     dFileTrans->msgReceiver(dFileTrans, msgType, &transMsg);
273 }
274 
275 /* To post message when come to end */
DFileTransNotifyEndMsg(DFileTrans * dFileTrans)276 static void DFileTransNotifyEndMsg(DFileTrans *dFileTrans)
277 {
278     if (dFileTrans->isSender) {
279         if (dFileTrans->sendState == STATE_SEND_FILE_FAIL) {
280             NotifyTransMsg(dFileTrans, DFILE_TRANS_MSG_FILE_SEND_FAIL);
281         } else if (dFileTrans->sendState == STATE_SEND_FILE_DONE) {
282             NotifyTransMsg(dFileTrans, DFILE_TRANS_MSG_FILE_SENT);
283         }
284     } else {
285         if (dFileTrans->recvState == STATE_RECEIVE_FILE_FAIL) {
286             NotifyTransMsg(dFileTrans, DFILE_TRANS_MSG_FILE_RECEIVE_FAIL);
287         } else if (dFileTrans->recvState == STATE_RECEIVE_FILE_DONE) {
288             NotifyTransMsg(dFileTrans, DFILE_TRANS_MSG_END);
289         }
290     }
291 }
292 
DFileTransStateFinished(DFileTrans * dFileTrans)293 static uint8_t DFileTransStateFinished(DFileTrans *dFileTrans)
294 {
295     if ((dFileTrans->isSender &&
296         (dFileTrans->sendState == STATE_SEND_FILE_FAIL || dFileTrans->sendState == STATE_SEND_FILE_DONE)) ||
297         (!dFileTrans->isSender &&
298         (dFileTrans->recvState == STATE_RECEIVE_FILE_FAIL || dFileTrans->recvState == STATE_RECEIVE_FILE_DONE))) {
299         return NSTACKX_TRUE;
300     }
301 
302     return NSTACKX_FALSE;
303 }
304 
SendFrame(DFileTrans * dFileTrans,uint8_t * frame,size_t frameLength,DFileSendState * nextSend,DFileReceiveState * nextRecv)305 int32_t SendFrame(DFileTrans *dFileTrans, uint8_t *frame, size_t frameLength, DFileSendState *nextSend,
306     DFileReceiveState *nextRecv)
307 {
308     SetDfileFrameTransID((DFileFrame *)frame, dFileTrans->transId);
309     int32_t ret = dFileTrans->writeHandle(frame, frameLength, dFileTrans->context);
310     if (ret != (int32_t)frameLength) {
311         /* Data was not sent. */
312         if (ret != NSTACKX_EAGAIN) {
313             if (dFileTrans->isSender && nextSend != NULL) {
314                 *nextSend = STATE_SEND_FILE_FAIL;
315             }
316             if (!dFileTrans->isSender && nextRecv != NULL) {
317                 *nextRecv = STATE_RECEIVE_FILE_FAIL;
318             }
319             ret = NSTACKX_EFAILED;
320             dFileTrans->errorCode = DFILE_TRANS_SOCKET_ERROR;
321         }
322         return ret;
323     }
324     return NSTACKX_EOK;
325 }
326 
ExtendTimeout(uint32_t * timeout,uint32_t maxTimeout)327 static inline void ExtendTimeout(uint32_t *timeout, uint32_t maxTimeout)
328 {
329     if (*timeout < maxTimeout) {
330         *timeout *= NSTACKX_DFILE_BACKOFF_FACTOR;
331         if (*timeout > maxTimeout) {
332             *timeout = maxTimeout;
333         }
334     }
335 }
336 
SendFileHeader(DFileTrans * dFileTrans,DFileSendState * nextState)337 static void SendFileHeader(DFileTrans *dFileTrans, DFileSendState *nextState)
338 {
339     uint32_t fileNum;
340     if (dFileTrans->fileList->tarFlag == NSTACKX_TRUE) {
341         fileNum = 1;
342     } else {
343         fileNum = FileListGetNum(dFileTrans->fileList);
344     }
345     do {
346         (void)memset_s(dFileTrans->sendBuffer, sizeof(dFileTrans->sendBuffer), 0, sizeof(dFileTrans->sendBuffer));
347 
348         int32_t lastEncodeHeaderFileId = dFileTrans->lastSentHeaderFileId;
349         EncodeFileHeaderFrame(dFileTrans->fileList, &lastEncodeHeaderFileId, dFileTrans->sendBuffer,
350             dFileTrans->mtu, &dFileTrans->sendBufferLength);
351         int32_t ret = SendFrame(dFileTrans, dFileTrans->sendBuffer, dFileTrans->sendBufferLength, nextState, NULL);
352         if (ret != NSTACKX_EOK) {
353             break;
354         }
355 
356         DFILE_LOGI(TAG, "transId %hu send header successfully. len %zu lastEncodeHeaderFileId %d, fileNum %u",
357              dFileTrans->transId, dFileTrans->sendBufferLength, lastEncodeHeaderFileId, fileNum);
358 
359         dFileTrans->lastSentHeaderFileId = lastEncodeHeaderFileId;
360         if (dFileTrans->lastSentHeaderFileId == (int32_t)fileNum) {
361             *nextState = STATE_WAIT_FOR_FILE_HEADER_CONFIRM;
362             break;
363         }
364     } while (NSTACKX_TRUE);
365 }
366 
FileManagerSenderMsgHandler(uint16_t fileId,FileManagerMsgType msgType,FileManagerMsg * msg,DFileTrans * dFileTrans)367 void FileManagerSenderMsgHandler(uint16_t fileId, FileManagerMsgType msgType, FileManagerMsg *msg,
368                                  DFileTrans *dFileTrans)
369 {
370     char *files[NSTACKX_DFILE_MAX_FILE_NUM] = {0};
371     if (dFileTrans == NULL) {
372         return;
373     }
374     if (msgType != FILE_MANAGER_TRANS_IN_PROGRESS) {
375         DFILE_LOGI(TAG, "transId %u, Sender: File Id %u got message (%d) from file manager, code %d",
376              dFileTrans->transId, fileId, msgType, (msgType == FILE_MANAGER_SEND_FAIL) ? msg->errorCode : 0);
377     }
378 
379     if (msgType == FILE_MANAGER_TRANS_IN_PROGRESS) {
380         msg->fileList.fileNum = NSTACKX_DFILE_MAX_FILE_NUM;
381         msg->fileList.userData = dFileTrans->fileList->userData;
382         msg->fileList.transId = dFileTrans->transId;
383         FileListGetNames(dFileTrans->fileList, files, &msg->fileList.fileNum, dFileTrans->fileList->noticeFileNameType);
384         msg->fileList.files = (const char **)files;
385         dFileTrans->msgReceiver(dFileTrans, DFILE_TRANS_MSG_IN_PROGRESS, msg);
386         return;
387     }
388     if (msgType == FILE_MANAGER_SEND_FAIL) {
389         dFileTrans->errorCode = DFILE_TRANS_FILE_SEND_TASK_ERROR;
390         SetSendState(dFileTrans, STATE_SEND_FILE_FAIL);
391         NotifyTransMsg(dFileTrans, DFILE_TRANS_MSG_FILE_SEND_FAIL);
392     }
393 }
394 
FileManagerTransMsgHandler(uint16_t fileId,FileManagerMsgType msgType,FileManagerMsg * msg,void * context,uint16_t transId)395 static void FileManagerTransMsgHandler(uint16_t fileId, FileManagerMsgType msgType, FileManagerMsg *msg, void *context,
396     uint16_t transId)
397 {
398     DFileSession *session = (DFileSession *)context;
399     List *pos = NULL;
400     DFileTrans *dFileTrans = NULL;
401     uint8_t isFound = NSTACKX_FALSE;
402     if (session == NULL || session->closeFlag) {
403         return;
404     }
405     LIST_FOR_EACH(pos, &session->dFileTransChain) {
406         dFileTrans = (DFileTrans *)pos;
407         if (dFileTrans != NULL && dFileTrans->transId == transId) {
408             isFound = NSTACKX_TRUE;
409             break;
410         }
411     }
412     if (!isFound) {
413         DFILE_LOGE(TAG, "can't get valid trans %u to send msg", transId);
414         return;
415     }
416 
417     if (dFileTrans->isSender) {
418         FileManagerSenderMsgHandler(fileId, msgType, msg, dFileTrans);
419     } else {
420         FileManagerReceiverMsgHandler(fileId, msgType, msg, dFileTrans);
421     }
422 }
423 
StartFileManagerSenderTask(DFileTrans * dFileTrans)424 static int32_t StartFileManagerSenderTask(DFileTrans *dFileTrans)
425 {
426     FileListMsgPara msgPara;
427     uint32_t i;
428     FileList *fileList = dFileTrans->fileList;
429     uint16_t fileNum = FileListGetNum(fileList);
430     SendFileListInfo sendFileListInfo;
431 
432     (void)memset_s(&sendFileListInfo, sizeof(sendFileListInfo), 0, sizeof(sendFileListInfo));
433     (void)memset_s(&msgPara, sizeof(msgPara), 0, sizeof(msgPara));
434 
435     if (dFileTrans->fileManagerTaskStarted) {
436         return NSTACKX_EOK;
437     }
438     if (fileNum > NSTACKX_DFILE_MAX_FILE_NUM) {
439         DFILE_LOGE(TAG, "too many files: %u", fileNum);
440         return NSTACKX_ENOMEM;
441     }
442     for (i = 0; i < FileListGetNum(fileList); i++) {
443         sendFileListInfo.fileList[i] = fileList->list[i].fullFileName;
444         sendFileListInfo.fileSize[i] = fileList->list[i].fileSize;
445         sendFileListInfo.startOffset[i] = fileList->list[i].startOffset;
446     }
447 
448     if (fileList->tarFlag == NSTACKX_TRUE) {
449         sendFileListInfo.fileList[i] = fileList->tarFile;
450     }
451     sendFileListInfo.transId = dFileTrans->transId;
452     sendFileListInfo.fileNum = FileListGetNum(fileList);
453     sendFileListInfo.tarFlag = fileList->tarFlag;
454     sendFileListInfo.smallFlag = fileList->smallFlag;
455     msgPara.msgReceiver = FileManagerTransMsgHandler;
456     msgPara.context = dFileTrans->session;
457     int32_t ret = FileManagerSendFileTask(dFileTrans->fileManager, &sendFileListInfo, &msgPara);
458     if (ret != NSTACKX_EOK) {
459         DFILE_LOGE(TAG, "Start send file task fail %d", ret);
460         return ret;
461     }
462     dFileTrans->fileManagerTaskStarted = NSTACKX_TRUE;
463     dFileTrans->totalDataFrameCnt = GetTotalFrameCount(dFileTrans);
464     return NSTACKX_EOK;
465 }
466 
WaitForFileHeaderConfirmPrepare(DFileTrans * dFileTrans)467 static void WaitForFileHeaderConfirmPrepare(DFileTrans *dFileTrans)
468 {
469     dFileTrans->lastSentHeaderFileId = -1;
470     if (dFileTrans->headerRetryCnt == 0) {
471         dFileTrans->timeout = dFileTrans->config.maxRtt;
472     } else {
473         ExtendTimeout(&dFileTrans->timeout, dFileTrans->config.maxFileHeaderConfirmFrameTimeout);
474     }
475     ClockGetTime(CLOCK_MONOTONIC, &dFileTrans->ts);
476 }
477 
WaitForFileHeaderConfirm(DFileTrans * dFileTrans,DFileSendState * nextState)478 static void WaitForFileHeaderConfirm(DFileTrans *dFileTrans, DFileSendState *nextState)
479 {
480     if (FileListAllFileNameAcked(dFileTrans->fileList)) {
481         int32_t ret = StartFileManagerSenderTask(dFileTrans);
482         if (ret == NSTACKX_EOK) {
483             *nextState = STATE_SEND_FILE_DATA_ONGOING;
484         } else {
485             *nextState = STATE_SEND_FILE_FAIL;
486             dFileTrans->errorCode = DFILE_TRANS_INTERNAL_ERROR;
487         }
488         return;
489     }
490 
491     if (GetElapseTime(&dFileTrans->ts) >= dFileTrans->timeout) {
492         if (dFileTrans->headerRetryCnt > dFileTrans->config.maxCtrlFrameRetryCnt) {
493             *nextState = STATE_SEND_FILE_FAIL;
494             dFileTrans->errorCode = DFILE_TRANS_FILE_HEADER_CONFIRM_TIMEOUT;
495             WaitFileHeaderTimeoutEvent(dFileTrans->errorCode);
496             return;
497         }
498         dFileTrans->headerRetryCnt++;
499         *nextState = STATE_SEND_FILE_HEADER_ONGOING;
500     }
501 }
502 
SendFileBlockPrepare(DFileTrans * dFileTrans)503 static void SendFileBlockPrepare(DFileTrans *dFileTrans)
504 {
505     ClockGetTime(CLOCK_MONOTONIC, &dFileTrans->ts);
506     dFileTrans->timeout = dFileTrans->config.initialAckInterval;
507     NotifyTransMsg(dFileTrans, DFILE_TRANS_MSG_FILE_SEND_DATA);
508 }
509 
SendFileDataOngoing(DFileTrans * dFileTrans,DFileSendState * nextState)510 static void SendFileDataOngoing(DFileTrans *dFileTrans, DFileSendState *nextState)
511 {
512     if (dFileTrans->fileTransferDoneReceived) {
513         *nextState = STATE_SEND_FILE_TRANSFER_DONE_ACK;
514         return;
515     }
516     if (GetElapseTime(&dFileTrans->ts) >= dFileTrans->timeout) {
517         if (!CapsTcp(dFileTrans->session)) {
518             dFileTrans->lostAckCnt++;
519             DFILE_LOGW(TAG, "transId %u Sender lost ACK count %u totalRecvBlocks %llu inboundQueueSize %llu",
520                 dFileTrans->transId, dFileTrans->lostAckCnt,
521                 NSTACKX_ATOM_FETCH(&(dFileTrans->session->totalRecvBlocks)),
522                 dFileTrans->session->inboundQueueSize);
523             if (dFileTrans->lostAckCnt >= dFileTrans->config.maxAckCnt) {
524                 *nextState = STATE_SEND_FILE_FAIL;
525                 dFileTrans->errorCode = DFILE_TRANS_FILE_DATA_ACK_TIMEOUT;
526                 DFILE_LOGW(TAG, "transId %u Sender lost too many ACK count", dFileTrans->transId);
527                 return;
528             }
529         }
530 
531         /* Update timestamp */
532         ClockGetTime(CLOCK_MONOTONIC, &dFileTrans->ts);
533         return;
534     }
535 
536     if (FileManagerIsLastBlockRead(dFileTrans->fileManager, dFileTrans->transId)) {
537         *nextState = STATE_WAIT_FOR_FILE_TRANSFER_DONE_FRAME;
538     }
539 }
540 
WaitForFileTransferDonePrepare(DFileTrans * dFileTrans)541 static void WaitForFileTransferDonePrepare(DFileTrans *dFileTrans)
542 {
543     ClockGetTime(CLOCK_MONOTONIC, &dFileTrans->ts);
544     dFileTrans->timeout = dFileTrans->config.maxCtrlFrameTimeout;
545 }
546 
WaitForFileTransferDoneFrame(DFileTrans * dFileTrans,DFileSendState * nextState)547 static void WaitForFileTransferDoneFrame(DFileTrans *dFileTrans, DFileSendState *nextState)
548 {
549     if (dFileTrans->fileTransferDoneReceived) {
550         *nextState = STATE_SEND_FILE_TRANSFER_DONE_ACK;
551     }
552 
553     if (GetElapseTime(&dFileTrans->ts) >= dFileTrans->timeout) {
554         if (CapsTcp(dFileTrans->session)) {
555             *nextState = STATE_SEND_FILE_DATA_ONGOING;
556             return;
557         }
558         *nextState = STATE_SEND_FILE_FAIL;
559         dFileTrans->errorCode = DFILE_TRANS_TRANSFER_DONE_TIMEOUT;
560         return;
561     }
562 
563     /* Need to re-send data block. */
564     if (!FileManagerIsLastBlockRead(dFileTrans->fileManager, dFileTrans->transId)) {
565         *nextState = STATE_SEND_FILE_DATA_ONGOING;
566         return;
567     }
568 }
569 
SendFileTransferDoneAckFrame(DFileTrans * dFileTrans,DFileSendState * nextState)570 static void SendFileTransferDoneAckFrame(DFileTrans *dFileTrans, DFileSendState *nextState)
571 {
572     uint32_t i;
573 
574     (void)memset_s(dFileTrans->sendBuffer, sizeof(dFileTrans->sendBuffer), 0, sizeof(dFileTrans->sendBuffer));
575     EncodeFileTransferDoneAckFrame(dFileTrans->sendBuffer, dFileTrans->mtu, dFileTrans->transId,
576         &dFileTrans->sendBufferLength);
577     for (i = 0; i < TRANSFER_DONE_ACK_REPEATED_TIMES; i++) {
578         int32_t ret = SendFrame(dFileTrans, dFileTrans->sendBuffer, dFileTrans->sendBufferLength, nextState, NULL);
579         if (ret != NSTACKX_EOK) {
580             break;
581         }
582     }
583     TransferDoneAckNode *transferDoneAckNode = calloc(1, sizeof(TransferDoneAckNode));
584     if (transferDoneAckNode == NULL) {
585         DFILE_LOGE(TAG, "transferDoneAckNode calloc failed");
586         return;
587     }
588     transferDoneAckNode->transId = dFileTrans->transId;
589     transferDoneAckNode->sendNum = MAX_SEND_TRANSFERDONE_ACK_FRAME_COUNT;
590     if (MutexListAddNode(&dFileTrans->session->transferDoneAckList, &transferDoneAckNode->list, 0) != NSTACKX_EOK) {
591         free(transferDoneAckNode);
592     }
593     DFILE_LOGI(TAG, "transferDoneAckNode add transId %u", dFileTrans->transId);
594     if (i == 0) {
595         return;
596     }
597 
598     *nextState = STATE_SEND_FILE_DONE;
599 }
600 
SetSendState(DFileTrans * dFileTrans,DFileSendState nextState)601 static void SetSendState(DFileTrans *dFileTrans, DFileSendState nextState)
602 {
603     if (dFileTrans->sendState == nextState) {
604         return;
605     }
606 
607     switch (nextState) {
608         case STATE_WAIT_FOR_FILE_HEADER_CONFIRM:
609             WaitForFileHeaderConfirmPrepare(dFileTrans);
610             break;
611         case STATE_SEND_FILE_DATA_ONGOING:
612             SendFileBlockPrepare(dFileTrans);
613             break;
614         case STATE_WAIT_FOR_FILE_TRANSFER_DONE_FRAME:
615             WaitForFileTransferDonePrepare(dFileTrans);
616             break;
617         default:
618             break;
619     }
620 
621     if (dFileTrans->sendState >= STATE_SEND_FILE_TRANSFER_DONE_ACK && nextState == STATE_SEND_FILE_FAIL) {
622         /*
623          * After receiving TRANSFER_DONE frame, sender still may encounter error, such as sending TRANSFER_DONE_ACK
624          * frame. In such case, we just stop the state machine and report finish to user.
625          */
626         DFILE_LOGW(TAG, "transId %u Sender error during state %s - %s, ignore error and finish sending process",
627              dFileTrans->transId, GetSendStateMessage(dFileTrans->sendState), GetErrorMessage(dFileTrans->errorCode));
628         nextState = STATE_SEND_FILE_DONE;
629     }
630 
631     if (dFileTrans->errorCode != DFILE_TRANS_NO_ERROR) {
632         DFILE_LOGE(TAG, "transId %u error: %s", dFileTrans->transId, GetErrorMessage(dFileTrans->errorCode));
633     }
634     dFileTrans->sendState = nextState;
635 
636     if ((nextState == STATE_SEND_FILE_DONE || nextState == STATE_SEND_FILE_FAIL) &&
637         dFileTrans->fileManagerTaskStarted) {
638         DFILE_LOGI(TAG, "transId: %u, Send state: %s -> %s", dFileTrans->transId,
639                 GetSendStateMessage(dFileTrans->sendState),GetSendStateMessage(nextState));
640         if (FileManagerStopTask(dFileTrans->fileManager, dFileTrans->transId, FILE_LIST_TRANSFER_FINISH) !=
641             NSTACKX_EOK) {
642             DFILE_LOGE(TAG, "transId %u FileManagerStopTask failed", dFileTrans->transId);
643         }
644         dFileTrans->fileManagerTaskStarted = NSTACKX_FALSE;
645     }
646 }
647 
SenderFsm(DFileTrans * dFileTrans)648 static void SenderFsm(DFileTrans *dFileTrans)
649 {
650     DFileSendState nextState = dFileTrans->sendState;
651 
652     do {
653         switch (dFileTrans->sendState) {
654             case STATE_SEND_FILE_INIT:
655                 nextState = STATE_SEND_FILE_HEADER_ONGOING;
656                 dFileTrans->session->transFlag = NSTACKX_TRUE;
657                 dFileTrans->fileManager->transFlag = NSTACKX_TRUE;
658                 break;
659             case STATE_SEND_FILE_HEADER_ONGOING:
660                 SendFileHeader(dFileTrans, &nextState);
661                 break;
662             case STATE_WAIT_FOR_FILE_HEADER_CONFIRM:
663                 WaitForFileHeaderConfirm(dFileTrans, &nextState);
664                 break;
665             case STATE_SEND_FILE_DATA_ONGOING:
666                 SendFileDataOngoing(dFileTrans, &nextState);
667                 break;
668             case STATE_WAIT_FOR_FILE_TRANSFER_DONE_FRAME:
669                 WaitForFileTransferDoneFrame(dFileTrans, &nextState);
670                 break;
671             case STATE_SEND_FILE_TRANSFER_DONE_ACK:
672                 SendFileTransferDoneAckFrame(dFileTrans, &nextState);
673                 break;
674             default:
675                 break;
676         }
677         if (dFileTrans->sendState == nextState) {
678             break;
679         }
680         SetSendState(dFileTrans, nextState);
681     } while (dFileTrans->sendState != STATE_SEND_FILE_FAIL && dFileTrans->sendState != STATE_SEND_FILE_DONE);
682 }
683 
ReceiveFileHeaderPrepare(DFileTrans * dFileTrans)684 static void ReceiveFileHeaderPrepare(DFileTrans *dFileTrans)
685 {
686     ClockGetTime(CLOCK_MONOTONIC, &dFileTrans->ts);
687     if (dFileTrans->headerAckRetryCnt == 0) {
688         dFileTrans->timeout = dFileTrans->config.maxRtt;
689     } else {
690         ExtendTimeout(&dFileTrans->timeout, dFileTrans->config.maxCtrlFrameTimeout);
691     }
692 }
693 
ReceiveFileHeaderOngoing(DFileTrans * dFileTrans,DFileReceiveState * nextState)694 static void ReceiveFileHeaderOngoing(DFileTrans *dFileTrans, DFileReceiveState *nextState)
695 {
696     uint8_t timeout = (GetElapseTime(&dFileTrans->ts) >= dFileTrans->timeout) ? NSTACKX_TRUE : NSTACKX_FALSE;
697     if (dFileTrans->allFileNameReceived || timeout) {
698         *nextState = STATE_SEND_FILE_HEADER_CONFIRM;
699         return;
700     }
701 }
702 
NotifyRecvSucMsg(DFileTrans * dFileTrans)703 static void NotifyRecvSucMsg(DFileTrans *dFileTrans)
704 {
705     if (dFileTrans->isRecvSucMsgNotified) {
706         return;
707     }
708     NotifyTransMsg(dFileTrans, DFILE_TRANS_MSG_FILE_RECEIVED);
709     dFileTrans->isRecvSucMsgNotified = NSTACKX_TRUE;
710 }
711 
FileManagerReceiverMsgHandler(uint16_t fileId,FileManagerMsgType msgType,FileManagerMsg * msg,DFileTrans * dFileTrans)712 void FileManagerReceiverMsgHandler(uint16_t fileId, FileManagerMsgType msgType, FileManagerMsg *msg,
713                                    DFileTrans *dFileTrans)
714 {
715     if (dFileTrans == NULL) {
716         return;
717     }
718     if (msgType != FILE_MANAGER_RECEIVE_SUCCESS) {
719         DFILE_LOGE(TAG, "transId %u, Receiver: File Id %u got message (%d) from file manager, code %d",
720              dFileTrans->transId, fileId, msgType, (msgType == FILE_MANAGER_RECEIVE_FAIL) ? msg->errorCode : 0);
721     }
722 
723     if (msgType == FILE_MANAGER_RECEIVE_FAIL) {
724         dFileTrans->errorCode = DFILE_TRANS_FILE_RECEIVE_TASK_ERROR;
725         SetReceiveState(dFileTrans, STATE_RECEIVE_FILE_FAIL);
726         NotifyTransMsg(dFileTrans, DFILE_TRANS_MSG_FILE_RECEIVE_FAIL);
727         return;
728     }
729 
730     if (fileId) {
731         if (msgType == FILE_MANAGER_RECEIVE_SUCCESS) {
732             FileListSetFileReceiveSuccess(dFileTrans->fileList, fileId);
733         }
734         if (FileListAllFileReceived(dFileTrans->fileList)) {
735             /*
736              * When all files are empty, it won't enter RECEIVE_DATA_ON_GOING state.
737              * We have to set allFileDataReceived in this case
738              */
739             dFileTrans->allFileDataReceived = NSTACKX_TRUE;
740             dFileTrans->ioWriteFinishFlag = NSTACKX_TRUE;
741             NotifyRecvSucMsg(dFileTrans);
742             ReceiverFsm(dFileTrans);
743             dFileTrans->isAckSend = NSTACKX_FALSE;
744         }
745     }
746 }
747 
StartFileManagerReceiverTask(DFileTrans * dFileTrans)748 static int32_t StartFileManagerReceiverTask(DFileTrans *dFileTrans)
749 {
750     RecvFileListInfo fileListInfo;
751     FileList *fileList = dFileTrans->fileList;
752     FileListMsgPara msgPara;
753 
754     if (dFileTrans->fileManagerTaskStarted) {
755         return NSTACKX_EOK;
756     }
757     fileListInfo.fileBasicInfo = calloc(FileListGetNum(fileList), sizeof(FileBaseInfo));
758     if (fileListInfo.fileBasicInfo == NULL) {
759         return NSTACKX_ENOMEM;
760     }
761 
762     for (uint32_t i = 0; i < FileListGetNum(fileList); i++) {
763         fileListInfo.fileBasicInfo[i].fileSize = fileList->list[i].fileSize;
764         fileListInfo.fileBasicInfo[i].fileId = fileList->list[i].fileId;
765         fileListInfo.fileBasicInfo[i].fileName = fileList->list[i].fileName;
766         fileListInfo.fileBasicInfo[i].startOffset = fileList->list[i].startOffset;
767         dFileTrans->totalBytes += fileList->list[i].fileSize;
768     }
769 
770     fileListInfo.pathType = FileListGetPathType(fileList);
771     fileListInfo.fileNum = FileListGetNum(fileList);
772     fileListInfo.transId = dFileTrans->transId;
773     fileListInfo.noSyncFlag = fileList->noSyncFlag;
774     msgPara.msgReceiver = FileManagerTransMsgHandler;
775     msgPara.context = dFileTrans->session;
776     int32_t ret = FileManagerRecvFileTask(dFileTrans->fileManager, &fileListInfo, &msgPara);
777     if (ret != NSTACKX_EOK) {
778         DFILE_LOGE(TAG, "Start receive task fail %d", ret);
779         free(fileListInfo.fileBasicInfo);
780         return NSTACKX_EFAILED;
781     }
782     dFileTrans->fileManagerTaskStarted = NSTACKX_TRUE;
783     free(fileListInfo.fileBasicInfo);
784     return NSTACKX_EOK;
785 }
786 
SendFileHeaderConfirm(DFileTrans * dFileTrans,DFileReceiveState * nextState)787 static void SendFileHeaderConfirm(DFileTrans *dFileTrans, DFileReceiveState *nextState)
788 {
789     do {
790         (void)memset_s(dFileTrans->sendBuffer, sizeof(dFileTrans->sendBuffer), 0, sizeof(dFileTrans->sendBuffer));
791         uint16_t lastEncAckedHeaderFileId = dFileTrans->lastAckedHeaderFileId;
792         EncodeFileHeaderConfirmFrame(dFileTrans->fileList, &lastEncAckedHeaderFileId,
793             dFileTrans->sendBuffer, dFileTrans->mtu, &dFileTrans->sendBufferLength);
794         int32_t ret = SendFrame(dFileTrans, dFileTrans->sendBuffer, dFileTrans->sendBufferLength, NULL, nextState);
795         if (ret != NSTACKX_EOK) {
796             return;
797         }
798         dFileTrans->lastAckedHeaderFileId = lastEncAckedHeaderFileId;
799         if (dFileTrans->lastAckedHeaderFileId == FileListGetNum(dFileTrans->fileList)) {
800             DFILE_LOGI(TAG, "transId %u last send header confirm successfully. len %u",
801                 dFileTrans->transId, dFileTrans->sendBufferLength);
802             break;
803         }
804     } while (NSTACKX_TRUE);
805 
806     if (dFileTrans->allFileNameReceived) {
807         if (StartFileManagerReceiverTask(dFileTrans) != NSTACKX_EOK) {
808             *nextState = STATE_RECEIVE_FILE_FAIL;
809             dFileTrans->errorCode = DFILE_TRANS_INTERNAL_ERROR;
810         } else {
811             *nextState = STATE_RECEIVE_FILE_DATA_ONGOING;
812         }
813     } else {
814         /* Timeout, check should retry or fail */
815         if (dFileTrans->headerAckRetryCnt > dFileTrans->config.maxCtrlFrameRetryCnt) {
816             *nextState = STATE_RECEIVE_FILE_FAIL;
817             dFileTrans->errorCode = DFILE_TRANS_FILE_HEADER_TIMEOUT;
818             return;
819         }
820         *nextState = STATE_RECEIVE_FILE_HEADER_ONGOING;
821         dFileTrans->headerAckRetryCnt++;
822     }
823 }
824 
GetTotalFrameCount(DFileTrans * dFileTrans)825 static uint64_t GetTotalFrameCount(DFileTrans *dFileTrans)
826 {
827     uint64_t totalFrameCount = 0;
828     uint32_t lastSequence;
829 
830     for (uint16_t fileId = NSTACKX_FIRST_FILE_ID; fileId <= FileListGetNum(dFileTrans->fileList); fileId++) {
831         if (!FileListGetFileSize(dFileTrans->fileList, fileId)) {
832             continue;
833         }
834         int32_t ret = FileManagerGetLastSequence(dFileTrans->fileManager, dFileTrans->transId, fileId, &lastSequence);
835         if (ret != NSTACKX_EOK) {
836             continue;
837         }
838         totalFrameCount += (lastSequence + 1);
839     }
840     return totalFrameCount;
841 }
842 
ReceiveFileDataPrepare(DFileTrans * dFileTrans)843 static void ReceiveFileDataPrepare(DFileTrans *dFileTrans)
844 {
845     PeerInfo *peerInfo = dFileTrans->context;
846     if (dFileTrans->recvState == STATE_SEND_FILE_HEADER_CONFIRM) {
847         /* Update time stamp when entering from "HEADER" stage to "DATA" state */
848         ClockGetTime(CLOCK_MONOTONIC, &dFileTrans->ts);
849         ClockGetTime(CLOCK_MONOTONIC, &dFileTrans->heartBeatTs);
850 
851         dFileTrans->timeout = dFileTrans->config.initialRecvIdleTimeout;
852         dFileTrans->ackInterval = peerInfo->ackInterval;
853         dFileTrans->transRetryCount = dFileTrans->config.maxRetryPageCnt;
854         dFileTrans->receivedDataFrameCnt = 0;
855         dFileTrans->totalDataFrameCnt = GetTotalFrameCount(dFileTrans);
856         dFileTrans->adjustAckIntervalLimit = NstackAdjustAckIntervalRatio(dFileTrans->totalDataFrameCnt);
857         ClockGetTime(CLOCK_MONOTONIC, &dFileTrans->retryAllPacketTs);
858 #if DFILE_SHOW_RECEIVE_TIME
859         ClockGetTime(CLOCK_MONOTONIC, &dFileTrans->startTs);
860 #endif
861     }
862 }
863 
ReceiverIdleTimeout(DFileTrans * dFileTrans,DFileReceiveState * nextState)864 static uint8_t ReceiverIdleTimeout(DFileTrans *dFileTrans, DFileReceiveState *nextState)
865 {
866     uint8_t timeout = NSTACKX_FALSE;
867     uint32_t elapseTime = GetElapseTime(&dFileTrans->ts);
868     if (elapseTime >= dFileTrans->timeout) {
869         dFileTrans->idleTimeoutCnt++;
870         DFILE_LOGE(TAG,
871             "transId %u: Over %u ms not recv data. idleTimeoutCnt %u last fileid %u sequence %u recv %llu all %llu",
872             dFileTrans->transId, elapseTime, dFileTrans->idleTimeoutCnt, dFileTrans->lastFileDataRecvFileId,
873             dFileTrans->lastFileDataSequence, dFileTrans->receivedDataFrameCnt, dFileTrans->totalDataFrameCnt);
874         timeout = NSTACKX_TRUE;
875     }
876 
877     if (timeout && dFileTrans->idleTimeoutCnt >= dFileTrans->config.maxRecvIdleCnt) {
878         if (!CapsTcp(dFileTrans->session)) {
879             return NSTACKX_TRUE;
880         }
881     }
882 
883     if (timeout) {
884         ClockGetTime(CLOCK_MONOTONIC, &dFileTrans->ts);
885         *nextState = STATE_SEND_FILE_DATA_ACK;
886     }
887     return NSTACKX_FALSE;
888 }
889 
RefreshFileRecvStatus(DFileTrans * dFileTrans)890 static int32_t RefreshFileRecvStatus(DFileTrans *dFileTrans)
891 {
892     uint16_t fileIdList[NSTACKX_DFILE_MAX_FILE_NUM] = {0};
893     uint8_t fileIdSuccessFlag[NSTACKX_DFILE_MAX_FILE_NUM] = {0};
894     uint32_t fileIdNum = NSTACKX_DFILE_MAX_FILE_NUM;
895     if (FileManagerGetReceivedFiles(dFileTrans->fileManager, dFileTrans->transId,
896         fileIdList, fileIdSuccessFlag, &fileIdNum) != NSTACKX_EOK) {
897         DFILE_LOGE(TAG, "transId %u get received files failed", dFileTrans->transId);
898         return NSTACKX_EFAILED;
899     }
900     if (fileIdNum == 0) {
901         DFILE_LOGI(TAG, "transId %u get zero received files", dFileTrans->transId);
902         return NSTACKX_EOK;
903     }
904     for (uint32_t i = 0; i < fileIdNum; i++) {
905         if (fileIdList[i] == 0) {
906             continue;
907         }
908         if (fileIdSuccessFlag[i]) {
909             FileListSetFileReceiveSuccess(dFileTrans->fileList, fileIdList[i]);
910         } else {
911             FileListSetFileReceiveFail(dFileTrans->fileList, fileIdList[i]);
912         }
913     }
914     return NSTACKX_EOK;
915 }
916 
ReceiveFileDataOngoing(DFileTrans * dFileTrans,DFileReceiveState * nextState)917 static void ReceiveFileDataOngoing(DFileTrans *dFileTrans, DFileReceiveState *nextState)
918 {
919     if (dFileTrans->dupFileName) {
920         dFileTrans->dupFileName = NSTACKX_FALSE;
921         *nextState = STATE_SEND_FILE_HEADER_CONFIRM;
922         return;
923     }
924 
925     if (dFileTrans->allFileDataReceived) {
926         if (dFileTrans->ioWriteFinishFlag == NSTACKX_FALSE) {
927             return;
928         }
929         if (RefreshFileRecvStatus(dFileTrans) != NSTACKX_EOK) {
930             DFILE_LOGE(TAG, "transId %u refresh file receive status failed", dFileTrans->transId);
931             *nextState = STATE_RECEIVE_FILE_FAIL;
932             dFileTrans->errorCode = DFILE_TRANS_FILE_RECEIVE_TASK_ERROR;
933             return;
934         }
935         if (FileListAllFileReceived(dFileTrans->fileList)) {
936             *nextState = STATE_SEND_FILE_TRANSFER_DONE;
937             return;
938         }
939     } else {
940         if (ReceiverIdleTimeout(dFileTrans, nextState)) {
941             *nextState = STATE_RECEIVE_FILE_FAIL;
942             dFileTrans->errorCode = DFILE_TRANS_FILE_DATA_TIMEOUT;
943             return;
944         }
945     }
946 
947     if (*nextState != STATE_SEND_FILE_DATA_ACK && GetElapseTime(&dFileTrans->heartBeatTs) >= dFileTrans->ackInterval) {
948         if (dFileTrans->allFileDataReceived) {
949             if (FileManagerSetAllDataReceived(dFileTrans->fileManager, dFileTrans->transId) != NSTACKX_EOK) {
950                 DFILE_LOGE(TAG, "transId %u get set all file data received failed", dFileTrans->transId);
951                 *nextState = STATE_RECEIVE_FILE_FAIL;
952                 dFileTrans->errorCode = DFILE_TRANS_FILE_RECEIVE_TASK_ERROR;
953                 return;
954             }
955         }
956         *nextState = STATE_SEND_FILE_DATA_ACK;
957         dFileTrans->isAckSend = NSTACKX_TRUE;
958     }
959 }
960 
SendFileTransferDoneFrame(DFileTrans * dFileTrans,DFileReceiveState * nextState)961 static void SendFileTransferDoneFrame(DFileTrans *dFileTrans, DFileReceiveState *nextState)
962 {
963     uint16_t fileIdList[NSTACKX_DFILE_MAX_FILE_NUM] = {0};
964     uint32_t fileIdNum = NSTACKX_DFILE_MAX_FILE_NUM;
965 
966     if (GetElapseTime(&dFileTrans->ts) >= dFileTrans->timeout) {
967         dFileTrans->errorCode = DFILE_TRANS_FILE_WRITE_FAIL;
968         DFILE_LOGE(TAG, "SendFileTransferDoneFrame timeout");
969         *nextState = STATE_RECEIVE_FILE_FAIL;
970         return;
971     }
972     NotifyRecvSucMsg(dFileTrans);
973 
974     FileListGetReceivedFileIdList(dFileTrans->fileList, fileIdList, &fileIdNum);
975     (void)memset_s(dFileTrans->sendBuffer, sizeof(dFileTrans->sendBuffer), 0, sizeof(dFileTrans->sendBuffer));
976     /*
977      * Currently max file number is 500, and default MTU is 1500, so one MTU can contain all the file Id.
978      */
979     EncodeFileTransferDoneFrame(dFileTrans->sendBuffer, dFileTrans->mtu, fileIdList, fileIdNum,
980         &dFileTrans->sendBufferLength);
981     int32_t ret = SendFrame(dFileTrans, dFileTrans->sendBuffer, dFileTrans->sendBufferLength, NULL, nextState);
982     if (ret != NSTACKX_EOK) {
983         return;
984     }
985     DFILE_LOGI(TAG, "file trans fer done frame: transId %u, frameLen %u, fileIdNum %u",
986          dFileTrans->transId, dFileTrans->sendBufferLength, fileIdNum);
987     *nextState = STATE_WAIT_FOR_FILE_TRANSFER_DONE_ACK;
988 }
989 
WaitForFileTransferDoneAckPrepare(DFileTrans * dFileTrans)990 static void WaitForFileTransferDoneAckPrepare(DFileTrans *dFileTrans)
991 {
992     ClockGetTime(CLOCK_MONOTONIC, &dFileTrans->ts);
993     dFileTrans->timeout = dFileTrans->config.maxRtt;
994 }
995 
WaitForFileTransferDoneAck(DFileTrans * dFileTrans,DFileReceiveState * nextState)996 static void WaitForFileTransferDoneAck(DFileTrans *dFileTrans, DFileReceiveState *nextState)
997 {
998     if (dFileTrans->fileTransferDoneAcked) {
999         *nextState = STATE_RECEIVE_FILE_DONE;
1000         return;
1001     }
1002 
1003     if (GetElapseTime(&dFileTrans->ts) >= dFileTrans->timeout) {
1004         if (dFileTrans->transferDoneRetryCnt > dFileTrans->config.maxCtrlFrameRetryCnt &&
1005             !CapsTcp(dFileTrans->session)) {
1006             dFileTrans->errorCode = DFILE_TRANS_TRANSFER_DONE_ACK_TIMEOUT;
1007             *nextState = STATE_RECEIVE_FILE_FAIL;
1008             DFILE_LOGI(TAG, "transId %u enter WaitForFileTransferDoneAck and next state is STATE_RECEIVE_FILE_FAIL",
1009                  dFileTrans->transId);
1010             return;
1011         }
1012         /* Prepare to enter STATE_SEND_FILE_TRANSFER_DONE again */
1013         ClockGetTime(CLOCK_MONOTONIC, &dFileTrans->ts);
1014         dFileTrans->transferDoneRetryCnt++;
1015         *nextState = STATE_SEND_FILE_TRANSFER_DONE;
1016         DFILE_LOGI(TAG, "transId %u enter WaitForFileTransferDoneAck and next state is STATE_SEND_FILE_TRANSFER_DONE",
1017              dFileTrans->transId);
1018         return;
1019     }
1020 }
1021 
1022 #if DFILE_SHOW_RECEIVE_TIME
CalculateRecvRate(DFileTrans * dFileTrans)1023 static void CalculateRecvRate(DFileTrans *dFileTrans)
1024 {
1025     struct timespec endTs;
1026 
1027     ClockGetTime(CLOCK_MONOTONIC, &endTs);
1028     uint64_t allFileSize = dFileTrans->totalDataFrameCnt * dFileTrans->fileManager->maxFrameLength;
1029     uint32_t spendTime = GetTimeDiffMs(&endTs, &dFileTrans->startTs);
1030     if (spendTime != 0) {
1031         const double rate = 1.0 * allFileSize / DFILE_MEGABYTES * MSEC_TICKS_PER_SEC / spendTime;
1032         DFILE_LOGI(TAG, "Trans#%u Receive time %u ms rate is %.2f MB/s", dFileTrans->transId, spendTime, rate);
1033     }
1034 }
1035 #endif
1036 
SetReceiveStateHandle(DFileTrans * dFileTrans,DFileReceiveState nextState)1037 static void SetReceiveStateHandle(DFileTrans *dFileTrans, DFileReceiveState nextState)
1038 {
1039     switch (nextState) {
1040         case STATE_RECEIVE_FILE_HEADER_ONGOING:
1041             ReceiveFileHeaderPrepare(dFileTrans);
1042             break;
1043         case STATE_RECEIVE_FILE_DATA_ONGOING:
1044             ReceiveFileDataPrepare(dFileTrans);
1045             break;
1046         case STATE_SEND_FILE_HEADER_CONFIRM:
1047             dFileTrans->lastAckedHeaderFileId = NSTACKX_RESERVED_FILE_ID;
1048             break;
1049         case STATE_WAIT_FOR_FILE_TRANSFER_DONE_ACK:
1050             WaitForFileTransferDoneAckPrepare(dFileTrans);
1051             break;
1052         case STATE_SEND_FILE_TRANSFER_DONE:
1053             ClockGetTime(CLOCK_MONOTONIC, &dFileTrans->ts);
1054             dFileTrans->timeout = dFileTrans->config.maxFileWriteTimeout;
1055             break;
1056         default:
1057             break;
1058     }
1059 }
1060 
SetReceiveState(DFileTrans * dFileTrans,DFileReceiveState nextState)1061 static void SetReceiveState(DFileTrans *dFileTrans, DFileReceiveState nextState)
1062 {
1063     if (dFileTrans->recvState == nextState) {
1064         return;
1065     }
1066 
1067     SetReceiveStateHandle(dFileTrans, nextState);
1068     if (dFileTrans->recvState > STATE_SEND_FILE_TRANSFER_DONE && nextState == STATE_RECEIVE_FILE_FAIL) {
1069         /*
1070          * For receiver, it may encounter error after sending TRANSFER DONE frame.
1071          * In such case, we just stop the state machine and report finish to user.
1072          */
1073         DFILE_LOGW(TAG, "transId %u, Receiver error during state %s - code %d, ignore and finish receiving process",
1074             dFileTrans->transId, GetReceiveStateMessage(dFileTrans->recvState), dFileTrans->errorCode);
1075         nextState = STATE_RECEIVE_FILE_DONE;
1076     }
1077 
1078     if (dFileTrans->errorCode != DFILE_TRANS_NO_ERROR) {
1079         DFILE_LOGE(TAG, "transId %u error: %s", dFileTrans->transId, GetErrorMessage(dFileTrans->errorCode));
1080     }
1081     dFileTrans->recvState = nextState;
1082 
1083     if ((nextState == STATE_RECEIVE_FILE_DONE || nextState == STATE_RECEIVE_FILE_FAIL) &&
1084         dFileTrans->fileManagerTaskStarted) {
1085         DFILE_LOGI(TAG, "transId %u, Receive state: %s -> %s", dFileTrans->transId,
1086             GetReceiveStateMessage(dFileTrans->recvState), GetReceiveStateMessage(nextState));
1087         if (FileManagerStopTask(dFileTrans->fileManager, dFileTrans->transId, FILE_LIST_TRANSFER_FINISH) !=
1088             NSTACKX_EOK) {
1089             DFILE_LOGE(TAG, "transId %u FileManagerStopTask failed", dFileTrans->transId);
1090         }
1091         dFileTrans->fileManagerTaskStarted = NSTACKX_FALSE;
1092     }
1093 #if DFILE_SHOW_RECEIVE_TIME
1094     if (nextState == STATE_RECEIVE_FILE_DONE) {
1095         CalculateRecvRate(dFileTrans);
1096     }
1097 #endif
1098 }
1099 
ReceiverFsm(DFileTrans * dFileTrans)1100 static void ReceiverFsm(DFileTrans *dFileTrans)
1101 {
1102     DFileReceiveState nextState = dFileTrans->recvState;
1103 
1104     do {
1105         switch (dFileTrans->recvState) {
1106             case STATE_RECEIVE_FILE_INIT:
1107                 nextState = STATE_RECEIVE_FILE_HEADER_ONGOING;
1108                 dFileTrans->session->transFlag = NSTACKX_TRUE;
1109                 dFileTrans->fileManager->transFlag = NSTACKX_TRUE;
1110                 break;
1111             case STATE_RECEIVE_FILE_HEADER_ONGOING:
1112                 ReceiveFileHeaderOngoing(dFileTrans, &nextState);
1113                 break;
1114             case STATE_SEND_FILE_HEADER_CONFIRM:
1115                 SendFileHeaderConfirm(dFileTrans, &nextState);
1116                 break;
1117             case STATE_RECEIVE_FILE_DATA_ONGOING:
1118                 ReceiveFileDataOngoing(dFileTrans, &nextState);
1119                 break;
1120             case STATE_SEND_FILE_DATA_ACK:
1121                 SendFileDataAck(dFileTrans, &nextState);
1122                 break;
1123             case STATE_SEND_FILE_TRANSFER_DONE:
1124                 SendFileTransferDoneFrame(dFileTrans, &nextState);
1125                 break;
1126             case STATE_WAIT_FOR_FILE_TRANSFER_DONE_ACK:
1127                 WaitForFileTransferDoneAck(dFileTrans, &nextState);
1128                 break;
1129             default:
1130                 break;
1131         }
1132         if (dFileTrans->recvState == nextState) {
1133             break;
1134         }
1135         SetReceiveState(dFileTrans, nextState);
1136     } while (dFileTrans->recvState != STATE_RECEIVE_FILE_FAIL && dFileTrans->recvState != STATE_RECEIVE_FILE_DONE);
1137 }
1138 
TransferFsm(DFileTrans * dFileTrans)1139 static void TransferFsm(DFileTrans *dFileTrans)
1140 {
1141     if (dFileTrans->isSender) {
1142         SenderFsm(dFileTrans);
1143     } else {
1144         ReceiverFsm(dFileTrans);
1145     }
1146 }
1147 
RenameFileIfExisting(DFileTrans * dFileTrans)1148 static int32_t RenameFileIfExisting(DFileTrans *dFileTrans)
1149 {
1150     DFileRenamePara renamePara;
1151     uint16_t pathType = FileListGetPathType(dFileTrans->fileList);
1152     if (dFileTrans->onRenameFile == NULL) {
1153         return NSTACKX_EOK;
1154     }
1155     for (uint16_t i = 0; i < FileListGetNum(dFileTrans->fileList); i++) {
1156         const char *fileName = FileListGetFileName(dFileTrans->fileList, i + 1);
1157         (void)memset_s(&renamePara, sizeof(DFileRenamePara), 0, sizeof(DFileRenamePara));
1158         renamePara.rootPathType = pathType;
1159         renamePara.initFileName = fileName;
1160         dFileTrans->onRenameFile(&renamePara);
1161 
1162         if (strlen(renamePara.newFileName) == 0 || strlen(renamePara.newFileName) + 1 > NSTACKX_MAX_REMOTE_PATH_LEN) {
1163             DFILE_LOGE(TAG, "transId %u rename file %s failed remotePath too long", dFileTrans->transId, fileName);
1164             return NSTACKX_EFAILED;
1165         }
1166         if (GetFileNameLen(renamePara.newFileName) > NSTACKX_MAX_FILE_NAME_LEN) {
1167             DFILE_LOGE(TAG, "transId %u rename file %s failed newFileName too long", dFileTrans->transId, fileName);
1168             return NSTACKX_EFAILED;
1169         }
1170         if (FileListRenameFile(dFileTrans->fileList, i + 1, renamePara.newFileName) != NSTACKX_EOK) {
1171             DFILE_LOGE(TAG, "transId %u FileListRenameFile  failed", dFileTrans->transId);
1172             return NSTACKX_EFAILED;
1173         }
1174     }
1175     return NSTACKX_EOK;
1176 }
1177 
HandleFileNameTableFrame(DFileTrans * dFileTrans,DFileFrame * dFileFrame)1178 static int32_t HandleFileNameTableFrame(DFileTrans *dFileTrans, DFileFrame *dFileFrame)
1179 {
1180     if (dFileTrans->isSender) {
1181         return NSTACKX_EFAILED;
1182     }
1183 
1184     if (dFileTrans->recvState != STATE_RECEIVE_FILE_INIT &&
1185         dFileTrans->recvState != STATE_RECEIVE_FILE_HEADER_ONGOING &&
1186         dFileTrans->recvState != STATE_SEND_FILE_HEADER_CONFIRM &&
1187         dFileTrans->recvState != STATE_RECEIVE_FILE_DATA_ONGOING) {
1188         return NSTACKX_EFAILED;
1189     }
1190 
1191     if (DecodeFileHeaderFrame(dFileTrans->fileList, (FileHeaderFrame *)dFileFrame) != NSTACKX_EOK) {
1192         DFILE_LOGE(TAG, "decode file hearder frame failed");
1193     }
1194 
1195     if (!dFileTrans->allFileNameReceived) {
1196         /* Check whether all file names are receviced only when previous allFileNameReceived is false */
1197         dFileTrans->allFileNameReceived = FileListAllFileNameReceived(dFileTrans->fileList);
1198         if (dFileTrans->allFileNameReceived) {
1199             if (RenameFileIfExisting(dFileTrans) != NSTACKX_EOK) {
1200                 dFileTrans->errorCode = DFILE_TRANS_FILE_RENAME_FAIL;
1201                 NotifyTransMsg(dFileTrans, DFILE_TRANS_MSG_FILE_RECEIVE_FAIL);
1202                 dFileTrans->allFileNameReceived = NSTACKX_FALSE;
1203             }
1204 
1205             NotifyTransMsg(dFileTrans, DFILE_TRANS_MSG_FILE_LIST_RECEIVED);
1206         }
1207     } else {
1208         dFileTrans->dupFileName = NSTACKX_TRUE;
1209     }
1210     return NSTACKX_EOK;
1211 }
1212 
HandleFileTableAckFrame(DFileTrans * dFileTrans,DFileFrame * dFileFrame)1213 static int32_t HandleFileTableAckFrame(DFileTrans *dFileTrans, DFileFrame *dFileFrame)
1214 {
1215     if (!dFileTrans->isSender) {
1216         return NSTACKX_EFAILED;
1217     }
1218     dFileTrans->lostAckCnt = 0;
1219     if (dFileTrans->sendState != STATE_SEND_FILE_HEADER_ONGOING &&
1220         dFileTrans->sendState != STATE_WAIT_FOR_FILE_HEADER_CONFIRM) {
1221         return NSTACKX_EFAILED;
1222     }
1223 
1224     if (DecodeFileHeaderConfirmFrame(dFileTrans->fileList, (FileHeaderConfirmFrame *)dFileFrame) != NSTACKX_EOK) {
1225         return NSTACKX_EFAILED;
1226     }
1227     return NSTACKX_EOK;
1228 }
1229 
UpdateTransParam(DFileTrans * dFileTrans,uint8_t endFlag,uint16_t fileId,uint16_t len)1230 static void UpdateTransParam(DFileTrans *dFileTrans, uint8_t endFlag, uint16_t fileId, uint16_t len)
1231 {
1232     uint32_t maxFileId = FileListGetNum(dFileTrans->fileList);
1233     if (endFlag) {
1234         FileListSetLastBlockReceived(dFileTrans->fileList, fileId);
1235         DFILE_LOGI(TAG, "transId %u recv the end frame fileId %hu", dFileTrans->transId, fileId);
1236     }
1237     if (FileListGetLastBlockReceived(dFileTrans->fileList, (uint16_t)maxFileId)) {
1238         dFileTrans->shouldSendAckDividor = NSTACKX_SEND_ACK_PER_TWO_RECYCLE;
1239         if (!dFileTrans->recvLastFramePrint) {
1240             DFILE_LOGI(TAG, "transId %u recv the last frame", dFileTrans->transId);
1241             dFileTrans->recvLastFramePrint = NSTACKX_TRUE;
1242         }
1243     }
1244     if (FileListGetLastBlockReceived(dFileTrans->fileList, (uint16_t)maxFileId) &&
1245         dFileTrans->receivedDataFrameCnt >= dFileTrans->adjustAckIntervalLimit) {
1246         if (!dFileTrans->adjustToLastFrameAckInterval) {
1247             dFileTrans->ackInterval = dFileTrans->config.lastFrameAckInterval;
1248             dFileTrans->adjustToLastFrameAckInterval = NSTACKX_TRUE;
1249         }
1250 
1251         dFileTrans->shouldSendAckDividor = NSTACKX_SEND_ACK_PER_ONE_RECYCLE;
1252 
1253         if (!dFileTrans->adjustAckIntervalLimitPrint) {
1254             DFILE_LOGI(TAG, "transId %u dFileTrans->ackInterval %u", dFileTrans->transId, dFileTrans->ackInterval);
1255             dFileTrans->adjustAckIntervalLimitPrint = NSTACKX_TRUE;
1256         }
1257     }
1258     if (endFlag && fileId == maxFileId) {
1259         DFileReceiveState nextState;
1260         DFILE_LOGI(TAG, "send all retry packets");
1261         SendFileDataAck(dFileTrans, &nextState);
1262     }
1263     dFileTrans->receivedDataFrameCnt++;
1264     dFileTrans->bytesTransferred += len;
1265     if (dFileTrans->bytesTransferred <
1266         dFileTrans->bytesTransferredLastRecord + NSTACKX_KILO_BYTES * KILO_BYTES_TRANSFER_NOTICE_THRESHOLD) {
1267         return;
1268     }
1269     dFileTrans->bytesTransferredLastRecord = dFileTrans->bytesTransferred;
1270     if (dFileTrans->bytesTransferred >= dFileTrans->totalBytes) {
1271         return;
1272     } else {
1273         NotifyTransProgress(dFileTrans, dFileTrans->bytesTransferred);
1274     }
1275 }
1276 
WriteDataFrame(DFileTrans * dFileTrans,FileDataFrame * dataFrame)1277 static int32_t WriteDataFrame(DFileTrans *dFileTrans, FileDataFrame *dataFrame)
1278 {
1279     uint16_t fileId = ntohs(dataFrame->fileId);
1280     uint16_t len = ntohs(dataFrame->header.length) + sizeof(DFileFrameHeader) - sizeof(FileDataFrame);
1281     uint8_t endFlag = CheckDfileFrameEndFlag(dataFrame);
1282 
1283     int32_t ret = FileManagerFileWrite(dFileTrans->fileManager, dataFrame);
1284     if (ret != NSTACKX_EOK) {
1285         DFILE_LOGE(TAG, "FileManagerFileWrite failed! ret %d", ret);
1286         dFileTrans->errorCode = DFILE_TRANS_FILE_WRITE_FAIL;
1287         SetReceiveState(dFileTrans, STATE_RECEIVE_FILE_FAIL);
1288         return ret;
1289     }
1290     UpdateTransParam(dFileTrans, endFlag, fileId, len);
1291 
1292     return NSTACKX_EOK;
1293 }
1294 
CheckReceiverTransAndFrameValid(const DFileTrans * dFileTrans,const FileDataFrame * dataFrame)1295 static int32_t CheckReceiverTransAndFrameValid(const DFileTrans *dFileTrans, const FileDataFrame *dataFrame)
1296 {
1297     if (ntohs(dataFrame->header.length) <= sizeof(FileDataFrame) - sizeof(DFileFrameHeader)) {
1298         return NSTACKX_EFAILED;
1299     }
1300 
1301     if (dFileTrans->isSender || (dFileTrans->recvState != STATE_RECEIVE_FILE_DATA_ONGOING &&
1302         dFileTrans->recvState != STATE_SEND_FILE_DATA_ACK)) {
1303         return NSTACKX_EFAILED;
1304     }
1305 
1306     /* validate file id */
1307     if (GetFileIdFromFileDataFrame(dFileTrans->fileList, dataFrame) == NSTACKX_RESERVED_FILE_ID) {
1308         DFILE_LOGE(TAG, "dFileTrans %u error. GetFileIdFromFileDataFrame failed", dFileTrans->transId);
1309         return NSTACKX_EFAILED;
1310     }
1311     return NSTACKX_EOK;
1312 }
1313 
HandleFileDataFrame(DFileTrans * trans,DFileFrame * dFileFrame)1314 static int32_t HandleFileDataFrame(DFileTrans *trans, DFileFrame *dFileFrame)
1315 {
1316     FileDataFrame *dataFrame = (FileDataFrame *)dFileFrame;
1317 
1318     int32_t ret = NSTACKX_EFAILED;
1319     uint8_t received;
1320     if (CheckReceiverTransAndFrameValid(trans, dataFrame)) {
1321         goto L_ERR;
1322     }
1323     trans->recvCount++;
1324 
1325     if (FileManagerIsRecvBlockWritable(trans->fileManager, trans->transId) != NSTACKX_TRUE) {
1326         trans->recvBlockListFullTimes++;
1327         goto L_TIMESTAMP_UPDATE;
1328     }
1329 
1330     ret = WriteDataFrame(trans, dataFrame);
1331     if (ret != NSTACKX_EOK) {
1332         DFILE_LOGE(TAG, "transId %u error. WriteDataFrame ret == %d", trans->transId, ret);
1333         goto L_ERR;
1334     }
1335 
1336     received = FileListGetLastBlockReceived(trans->fileList, FileListGetNum(trans->fileList));
1337     if (trans->receivedDataFrameCnt >= trans->totalDataFrameCnt) {
1338         DFILE_LOGI(TAG, "transId:%u last block received:%u", trans->transId, received);
1339         if (received) {
1340             trans->allFileDataReceived = NSTACKX_TRUE;
1341             DFILE_LOGI(TAG, "transId %u FINISH!!! retry send %u retry num %u not Insert Count %u %llu/%llu "
1342                 "recvblocklist full times %llu totalSend %llu totalRecv %llu",
1343                 trans->transId, trans->allRetrySendCount, trans->allRetryCount, trans->notInsertCount,
1344                 trans->receivedDataFrameCnt, trans->totalDataFrameCnt, trans->recvBlockListFullTimes,
1345                 trans->session->totalSendBlocks, trans->session->totalRecvBlocks);
1346         }
1347     }
1348 
1349 L_TIMESTAMP_UPDATE:
1350     ClockGetTime(CLOCK_MONOTONIC, &trans->ts);
1351 L_ERR:
1352     return ret;
1353 }
1354 
HandleTransferDoneFrame(DFileTrans * dFileTrans,DFileFrame * dFileFrame)1355 static int32_t HandleTransferDoneFrame(DFileTrans *dFileTrans, DFileFrame *dFileFrame)
1356 {
1357     if (!dFileTrans->isSender) {
1358         return NSTACKX_EFAILED;
1359     }
1360 
1361     if (dFileTrans->sendState != STATE_WAIT_FOR_FILE_TRANSFER_DONE_FRAME &&
1362         dFileTrans->sendState != STATE_SEND_FILE_TRANSFER_DONE_ACK &&
1363         dFileTrans->sendState != STATE_SEND_FILE_DATA_ONGOING) {
1364         DFILE_LOGE(TAG, "transId %u, HandleTransferDoneFrame failed.sendState %d",
1365              dFileTrans->transId, dFileTrans->sendState);
1366         return NSTACKX_EFAILED;
1367     }
1368 
1369     if (!dFileTrans->fileTransferDoneReceived) {
1370         dFileTrans->fileTransferDoneReceived = NSTACKX_TRUE;
1371         if (DecodeFileTransferDoneFrame(dFileTrans->fileList, (FileTransferDoneFrame *)dFileFrame) != NSTACKX_EOK) {
1372             return NSTACKX_EFAILED;
1373         }
1374     }
1375     return NSTACKX_EOK;
1376 }
1377 
HandleDFileFrame(DFileTrans * dFileTrans,DFileFrame * dFileFrame)1378 int32_t HandleDFileFrame(DFileTrans *dFileTrans, DFileFrame *dFileFrame)
1379 {
1380     int32_t ret = NSTACKX_EFAILED;
1381 
1382     if (dFileTrans->mtu == 0 || DFileTransStateFinished(dFileTrans)) {
1383         return ret;
1384     }
1385 
1386     if (dFileFrame->header.type != NSTACKX_DFILE_FILE_DATA_FRAME) {
1387         DFILE_LOGI(TAG, "transId %u, Handle frame (%hhu):%s",
1388              dFileTrans->transId, dFileFrame->header.type, GetFrameName(dFileFrame->header.type));
1389     }
1390 
1391     switch (dFileFrame->header.type) {
1392         case NSTACKX_DFILE_FILE_HEADER_FRAME:
1393             ret = HandleFileNameTableFrame(dFileTrans, dFileFrame);
1394             break;
1395         case NSTACKX_DFILE_FILE_HEADER_CONFIRM_FRAME:
1396             ret = HandleFileTableAckFrame(dFileTrans, dFileFrame);
1397             break;
1398         case NSTACKX_DFILE_FILE_DATA_FRAME:
1399             ret = HandleFileDataFrame(dFileTrans, dFileFrame);
1400             break;
1401         case NSTACKX_DFILE_FILE_TRANSFER_DONE_FRAME:
1402             ret = HandleTransferDoneFrame(dFileTrans, dFileFrame);
1403             break;
1404         case NSTACKX_DFILE_FILE_TRANSFER_DONE_ACK_FRAME:
1405             if (!dFileTrans->isSender) {
1406                 dFileTrans->fileTransferDoneAcked = NSTACKX_TRUE;
1407             }
1408             ret = NSTACKX_EOK;
1409             break;
1410         default:
1411             break;
1412     }
1413 
1414     /* Continue FSM as per frame */
1415     TransferFsm(dFileTrans);
1416     if (dFileTrans->isAckSend) {
1417         NotifyTransMsg(dFileTrans, DFILE_TRANS_MSG_FILE_SEND_ACK);
1418         dFileTrans->isAckSend = NSTACKX_FALSE;
1419     }
1420     DFileTransNotifyEndMsg(dFileTrans);
1421 
1422     return ret;
1423 }
1424 
DFileTransProcess(DFileTrans * dFileTrans)1425 void DFileTransProcess(DFileTrans *dFileTrans)
1426 {
1427     if (dFileTrans->mtu == 0 || DFileTransStateFinished(dFileTrans)) {
1428         return;
1429     }
1430 
1431     TransferFsm(dFileTrans);
1432     dFileTrans->isAckSend = NSTACKX_FALSE;
1433     DFileTransNotifyEndMsg(dFileTrans);
1434 }
1435 
GetRemainingTime(uint32_t maxTime,const struct timespec * now,const struct timespec * ts)1436 static uint32_t GetRemainingTime(uint32_t maxTime, const struct timespec *now, const struct timespec *ts)
1437 {
1438     uint32_t elapseTime = GetTimeDiffMs(now, ts);
1439     if (elapseTime >= maxTime) {
1440         return 0;
1441     } else {
1442         return maxTime - elapseTime;
1443     }
1444 }
1445 
SenderGetTimeout(DFileTrans * dFileTrans)1446 static int64_t SenderGetTimeout(DFileTrans *dFileTrans)
1447 {
1448     struct timespec now;
1449 
1450     if (dFileTrans->sendState != STATE_WAIT_FOR_FILE_HEADER_CONFIRM &&
1451         dFileTrans->sendState != STATE_SEND_FILE_DATA_ONGOING &&
1452         dFileTrans->sendState != STATE_WAIT_FOR_FILE_TRANSFER_DONE_FRAME) {
1453         return NSTACKX_EFAILED;
1454     }
1455 
1456     ClockGetTime(CLOCK_MONOTONIC, &now);
1457     uint32_t remainTime = GetRemainingTime(dFileTrans->timeout, &now, &dFileTrans->ts);
1458 
1459     return (int64_t)remainTime;
1460 }
1461 
ReceiverGetTimeout(DFileTrans * dFileTrans)1462 static int64_t ReceiverGetTimeout(DFileTrans *dFileTrans)
1463 {
1464     struct timespec now;
1465     if (dFileTrans->recvState != STATE_RECEIVE_FILE_HEADER_ONGOING &&
1466         dFileTrans->recvState != STATE_RECEIVE_FILE_DATA_ONGOING &&
1467         dFileTrans->recvState != STATE_SEND_FILE_TRANSFER_DONE &&
1468         dFileTrans->recvState != STATE_WAIT_FOR_FILE_TRANSFER_DONE_ACK) {
1469         return NSTACKX_EFAILED;
1470     }
1471 
1472     ClockGetTime(CLOCK_MONOTONIC, &now);
1473     uint32_t remainTime = GetRemainingTime(dFileTrans->timeout, &now, &dFileTrans->ts);
1474     if (dFileTrans->recvState == STATE_RECEIVE_FILE_DATA_ONGOING) {
1475         uint32_t remainTimeHeartBeat = GetRemainingTime(dFileTrans->ackInterval, &now, &dFileTrans->heartBeatTs);
1476         if (remainTime > remainTimeHeartBeat) {
1477             remainTime = remainTimeHeartBeat;
1478         }
1479     }
1480 
1481     return (int64_t)remainTime;
1482 }
1483 
DFileTransGetTimeout(DFileTrans * dFileTrans)1484 int64_t DFileTransGetTimeout(DFileTrans *dFileTrans)
1485 {
1486     if (dFileTrans->isSender) {
1487         return SenderGetTimeout(dFileTrans);
1488     } else {
1489         return ReceiverGetTimeout(dFileTrans);
1490     }
1491 }
1492 
DFileTransSetMtu(DFileTrans * dFileTrans,uint16_t mtu)1493 int32_t DFileTransSetMtu(DFileTrans *dFileTrans, uint16_t mtu)
1494 {
1495     if (mtu <= offsetof(FileDataFrame, blockPayload) || mtu > NSTACKX_MAX_FRAME_SIZE) {
1496         return NSTACKX_EINVAL;
1497     }
1498 
1499     if (dFileTrans->mtu == mtu) {
1500         return NSTACKX_EOK;
1501     }
1502 
1503     dFileTrans->mtu = mtu;
1504     return NSTACKX_EOK;
1505 }
1506 
DFileTransCreate(const DFileTransPara * para)1507 DFileTrans *DFileTransCreate(const DFileTransPara *para)
1508 {
1509     DFileTrans *dFileTrans = malloc(sizeof(DFileTrans));
1510     if (dFileTrans == NULL) {
1511         return NULL;
1512     }
1513     (void)memset_s(dFileTrans, sizeof(DFileTrans), 0, sizeof(DFileTrans));
1514 
1515     dFileTrans->fileList = FileListCreate();
1516     if (dFileTrans->fileList == NULL) {
1517         free(dFileTrans);
1518         return NULL;
1519     }
1520 
1521     dFileTrans->lastSentHeaderFileId = -1;
1522     dFileTrans->isSender = para->isSender;
1523     dFileTrans->transId = para->transId;
1524     dFileTrans->fileManager = para->fileManager;
1525     dFileTrans->connType = para->connType;
1526     dFileTrans->writeHandle = para->writeHandle;
1527     dFileTrans->msgReceiver = para->msgReceiver;
1528     dFileTrans->context = para->context;
1529     dFileTrans->session = para->session;
1530     dFileTrans->onRenameFile = para->onRenameFile;
1531     dFileTrans->shouldSendAckDividor = NSTACKX_SEND_ACK_PER_THREE_RECYCLE;
1532     ListInitHead(&dFileTrans->retryList);
1533 
1534     if (ConfigDFileTrans(dFileTrans->connType, &dFileTrans->config) != NSTACKX_EOK) {
1535         FileListDestroy(dFileTrans->fileList);
1536         free(dFileTrans);
1537         return NULL;
1538     }
1539 
1540     return dFileTrans;
1541 }
1542 
DFileTransDestroy(DFileTrans * dFileTrans)1543 void DFileTransDestroy(DFileTrans *dFileTrans)
1544 {
1545     dFileTrans->session->allTaskCount--;
1546     DFileTransDestroyInner(dFileTrans);
1547 }
1548 
DFileTransDestroyInner(DFileTrans * dFileTrans)1549 void DFileTransDestroyInner(DFileTrans *dFileTrans)
1550 {
1551     free(dFileTrans->remainDataFrame);
1552     dFileTrans->remainDataFrame = NULL;
1553 
1554     if (dFileTrans->fileManagerTaskStarted) {
1555         DFILE_LOGI(TAG, "transId %u FileManagerStopTask", dFileTrans->transId);
1556         if (FileManagerStopTask(dFileTrans->fileManager, dFileTrans->transId, FILE_LIST_TRANSFER_FINISH) !=
1557             NSTACKX_EOK) {
1558             DFILE_LOGE(TAG, "transId %u FileManagerStopTask failed", dFileTrans->transId);
1559         }
1560     }
1561 
1562     FileListDestroy(dFileTrans->fileList);
1563     free(dFileTrans);
1564 }
1565 
DFileTransGetTotalBytes(const DFileTrans * dFileTrans)1566 uint64_t DFileTransGetTotalBytes(const DFileTrans *dFileTrans)
1567 {
1568     if (dFileTrans == NULL) {
1569         return 0;
1570     }
1571     return GetFilesTotalBytes(dFileTrans->fileList);
1572 }
1573