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