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