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