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