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_error.h"
24 #include "nstackx_file_manager.h"
25 #include "nstackx_list.h"
26 #include "nstackx_dfile_log.h"
27 #include "nstackx_timer.h"
28 #include "nstackx_util.h"
29 #include "nstackx_dfile_dfx.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     DFILE_LOGI(TAG, "transId %hu, 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     DFILE_LOGI(TAG, "transId %hu, pathType %hu", 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     uint32_t msgLen = sizeof(message) / sizeof(message[0]);
76     for (uint32_t i = 0; i < msgLen; 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     uint32_t msgLen = sizeof(message) / sizeof(message[0]);
99     for (uint32_t i = 0; i < msgLen; i++) {
100         if (state == i) {
101             return message[i];
102         }
103     }
104     return "unknown";
105 }
106 
GetErrorMessage(DFileTransErrorCode errorCode)107 static const char *GetErrorMessage(DFileTransErrorCode errorCode)
108 {
109     static const char *message[] = {
110         [DFILE_TRANS_NO_ERROR] = "No error",
111         [DFILE_TRANS_SOCKET_ERROR] = "Socket IO error",
112         [DFILE_TRANS_INTERNAL_ERROR] = "Internal error",
113         [DFILE_TRANS_FILE_HEADER_CONFIRM_TIMEOUT] = "Sender wait for HEADER CONFIRM frame timeout",
114         [DFILE_TRANS_FILE_DATA_ACK_TIMEOUT] = "Sender wait for heart beat (DATA ACK frame) timeout",
115         [DFILE_TRANS_TRANSFER_DONE_TIMEOUT] = "Sender wait for TRANSFER DONE frame timeout",
116         [DFILE_TRANS_FILE_HEADER_TIMEOUT] = "Receiver wait for HEADER frame timeout (partially received)",
117         [DFILE_TRANS_FILE_DATA_TIMEOUT] = "Receive file data timeout (partially received)",
118         [DFILE_TRANS_TRANSFER_DONE_ACK_TIMEOUT] = "Receiver wait for TRANSFER DONE ACK frame timeout",
119         [DFILE_TRANS_FILE_SEND_TASK_ERROR] = "Send task error",
120         [DFILE_TRANS_FILE_RECEIVE_TASK_ERROR] = "Receive task error",
121         [DFILE_TRANS_FILE_WRITE_FAIL] = "Write file list fail",
122         [DFILE_TRANS_FILE_RENAME_FAIL] = "Rename file failed",
123     };
124 
125     for (uint32_t i = 0; i < sizeof(message) / sizeof(message[0]); i++) {
126         if (errorCode == i) {
127             return message[i];
128         }
129     }
130     return "unknown";
131 }
132 
GetElapseTime(const struct timespec * ts)133 static inline uint32_t GetElapseTime(const struct timespec *ts)
134 {
135     struct timespec now;
136     ClockGetTime(CLOCK_MONOTONIC, &now);
137     return GetTimeDiffMs(&now, ts);
138 }
139 
ConvertTransError(DFileTransErrorCode errorCode)140 static int32_t ConvertTransError(DFileTransErrorCode errorCode)
141 {
142     switch (errorCode) {
143         case DFILE_TRANS_NO_ERROR:
144             return NSTACKX_EOK;
145         case DFILE_TRANS_SOCKET_ERROR:
146         case DFILE_TRANS_INTERNAL_ERROR:
147         case DFILE_TRANS_FILE_SEND_TASK_ERROR:
148         case DFILE_TRANS_FILE_RECEIVE_TASK_ERROR:
149         case DFILE_TRANS_FILE_WRITE_FAIL:
150         case DFILE_TRANS_FILE_RENAME_FAIL:
151             return NSTACKX_EFAILED;
152         case DFILE_TRANS_FILE_HEADER_CONFIRM_TIMEOUT:
153         case DFILE_TRANS_FILE_DATA_ACK_TIMEOUT:
154         case DFILE_TRANS_TRANSFER_DONE_TIMEOUT:
155         case DFILE_TRANS_FILE_HEADER_TIMEOUT:
156         case DFILE_TRANS_FILE_DATA_TIMEOUT:
157         case DFILE_TRANS_TRANSFER_DONE_ACK_TIMEOUT:
158             return NSTACKX_ETIMEOUT;
159         default:
160             break;
161     }
162 
163     return NSTACKX_EFAILED;
164 }
165 
166 
ReviewSuccessMsg(const DFileTrans * dFileTrans,DFileTransMsgType * msgType,DFileTransMsg * msg,char * files[])167 void ReviewSuccessMsg(const DFileTrans *dFileTrans, DFileTransMsgType *msgType,
168     DFileTransMsg *msg, char *files[])
169 {
170     if (*msgType != DFILE_TRANS_MSG_FILE_SENT && *msgType != DFILE_TRANS_MSG_FILE_RECEIVED) {
171         return;
172     }
173     if (*msgType == DFILE_TRANS_MSG_FILE_SENT) {
174         if (msg->fileList.fileNum == 0) {
175             msg->fileList.fileNum = NSTACKX_DFILE_MAX_FILE_NUM;
176             FileListGetNames(dFileTrans->fileList, files, &msg->fileList.fileNum,
177                              dFileTrans->fileList->noticeFileNameType);
178             msg->fileList.files = (const char **)files;
179             msg->errorCode = NSTACKX_EFAILED;
180             /*
181              * Both DFILE_TRANS_MSG_FILE_SENT and DFILE_TRANS_MSG_FILE_SEND_FAIL are ending status, which means that
182              * the trans will be destroyed in DTransMsgReceiver(). So DFILE_TRANS_MSG_FILE_SENT can be changed to
183              * DFILE_TRANS_MSG_FILE_SEND_FAIL directly.
184              */
185             *msgType = DFILE_TRANS_MSG_FILE_SEND_FAIL;
186             DFILE_LOGI(TAG, "transId %u: no success file", dFileTrans->transId);
187         }
188     }
189     if (*msgType == DFILE_TRANS_MSG_FILE_RECEIVED) {
190         if (msg->fileList.fileNum == 0) {
191             msg->fileList.fileNum = NSTACKX_DFILE_MAX_FILE_NUM;
192             FileListGetNames(dFileTrans->fileList, files, &msg->fileList.fileNum, NOTICE_FILE_NAME_TYPE);
193             msg->fileList.files = (const char **)files;
194             msg->errorCode = NSTACKX_EFAILED;
195             /*
196              * DFILE_TRANS_MSG_FILE_RECEIVED isn't an ending status, so it can't be changed to the ending status
197              * DFILE_TRANS_MSG_FILE_RECEIVE_FAIL directly.
198              */
199             *msgType = DFILE_TRANS_MSG_FILE_RECEIVED_TO_FAIL;
200             DFILE_LOGI(TAG, "transId %u: no success file", dFileTrans->transId);
201         }
202     }
203 }
204 
NotifyTransProgress(DFileTrans * dFileTrans,uint64_t bytesTransferred)205 static void NotifyTransProgress(DFileTrans *dFileTrans, uint64_t bytesTransferred)
206 {
207     DFileTransMsg transMsg;
208     char *files[NSTACKX_DFILE_MAX_FILE_NUM] = {0};
209     (void)memset_s(&transMsg, sizeof(transMsg), 0, sizeof(transMsg));
210     transMsg.transferUpdate.transId = dFileTrans->transId;
211     transMsg.transferUpdate.totalBytes = dFileTrans->totalBytes;
212     transMsg.transferUpdate.bytesTransferred = bytesTransferred;
213     transMsg.fileList.fileNum = NSTACKX_DFILE_MAX_FILE_NUM;
214     transMsg.fileList.userData = dFileTrans->fileList->userData;
215     transMsg.fileList.transId = dFileTrans->transId;
216     FileListGetNames(dFileTrans->fileList, files, &transMsg.fileList.fileNum, NOTICE_FILE_NAME_TYPE);
217     transMsg.fileList.files = (const char **)files;
218     dFileTrans->msgReceiver(dFileTrans, DFILE_TRANS_MSG_IN_PROGRESS, &transMsg);
219 }
220 
NotifyTransMsg(DFileTrans * dFileTrans,DFileTransMsgType msgType)221 static void NotifyTransMsg(DFileTrans *dFileTrans, DFileTransMsgType msgType)
222 {
223     if (dFileTrans->msgReceiver == NULL) {
224         return;
225     }
226 
227     DFileTransMsg transMsg;
228     char *files[NSTACKX_DFILE_MAX_FILE_NUM] = {0};
229     (void)memset_s(&transMsg, sizeof(transMsg), 0, sizeof(transMsg));
230     transMsg.fileList.fileNum = NSTACKX_DFILE_MAX_FILE_NUM;
231     transMsg.fileList.userData = dFileTrans->fileList->userData;
232     transMsg.fileList.transId = dFileTrans->transId;
233 
234     switch (msgType) {
235         case DFILE_TRANS_MSG_FILE_LIST_RECEIVED:
236             FileListGetNames(dFileTrans->fileList, files, &transMsg.fileList.fileNum, NOTICE_FILE_NAME_TYPE);
237             transMsg.fileList.files = (const char **)files;
238             break;
239         case DFILE_TRANS_MSG_FILE_RECEIVED:
240             FileListGetReceivedFiles(dFileTrans->fileList, files, &transMsg.fileList.fileNum);
241             transMsg.fileList.files = (const char **)files;
242             if (transMsg.fileList.fileNum == dFileTrans->fileList->num) {
243                 NotifyTransProgress(dFileTrans, dFileTrans->totalBytes);
244             }
245             break;
246         case DFILE_TRANS_MSG_FILE_SENT:
247             FileListGetSentFiles(dFileTrans->fileList, files, &transMsg.fileList.fileNum);
248             transMsg.fileList.files = (const char **)files;
249             break;
250         case DFILE_TRANS_MSG_FILE_RECEIVE_FAIL:
251             /*
252              * May encounter failure durinng HEADER stage, and not all the file names are received. In this case, we
253              * don't provide the file list.
254              */
255             transMsg.fileList.fileNum = 0;
256             if (FileListAllFileNameReceived(dFileTrans->fileList)) {
257                 transMsg.fileList.fileNum = NSTACKX_DFILE_MAX_FILE_NUM;
258                 FileListGetNames(dFileTrans->fileList, files, &transMsg.fileList.fileNum, NOTICE_FILE_NAME_TYPE);
259                 transMsg.fileList.files = (const char **)files;
260             }
261             transMsg.errorCode = ConvertTransError(dFileTrans->errorCode);
262             break;
263         case DFILE_TRANS_MSG_FILE_SEND_FAIL:
264             FileListGetNames(dFileTrans->fileList, files, &transMsg.fileList.fileNum,
265                              dFileTrans->fileList->noticeFileNameType);
266             transMsg.fileList.files = (const char **)files;
267             transMsg.errorCode = ConvertTransError(dFileTrans->errorCode);
268             break;
269         default:
270             break;
271     }
272     ReviewSuccessMsg(dFileTrans, &msgType, &transMsg, files);
273     dFileTrans->msgReceiver(dFileTrans, msgType, &transMsg);
274 }
275 
276 /* To post message when come to end */
DFileTransNotifyEndMsg(DFileTrans * dFileTrans)277 static void DFileTransNotifyEndMsg(DFileTrans *dFileTrans)
278 {
279     if (dFileTrans->isSender) {
280         if (dFileTrans->sendState == STATE_SEND_FILE_FAIL) {
281             NotifyTransMsg(dFileTrans, DFILE_TRANS_MSG_FILE_SEND_FAIL);
282         } else if (dFileTrans->sendState == STATE_SEND_FILE_DONE) {
283             NotifyTransMsg(dFileTrans, DFILE_TRANS_MSG_FILE_SENT);
284         }
285     } else {
286         if (dFileTrans->recvState == STATE_RECEIVE_FILE_FAIL) {
287             NotifyTransMsg(dFileTrans, DFILE_TRANS_MSG_FILE_RECEIVE_FAIL);
288         } else if (dFileTrans->recvState == STATE_RECEIVE_FILE_DONE) {
289             NotifyTransMsg(dFileTrans, DFILE_TRANS_MSG_END);
290         }
291     }
292 }
293 
DFileTransStateFinished(DFileTrans * dFileTrans)294 static uint8_t DFileTransStateFinished(DFileTrans *dFileTrans)
295 {
296     if ((dFileTrans->isSender &&
297         (dFileTrans->sendState == STATE_SEND_FILE_FAIL || dFileTrans->sendState == STATE_SEND_FILE_DONE)) ||
298         (!dFileTrans->isSender &&
299         (dFileTrans->recvState == STATE_RECEIVE_FILE_FAIL || dFileTrans->recvState == STATE_RECEIVE_FILE_DONE))) {
300         return NSTACKX_TRUE;
301     }
302 
303     return NSTACKX_FALSE;
304 }
305 
SendFrame(DFileTrans * dFileTrans,uint8_t * frame,size_t frameLength,DFileSendState * nextSend,DFileReceiveState * nextRecv)306 int32_t SendFrame(DFileTrans *dFileTrans, uint8_t *frame, size_t frameLength, DFileSendState *nextSend,
307     DFileReceiveState *nextRecv)
308 {
309     SetDfileFrameTransID((DFileFrame *)frame, dFileTrans->transId);
310     int32_t ret = dFileTrans->writeHandle(frame, frameLength, dFileTrans->context);
311     if (ret != (int32_t)frameLength) {
312         /* Data was not sent. */
313         if (ret != NSTACKX_EAGAIN) {
314             if (dFileTrans->isSender && nextSend != NULL) {
315                 *nextSend = STATE_SEND_FILE_FAIL;
316             }
317             if (!dFileTrans->isSender && nextRecv != NULL) {
318                 *nextRecv = STATE_RECEIVE_FILE_FAIL;
319             }
320             ret = NSTACKX_EFAILED;
321             dFileTrans->errorCode = DFILE_TRANS_SOCKET_ERROR;
322         }
323         return ret;
324     }
325     return NSTACKX_EOK;
326 }
327 
ExtendTimeout(uint32_t * timeout,uint32_t maxTimeout)328 static inline void ExtendTimeout(uint32_t *timeout, uint32_t maxTimeout)
329 {
330     if (*timeout < maxTimeout) {
331         *timeout *= NSTACKX_DFILE_BACKOFF_FACTOR;
332         if (*timeout > maxTimeout) {
333             *timeout = maxTimeout;
334         }
335     }
336 }
337 
SendFileHeader(DFileTrans * dFileTrans,DFileSendState * nextState)338 static void SendFileHeader(DFileTrans *dFileTrans, DFileSendState *nextState)
339 {
340     uint32_t fileNum;
341     if (dFileTrans->fileList->tarFlag == NSTACKX_TRUE) {
342         fileNum = 1;
343     } else {
344         fileNum = FileListGetNum(dFileTrans->fileList);
345     }
346     do {
347         (void)memset_s(dFileTrans->sendBuffer, sizeof(dFileTrans->sendBuffer), 0, sizeof(dFileTrans->sendBuffer));
348 
349         int32_t lastEncodeHeaderFileId = dFileTrans->lastSentHeaderFileId;
350         EncodeFileHeaderFrame(dFileTrans->fileList, &lastEncodeHeaderFileId, dFileTrans->sendBuffer,
351             dFileTrans->mtu, &dFileTrans->sendBufferLength);
352         int32_t ret = SendFrame(dFileTrans, dFileTrans->sendBuffer, dFileTrans->sendBufferLength, nextState, NULL);
353         if (ret != NSTACKX_EOK) {
354             break;
355         }
356 
357         DFILE_LOGI(TAG, "transId %hu send header successfully. len %zu lastEncodeHeaderFileId %d, fileNum %u",
358              dFileTrans->transId, dFileTrans->sendBufferLength, lastEncodeHeaderFileId, fileNum);
359 
360         dFileTrans->lastSentHeaderFileId = lastEncodeHeaderFileId;
361         if (dFileTrans->lastSentHeaderFileId == (int32_t)fileNum) {
362             *nextState = STATE_WAIT_FOR_FILE_HEADER_CONFIRM;
363             break;
364         }
365     } while (NSTACKX_TRUE);
366 }
367 
FileManagerSenderMsgHandler(uint16_t fileId,FileManagerMsgType msgType,FileManagerMsg * msg,DFileTrans * dFileTrans)368 void FileManagerSenderMsgHandler(uint16_t fileId, FileManagerMsgType msgType, FileManagerMsg *msg,
369                                  DFileTrans *dFileTrans)
370 {
371     char *files[NSTACKX_DFILE_MAX_FILE_NUM] = {0};
372     if (dFileTrans == NULL) {
373         return;
374     }
375     if (msgType != FILE_MANAGER_TRANS_IN_PROGRESS) {
376         DFILE_LOGI(TAG, "transId %u, Sender: File Id %u got message (%d) from file manager, code %d",
377              dFileTrans->transId, fileId, msgType, (msgType == FILE_MANAGER_SEND_FAIL) ? msg->errorCode : 0);
378     }
379 
380     if (msgType == FILE_MANAGER_TRANS_IN_PROGRESS) {
381         msg->fileList.fileNum = NSTACKX_DFILE_MAX_FILE_NUM;
382         msg->fileList.userData = dFileTrans->fileList->userData;
383         msg->fileList.transId = dFileTrans->transId;
384         FileListGetNames(dFileTrans->fileList, files, &msg->fileList.fileNum, dFileTrans->fileList->noticeFileNameType);
385         msg->fileList.files = (const char **)files;
386         dFileTrans->msgReceiver(dFileTrans, DFILE_TRANS_MSG_IN_PROGRESS, msg);
387         return;
388     }
389     if (msgType == FILE_MANAGER_SEND_FAIL) {
390         dFileTrans->errorCode = DFILE_TRANS_FILE_SEND_TASK_ERROR;
391         SetSendState(dFileTrans, STATE_SEND_FILE_FAIL);
392         NotifyTransMsg(dFileTrans, DFILE_TRANS_MSG_FILE_SEND_FAIL);
393     }
394 }
395 
FileManagerTransMsgHandler(uint16_t fileId,FileManagerMsgType msgType,FileManagerMsg * msg,void * context,uint16_t transId)396 static void FileManagerTransMsgHandler(uint16_t fileId, FileManagerMsgType msgType, FileManagerMsg *msg, void *context,
397     uint16_t transId)
398 {
399     DFileSession *session = (DFileSession *)context;
400     List *pos = NULL;
401     DFileTrans *dFileTrans = NULL;
402     uint8_t isFound = NSTACKX_FALSE;
403     if (session == NULL || session->closeFlag) {
404         return;
405     }
406     LIST_FOR_EACH(pos, &session->dFileTransChain) {
407         dFileTrans = (DFileTrans *)pos;
408         if (dFileTrans != NULL && dFileTrans->transId == transId) {
409             isFound = NSTACKX_TRUE;
410             break;
411         }
412     }
413     if (!isFound) {
414         DFILE_LOGE(TAG, "can't get valid trans %u to send msg", transId);
415         return;
416     }
417 
418     if (dFileTrans->isSender) {
419         FileManagerSenderMsgHandler(fileId, msgType, msg, dFileTrans);
420     } else {
421         FileManagerReceiverMsgHandler(fileId, msgType, msg, dFileTrans);
422     }
423 }
424 
StartFileManagerSenderTask(DFileTrans * dFileTrans)425 static int32_t StartFileManagerSenderTask(DFileTrans *dFileTrans)
426 {
427     FileListMsgPara msgPara;
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     uint32_t i;
443     for (i = 0; i < FileListGetNum(fileList); i++) {
444         sendFileListInfo.fileList[i] = fileList->list[i].fullFileName;
445         sendFileListInfo.fileSize[i] = fileList->list[i].fileSize;
446         sendFileListInfo.startOffset[i] = fileList->list[i].startOffset;
447     }
448 
449     if (fileList->tarFlag == NSTACKX_TRUE) {
450         sendFileListInfo.fileList[i] = fileList->tarFile;
451     }
452     sendFileListInfo.transId = dFileTrans->transId;
453     sendFileListInfo.fileNum = FileListGetNum(fileList);
454     sendFileListInfo.tarFlag = fileList->tarFlag;
455     sendFileListInfo.smallFlag = fileList->smallFlag;
456     msgPara.msgReceiver = FileManagerTransMsgHandler;
457     msgPara.context = dFileTrans->session;
458     int32_t ret = FileManagerSendFileTask(dFileTrans->fileManager, &sendFileListInfo, &msgPara);
459     if (ret != NSTACKX_EOK) {
460         DFILE_LOGE(TAG, "Start send file task fail %d", ret);
461         return ret;
462     }
463     dFileTrans->fileManagerTaskStarted = NSTACKX_TRUE;
464     dFileTrans->totalDataFrameCnt = GetTotalFrameCount(dFileTrans);
465     return NSTACKX_EOK;
466 }
467 
WaitForFileHeaderConfirmPrepare(DFileTrans * dFileTrans)468 static void WaitForFileHeaderConfirmPrepare(DFileTrans *dFileTrans)
469 {
470     dFileTrans->lastSentHeaderFileId = -1;
471     if (dFileTrans->headerRetryCnt == 0) {
472         dFileTrans->timeout = dFileTrans->config.maxRtt;
473     } else {
474         ExtendTimeout(&dFileTrans->timeout, dFileTrans->config.maxFileHeaderConfirmFrameTimeout);
475     }
476     ClockGetTime(CLOCK_MONOTONIC, &dFileTrans->ts);
477 }
478 
WaitForFileHeaderConfirm(DFileTrans * dFileTrans,DFileSendState * nextState)479 static void WaitForFileHeaderConfirm(DFileTrans *dFileTrans, DFileSendState *nextState)
480 {
481     if (FileListAllFileNameAcked(dFileTrans->fileList)) {
482         int32_t ret = StartFileManagerSenderTask(dFileTrans);
483         if (ret == NSTACKX_EOK) {
484             *nextState = STATE_SEND_FILE_DATA_ONGOING;
485         } else {
486             *nextState = STATE_SEND_FILE_FAIL;
487             dFileTrans->errorCode = DFILE_TRANS_INTERNAL_ERROR;
488         }
489         return;
490     }
491 
492     if (GetElapseTime(&dFileTrans->ts) >= dFileTrans->timeout) {
493         if (dFileTrans->headerRetryCnt > dFileTrans->config.maxCtrlFrameRetryCnt) {
494             *nextState = STATE_SEND_FILE_FAIL;
495             dFileTrans->errorCode = DFILE_TRANS_FILE_HEADER_CONFIRM_TIMEOUT;
496             WaitFileHeaderTimeoutEvent(dFileTrans->errorCode);
497             return;
498         }
499         dFileTrans->headerRetryCnt++;
500         *nextState = STATE_SEND_FILE_HEADER_ONGOING;
501     }
502 }
503 
SendFileBlockPrepare(DFileTrans * dFileTrans)504 static void SendFileBlockPrepare(DFileTrans *dFileTrans)
505 {
506     ClockGetTime(CLOCK_MONOTONIC, &dFileTrans->ts);
507     dFileTrans->timeout = dFileTrans->config.initialAckInterval;
508     NotifyTransMsg(dFileTrans, DFILE_TRANS_MSG_FILE_SEND_DATA);
509 }
510 
SendFileDataOngoing(DFileTrans * dFileTrans,DFileSendState * nextState)511 static void SendFileDataOngoing(DFileTrans *dFileTrans, DFileSendState *nextState)
512 {
513     if (dFileTrans->fileTransferDoneReceived) {
514         *nextState = STATE_SEND_FILE_TRANSFER_DONE_ACK;
515         return;
516     }
517     if (GetElapseTime(&dFileTrans->ts) >= dFileTrans->timeout) {
518         if (!CapsTcp(dFileTrans->session)) {
519             dFileTrans->lostAckCnt++;
520             DFILE_LOGW(TAG, "transId %u Sender lost ACK count %u totalRecvBlocks %llu inboundQueueSize %llu",
521                 dFileTrans->transId, dFileTrans->lostAckCnt,
522                 NSTACKX_ATOM_FETCH(&(dFileTrans->session->totalRecvBlocks)),
523                 dFileTrans->session->inboundQueueSize);
524             if (dFileTrans->lostAckCnt >= dFileTrans->config.maxAckCnt) {
525                 *nextState = STATE_SEND_FILE_FAIL;
526                 dFileTrans->errorCode = DFILE_TRANS_FILE_DATA_ACK_TIMEOUT;
527                 DFILE_LOGW(TAG, "transId %u Sender lost too many ACK count", dFileTrans->transId);
528                 return;
529             }
530         }
531 
532         /* Update timestamp */
533         ClockGetTime(CLOCK_MONOTONIC, &dFileTrans->ts);
534         return;
535     }
536 
537     if (FileManagerIsLastBlockRead(dFileTrans->fileManager, dFileTrans->transId)) {
538         *nextState = STATE_WAIT_FOR_FILE_TRANSFER_DONE_FRAME;
539     }
540 }
541 
WaitForFileTransferDonePrepare(DFileTrans * dFileTrans)542 static void WaitForFileTransferDonePrepare(DFileTrans *dFileTrans)
543 {
544     ClockGetTime(CLOCK_MONOTONIC, &dFileTrans->ts);
545     dFileTrans->timeout = dFileTrans->config.maxCtrlFrameTimeout;
546 }
547 
WaitForFileTransferDoneFrame(DFileTrans * dFileTrans,DFileSendState * nextState)548 static void WaitForFileTransferDoneFrame(DFileTrans *dFileTrans, DFileSendState *nextState)
549 {
550     if (dFileTrans->fileTransferDoneReceived) {
551         *nextState = STATE_SEND_FILE_TRANSFER_DONE_ACK;
552     }
553 
554     if (GetElapseTime(&dFileTrans->ts) >= dFileTrans->timeout) {
555         if (CapsTcp(dFileTrans->session)) {
556             *nextState = STATE_SEND_FILE_DATA_ONGOING;
557             return;
558         }
559         *nextState = STATE_SEND_FILE_FAIL;
560         dFileTrans->errorCode = DFILE_TRANS_TRANSFER_DONE_TIMEOUT;
561         return;
562     }
563 
564     /* Need to re-send data block. */
565     if (!FileManagerIsLastBlockRead(dFileTrans->fileManager, dFileTrans->transId)) {
566         *nextState = STATE_SEND_FILE_DATA_ONGOING;
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     }
700 }
701 
NotifyRecvSucMsg(DFileTrans * dFileTrans)702 static void NotifyRecvSucMsg(DFileTrans *dFileTrans)
703 {
704     if (dFileTrans->isRecvSucMsgNotified) {
705         return;
706     }
707     NotifyTransMsg(dFileTrans, DFILE_TRANS_MSG_FILE_RECEIVED);
708     dFileTrans->isRecvSucMsgNotified = NSTACKX_TRUE;
709 }
710 
FileManagerReceiverMsgHandler(uint16_t fileId,FileManagerMsgType msgType,FileManagerMsg * msg,DFileTrans * dFileTrans)711 void FileManagerReceiverMsgHandler(uint16_t fileId, FileManagerMsgType msgType, FileManagerMsg *msg,
712                                    DFileTrans *dFileTrans)
713 {
714     if (dFileTrans == NULL) {
715         return;
716     }
717     if (msgType != FILE_MANAGER_RECEIVE_SUCCESS) {
718         DFILE_LOGE(TAG, "transId %u, Receiver: File Id %u got message (%d) from file manager, code %d",
719              dFileTrans->transId, fileId, msgType, (msgType == FILE_MANAGER_RECEIVE_FAIL) ? msg->errorCode : 0);
720     }
721 
722     if (msgType == FILE_MANAGER_RECEIVE_FAIL) {
723         dFileTrans->errorCode = DFILE_TRANS_FILE_RECEIVE_TASK_ERROR;
724         SetReceiveState(dFileTrans, STATE_RECEIVE_FILE_FAIL);
725         NotifyTransMsg(dFileTrans, DFILE_TRANS_MSG_FILE_RECEIVE_FAIL);
726         return;
727     }
728 
729     if (fileId) {
730         if (msgType == FILE_MANAGER_RECEIVE_SUCCESS) {
731             FileListSetFileReceiveSuccess(dFileTrans->fileList, fileId);
732         }
733         if (FileListAllFileReceived(dFileTrans->fileList)) {
734             /*
735              * When all files are empty, it won't enter RECEIVE_DATA_ON_GOING state.
736              * We have to set allFileDataReceived in this case
737              */
738             dFileTrans->allFileDataReceived = NSTACKX_TRUE;
739             dFileTrans->ioWriteFinishFlag = NSTACKX_TRUE;
740             NotifyRecvSucMsg(dFileTrans);
741             ReceiverFsm(dFileTrans);
742             dFileTrans->isAckSend = NSTACKX_FALSE;
743         }
744     }
745 }
746 
StartFileManagerReceiverTask(DFileTrans * dFileTrans)747 static int32_t StartFileManagerReceiverTask(DFileTrans *dFileTrans)
748 {
749     RecvFileListInfo fileListInfo;
750     FileList *fileList = dFileTrans->fileList;
751     FileListMsgPara msgPara;
752 
753     if (dFileTrans->fileManagerTaskStarted) {
754         return NSTACKX_EOK;
755     }
756     fileListInfo.fileBasicInfo = calloc(FileListGetNum(fileList), sizeof(FileBaseInfo));
757     if (fileListInfo.fileBasicInfo == NULL) {
758         return NSTACKX_ENOMEM;
759     }
760 
761     for (uint32_t i = 0; i < FileListGetNum(fileList); i++) {
762         fileListInfo.fileBasicInfo[i].fileSize = fileList->list[i].fileSize;
763         fileListInfo.fileBasicInfo[i].fileId = fileList->list[i].fileId;
764         fileListInfo.fileBasicInfo[i].fileName = fileList->list[i].fileName;
765         fileListInfo.fileBasicInfo[i].startOffset = fileList->list[i].startOffset;
766         dFileTrans->totalBytes += fileList->list[i].fileSize;
767     }
768 
769     fileListInfo.pathType = FileListGetPathType(fileList);
770     fileListInfo.fileNum = FileListGetNum(fileList);
771     fileListInfo.transId = dFileTrans->transId;
772     fileListInfo.noSyncFlag = fileList->noSyncFlag;
773     msgPara.msgReceiver = FileManagerTransMsgHandler;
774     msgPara.context = dFileTrans->session;
775     int32_t ret = FileManagerRecvFileTask(dFileTrans->fileManager, &fileListInfo, &msgPara);
776     if (ret != NSTACKX_EOK) {
777         DFILE_LOGE(TAG, "Start receive task fail %d", ret);
778         free(fileListInfo.fileBasicInfo);
779         return NSTACKX_EFAILED;
780     }
781     dFileTrans->fileManagerTaskStarted = NSTACKX_TRUE;
782     free(fileListInfo.fileBasicInfo);
783     return NSTACKX_EOK;
784 }
785 
SendFileHeaderConfirm(DFileTrans * dFileTrans,DFileReceiveState * nextState)786 static void SendFileHeaderConfirm(DFileTrans *dFileTrans, DFileReceiveState *nextState)
787 {
788     do {
789         (void)memset_s(dFileTrans->sendBuffer, sizeof(dFileTrans->sendBuffer), 0, sizeof(dFileTrans->sendBuffer));
790         uint16_t lastEncAckedHeaderFileId = dFileTrans->lastAckedHeaderFileId;
791         EncodeFileHeaderConfirmFrame(dFileTrans->fileList, &lastEncAckedHeaderFileId,
792             dFileTrans->sendBuffer, dFileTrans->mtu, &dFileTrans->sendBufferLength);
793         int32_t ret = SendFrame(dFileTrans, dFileTrans->sendBuffer, dFileTrans->sendBufferLength, NULL, nextState);
794         if (ret != NSTACKX_EOK) {
795             return;
796         }
797         dFileTrans->lastAckedHeaderFileId = lastEncAckedHeaderFileId;
798         if (dFileTrans->lastAckedHeaderFileId == FileListGetNum(dFileTrans->fileList)) {
799             DFILE_LOGI(TAG, "transId %u last send header confirm successfully. len %u",
800                 dFileTrans->transId, dFileTrans->sendBufferLength);
801             break;
802         }
803     } while (NSTACKX_TRUE);
804 
805     if (dFileTrans->allFileNameReceived) {
806         if (StartFileManagerReceiverTask(dFileTrans) != NSTACKX_EOK) {
807             *nextState = STATE_RECEIVE_FILE_FAIL;
808             dFileTrans->errorCode = DFILE_TRANS_INTERNAL_ERROR;
809         } else {
810             *nextState = STATE_RECEIVE_FILE_DATA_ONGOING;
811         }
812     } else {
813         /* Timeout, check should retry or fail */
814         if (dFileTrans->headerAckRetryCnt > dFileTrans->config.maxCtrlFrameRetryCnt) {
815             *nextState = STATE_RECEIVE_FILE_FAIL;
816             dFileTrans->errorCode = DFILE_TRANS_FILE_HEADER_TIMEOUT;
817             return;
818         }
819         *nextState = STATE_RECEIVE_FILE_HEADER_ONGOING;
820         dFileTrans->headerAckRetryCnt++;
821     }
822 }
823 
GetTotalFrameCount(DFileTrans * dFileTrans)824 static uint64_t GetTotalFrameCount(DFileTrans *dFileTrans)
825 {
826     uint64_t totalFrameCount = 0;
827     uint32_t lastSequence;
828 
829     for (uint16_t fileId = NSTACKX_FIRST_FILE_ID; fileId <= FileListGetNum(dFileTrans->fileList); fileId++) {
830         if (!FileListGetFileSize(dFileTrans->fileList, fileId)) {
831             continue;
832         }
833         int32_t ret = FileManagerGetLastSequence(dFileTrans->fileManager, dFileTrans->transId, fileId, &lastSequence);
834         if (ret != NSTACKX_EOK) {
835             continue;
836         }
837         totalFrameCount += (lastSequence + 1);
838     }
839     return totalFrameCount;
840 }
841 
ReceiveFileDataPrepare(DFileTrans * dFileTrans)842 static void ReceiveFileDataPrepare(DFileTrans *dFileTrans)
843 {
844     PeerInfo *peerInfo = dFileTrans->context;
845     if (dFileTrans->recvState == STATE_SEND_FILE_HEADER_CONFIRM) {
846         /* Update time stamp when entering from "HEADER" stage to "DATA" state */
847         ClockGetTime(CLOCK_MONOTONIC, &dFileTrans->ts);
848         ClockGetTime(CLOCK_MONOTONIC, &dFileTrans->heartBeatTs);
849 
850         dFileTrans->timeout = dFileTrans->config.initialRecvIdleTimeout;
851         dFileTrans->ackInterval = peerInfo->ackInterval;
852         dFileTrans->transRetryCount = dFileTrans->config.maxRetryPageCnt;
853         dFileTrans->receivedDataFrameCnt = 0;
854         dFileTrans->totalDataFrameCnt = GetTotalFrameCount(dFileTrans);
855         dFileTrans->adjustAckIntervalLimit = NstackAdjustAckIntervalRatio(dFileTrans->totalDataFrameCnt);
856         ClockGetTime(CLOCK_MONOTONIC, &dFileTrans->retryAllPacketTs);
857 #if DFILE_SHOW_RECEIVE_TIME
858         ClockGetTime(CLOCK_MONOTONIC, &dFileTrans->startTs);
859 #endif
860     }
861 }
862 
ReceiverIdleTimeout(DFileTrans * dFileTrans,DFileReceiveState * nextState)863 static uint8_t ReceiverIdleTimeout(DFileTrans *dFileTrans, DFileReceiveState *nextState)
864 {
865     uint8_t timeout = NSTACKX_FALSE;
866     uint32_t elapseTime = GetElapseTime(&dFileTrans->ts);
867     if (elapseTime >= dFileTrans->timeout) {
868         dFileTrans->idleTimeoutCnt++;
869         DFILE_LOGE(TAG,
870             "transId %u: Over %u ms not recv data. idleTimeoutCnt %u last fileid %u sequence %u recv %llu all %llu",
871             dFileTrans->transId, elapseTime, dFileTrans->idleTimeoutCnt, dFileTrans->lastFileDataRecvFileId,
872             dFileTrans->lastFileDataSequence, dFileTrans->receivedDataFrameCnt, dFileTrans->totalDataFrameCnt);
873         timeout = NSTACKX_TRUE;
874     }
875 
876     if (timeout && dFileTrans->idleTimeoutCnt >= dFileTrans->config.maxRecvIdleCnt) {
877         if (!CapsTcp(dFileTrans->session)) {
878             return NSTACKX_TRUE;
879         }
880     }
881 
882     if (timeout) {
883         ClockGetTime(CLOCK_MONOTONIC, &dFileTrans->ts);
884         *nextState = STATE_SEND_FILE_DATA_ACK;
885     }
886     return NSTACKX_FALSE;
887 }
888 
RefreshFileRecvStatus(DFileTrans * dFileTrans)889 static int32_t RefreshFileRecvStatus(DFileTrans *dFileTrans)
890 {
891     uint16_t fileIdList[NSTACKX_DFILE_MAX_FILE_NUM] = {0};
892     uint8_t fileIdSuccessFlag[NSTACKX_DFILE_MAX_FILE_NUM] = {0};
893     uint32_t fileIdNum = NSTACKX_DFILE_MAX_FILE_NUM;
894     if (FileManagerGetReceivedFiles(dFileTrans->fileManager, dFileTrans->transId,
895         fileIdList, fileIdSuccessFlag, &fileIdNum) != NSTACKX_EOK) {
896         DFILE_LOGE(TAG, "transId %u get received files failed", dFileTrans->transId);
897         return NSTACKX_EFAILED;
898     }
899     if (fileIdNum == 0) {
900         DFILE_LOGI(TAG, "transId %u get zero received files", dFileTrans->transId);
901         return NSTACKX_EOK;
902     }
903     for (uint32_t i = 0; i < fileIdNum; i++) {
904         if (fileIdList[i] == 0) {
905             continue;
906         }
907         if (fileIdSuccessFlag[i]) {
908             FileListSetFileReceiveSuccess(dFileTrans->fileList, fileIdList[i]);
909         } else {
910             FileListSetFileReceiveFail(dFileTrans->fileList, fileIdList[i]);
911         }
912     }
913     return NSTACKX_EOK;
914 }
915 
ReceiveFileDataOngoing(DFileTrans * dFileTrans,DFileReceiveState * nextState)916 static void ReceiveFileDataOngoing(DFileTrans *dFileTrans, DFileReceiveState *nextState)
917 {
918     if (dFileTrans->dupFileName) {
919         dFileTrans->dupFileName = NSTACKX_FALSE;
920         *nextState = STATE_SEND_FILE_HEADER_CONFIRM;
921         return;
922     }
923 
924     if (dFileTrans->allFileDataReceived) {
925         if (dFileTrans->ioWriteFinishFlag == NSTACKX_FALSE) {
926             return;
927         }
928         if (RefreshFileRecvStatus(dFileTrans) != NSTACKX_EOK) {
929             DFILE_LOGE(TAG, "transId %u refresh file receive status failed", dFileTrans->transId);
930             *nextState = STATE_RECEIVE_FILE_FAIL;
931             dFileTrans->errorCode = DFILE_TRANS_FILE_RECEIVE_TASK_ERROR;
932             return;
933         }
934         if (FileListAllFileReceived(dFileTrans->fileList)) {
935             *nextState = STATE_SEND_FILE_TRANSFER_DONE;
936             return;
937         }
938     } else {
939         if (ReceiverIdleTimeout(dFileTrans, nextState)) {
940             *nextState = STATE_RECEIVE_FILE_FAIL;
941             dFileTrans->errorCode = DFILE_TRANS_FILE_DATA_TIMEOUT;
942             return;
943         }
944     }
945 
946     if (*nextState != STATE_SEND_FILE_DATA_ACK && GetElapseTime(&dFileTrans->heartBeatTs) >= dFileTrans->ackInterval) {
947         if (dFileTrans->allFileDataReceived) {
948             if (FileManagerSetAllDataReceived(dFileTrans->fileManager, dFileTrans->transId) != NSTACKX_EOK) {
949                 DFILE_LOGE(TAG, "transId %u get set all file data received failed", dFileTrans->transId);
950                 *nextState = STATE_RECEIVE_FILE_FAIL;
951                 dFileTrans->errorCode = DFILE_TRANS_FILE_RECEIVE_TASK_ERROR;
952                 return;
953             }
954         }
955         *nextState = STATE_SEND_FILE_DATA_ACK;
956         dFileTrans->isAckSend = NSTACKX_TRUE;
957     }
958 }
959 
SendFileTransferDoneFrame(DFileTrans * dFileTrans,DFileReceiveState * nextState)960 static void SendFileTransferDoneFrame(DFileTrans *dFileTrans, DFileReceiveState *nextState)
961 {
962     uint16_t fileIdList[NSTACKX_DFILE_MAX_FILE_NUM] = {0};
963     uint32_t fileIdNum = NSTACKX_DFILE_MAX_FILE_NUM;
964 
965     if (GetElapseTime(&dFileTrans->ts) >= dFileTrans->timeout) {
966         dFileTrans->errorCode = DFILE_TRANS_FILE_WRITE_FAIL;
967         DFILE_LOGE(TAG, "SendFileTransferDoneFrame timeout");
968         *nextState = STATE_RECEIVE_FILE_FAIL;
969         return;
970     }
971     NotifyRecvSucMsg(dFileTrans);
972 
973     FileListGetReceivedFileIdList(dFileTrans->fileList, fileIdList, &fileIdNum);
974     (void)memset_s(dFileTrans->sendBuffer, sizeof(dFileTrans->sendBuffer), 0, sizeof(dFileTrans->sendBuffer));
975     /*
976      * Currently max file number is 500, and default MTU is 1500, so one MTU can contain all the file Id.
977      */
978     EncodeFileTransferDoneFrame(dFileTrans->sendBuffer, dFileTrans->mtu, fileIdList, fileIdNum,
979         &dFileTrans->sendBufferLength);
980     int32_t ret = SendFrame(dFileTrans, dFileTrans->sendBuffer, dFileTrans->sendBufferLength, NULL, nextState);
981     if (ret != NSTACKX_EOK) {
982         return;
983     }
984     DFILE_LOGI(TAG, "file trans fer done frame: transId %u, frameLen %u, fileIdNum %u",
985          dFileTrans->transId, dFileTrans->sendBufferLength, fileIdNum);
986     *nextState = STATE_WAIT_FOR_FILE_TRANSFER_DONE_ACK;
987 }
988 
WaitForFileTransferDoneAckPrepare(DFileTrans * dFileTrans)989 static void WaitForFileTransferDoneAckPrepare(DFileTrans *dFileTrans)
990 {
991     ClockGetTime(CLOCK_MONOTONIC, &dFileTrans->ts);
992     dFileTrans->timeout = dFileTrans->config.maxRtt;
993 }
994 
WaitForFileTransferDoneAck(DFileTrans * dFileTrans,DFileReceiveState * nextState)995 static void WaitForFileTransferDoneAck(DFileTrans *dFileTrans, DFileReceiveState *nextState)
996 {
997     if (dFileTrans->fileTransferDoneAcked) {
998         *nextState = STATE_RECEIVE_FILE_DONE;
999         return;
1000     }
1001 
1002     if (GetElapseTime(&dFileTrans->ts) >= dFileTrans->timeout) {
1003         if (dFileTrans->transferDoneRetryCnt > dFileTrans->config.maxCtrlFrameRetryCnt &&
1004             !CapsTcp(dFileTrans->session)) {
1005             dFileTrans->errorCode = DFILE_TRANS_TRANSFER_DONE_ACK_TIMEOUT;
1006             *nextState = STATE_RECEIVE_FILE_FAIL;
1007             DFILE_LOGI(TAG, "transId %u enter WaitForFileTransferDoneAck and next state is STATE_RECEIVE_FILE_FAIL",
1008                  dFileTrans->transId);
1009             return;
1010         }
1011         /* Prepare to enter STATE_SEND_FILE_TRANSFER_DONE again */
1012         ClockGetTime(CLOCK_MONOTONIC, &dFileTrans->ts);
1013         dFileTrans->transferDoneRetryCnt++;
1014         *nextState = STATE_SEND_FILE_TRANSFER_DONE;
1015         DFILE_LOGI(TAG, "transId %u enter WaitForFileTransferDoneAck and next state is STATE_SEND_FILE_TRANSFER_DONE",
1016              dFileTrans->transId);
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         DFILE_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         DFILE_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         DFILE_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         DFILE_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             DFILE_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             DFILE_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             DFILE_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             DFILE_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         DFILE_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         DFILE_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             DFILE_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             DFILE_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         DFILE_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         DFILE_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         DFILE_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         DFILE_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         DFILE_LOGI(TAG, "transId:%u last block received:%u", trans->transId, received);
1337         if (received) {
1338             trans->allFileDataReceived = NSTACKX_TRUE;
1339             DFILE_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         DFILE_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         DFILE_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         DFILE_LOGI(TAG, "transId %u FileManagerStopTask", dFileTrans->transId);
1554         if (FileManagerStopTask(dFileTrans->fileManager, dFileTrans->transId, FILE_LIST_TRANSFER_FINISH) !=
1555             NSTACKX_EOK) {
1556             DFILE_LOGE(TAG, "transId %u FileManagerStopTask failed", dFileTrans->transId);
1557         }
1558     }
1559 
1560     FileListDestroy(dFileTrans->fileList);
1561     free(dFileTrans);
1562 }
1563 
DFileTransGetTotalBytes(const DFileTrans * dFileTrans)1564 uint64_t DFileTransGetTotalBytes(const DFileTrans *dFileTrans)
1565 {
1566     if (dFileTrans == NULL) {
1567         return 0;
1568     }
1569     return GetFilesTotalBytes(dFileTrans->fileList);
1570 }
1571