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_file_manager_client.h"
17 
18 #include "securec.h"
19 
20 #include "nstackx_dev.h"
21 #include "nstackx_dfile_mp.h"
22 #include "nstackx_dfile_session.h"
23 #include "nstackx_error.h"
24 #include "nstackx_event.h"
25 #include "nstackx_dfile_log.h"
26 #ifdef MBEDTLS_INCLUDED
27 #include "nstackx_mbedtls.h"
28 #else
29 #include "nstackx_openssl.h"
30 #endif
31 #include "nstackx_util.h"
32 
33 #define TAG "nStackXDFile"
34 
CheckSendListFullAndWait(FileManager * fileManager,sem_t * sem)35 static void CheckSendListFullAndWait(FileManager *fileManager, sem_t *sem)
36 {
37     int32_t semValue;
38     SemGetValue(sem, &semValue);
39     if (semValue == 0) {
40         fileManager->sendListFullTimes++;
41     }
42     SemWait(sem);
43 }
44 
ReadFromFile(FileManager * fileManager,FileInfo * fileInfo,uint64_t offset,uint8_t * buffer,uint32_t bufferLength)45 static int32_t ReadFromFile(FileManager *fileManager, FileInfo *fileInfo, uint64_t offset, uint8_t *buffer,
46     uint32_t bufferLength)
47 {
48     uint32_t readLength;
49     DFileSession *session = fileManager->context;
50 
51     offset += fileInfo->startOffset;
52     if (fileInfo->tarData != NULL) {
53         if (offset + bufferLength > fileInfo->writeOffset ||
54             memcpy_s(buffer, bufferLength, fileInfo->tarData + offset, bufferLength) != EOK) {
55             DFILE_LOGE(TAG, "memcpy_s failed");
56             return NSTACKX_EFAILED;
57         }
58         fileInfo->fileOffset = offset + bufferLength;
59         return NSTACKX_EOK;
60     }
61     if (fileInfo->fd == NSTACKX_INVALID_FD) {
62 #ifdef BUILD_FOR_WINDOWS
63         fileInfo->fd = fopen(fileInfo->fileName, "rb");
64 #else
65         fileInfo->fd = open(fileInfo->fileName, O_RDONLY);
66 #endif
67         if (fileInfo->fd == NSTACKX_INVALID_FD) {
68             fileInfo->errCode = ConvertErrCode(errno);
69             DFILE_LOGE(TAG, "file open failed, path %s errno %d", fileInfo->fileName, errno);
70             return NSTACKX_EFAILED;
71         }
72         fileInfo->fileOffset = 0;
73     }
74 
75     if (SetFileOffset(fileInfo, offset) != NSTACKX_EOK) {
76         fileInfo->errCode = FILE_MANAGER_FILE_EOTHER;
77         DFILE_LOGE(TAG, "set file offset failed");
78         return NSTACKX_EFAILED;
79     }
80 
81     if (CapsNoRW(session)) {
82         readLength = bufferLength;
83     } else {
84 #ifdef BUILD_FOR_WINDOWS
85         readLength = (uint32_t)fread(buffer, 1, bufferLength, fileInfo->fd);
86 #else
87         /* use pread because fseek have multi-thread issue in case of multi-path handle same file scenario */
88         readLength = (uint32_t)pread(fileInfo->fd, buffer, bufferLength, (int64_t)offset);
89 #endif
90     }
91 
92     if (readLength != bufferLength) {
93         DFILE_LOGE(TAG, "fread error %d read %u target %hu", GetErrno(), readLength, bufferLength);
94         fileInfo->errCode = FILE_MANAGER_FILE_EOTHER;
95         return NSTACKX_EFAILED;
96     }
97 
98     fileInfo->fileOffset += readLength;
99     return NSTACKX_EOK;
100 }
101 
GetEncryptedDataFrame(FileManager * fileManager,CryptPara * cryptPara,FileInfo * fileInfo,uint32_t targetSequence)102 static FileDataFrame *GetEncryptedDataFrame(FileManager *fileManager, CryptPara *cryptPara, FileInfo *fileInfo,
103                                             uint32_t targetSequence)
104 {
105     uint8_t *buffer = NULL;
106     uint16_t frameOffset, targetLenth;
107     FileDataFrame *fileDataFrame = NULL;
108     uint64_t fileOffset;
109     uint32_t payLoadLen;
110     fileOffset = ((uint64_t)fileInfo->standardBlockSize) * ((uint64_t)targetSequence);
111     if (targetSequence == fileInfo->totalBlockNum - 1) {
112         targetLenth = (uint16_t)(fileInfo->fileSize - fileOffset);
113     } else {
114         targetLenth = fileInfo->standardBlockSize;
115     }
116     if (targetLenth == 0) {
117         DFILE_LOGE(TAG, "target length is zero");
118         fileInfo->errCode = FILE_MANAGER_FILE_EOTHER;
119         return NULL;
120     }
121     buffer = (uint8_t *)calloc(targetLenth, 1);
122     if (buffer == NULL) {
123         fileInfo->errCode = FILE_MANAGER_ENOMEM;
124         return NULL;
125     }
126     if (ReadFromFile(fileManager, fileInfo, fileOffset, buffer, targetLenth) != NSTACKX_EOK) {
127         goto L_END;
128     }
129     fileManager->iorBytes += (uint64_t)targetLenth;
130     payLoadLen = targetLenth + GCM_ADDED_LEN;
131     frameOffset = offsetof(FileDataFrame, blockPayload);
132     fileDataFrame = (FileDataFrame *)calloc(1, frameOffset + payLoadLen);
133     if (fileDataFrame == NULL) {
134         fileInfo->errCode = FILE_MANAGER_ENOMEM;
135         goto L_END;
136     }
137     fileDataFrame->header.length = htons(frameOffset + payLoadLen - sizeof(DFileFrameHeader));
138     fileDataFrame->fileId = htons(fileInfo->fileId);
139     fileDataFrame->blockSequence = htonl(targetSequence);
140     if (AesGcmEncrypt(buffer, targetLenth, cryptPara, (uint8_t *)fileDataFrame + frameOffset, payLoadLen) == 0) {
141         fileInfo->errCode = FILE_MANAGER_FILE_EOTHER;
142         free(fileDataFrame);
143         fileDataFrame = NULL;
144         DFILE_LOGE(TAG, "data encrypt failed");
145     }
146 
147 L_END:
148     free(buffer);
149     return fileDataFrame;
150 }
151 
GetNoEncryptedDataFrame(FileManager * fileManager,FileInfo * fileInfo,uint32_t targetSequence)152 static FileDataFrame *GetNoEncryptedDataFrame(FileManager *fileManager, FileInfo *fileInfo, uint32_t targetSequence)
153 {
154     uint16_t frameOffset, targetLenth;
155     FileDataFrame *fileDataFrame = NULL;
156     uint64_t fileOffset;
157     uint8_t *buffer = NULL;
158 
159     fileOffset = ((uint64_t)fileInfo->standardBlockSize) * ((uint64_t)targetSequence);
160     if (targetSequence == fileInfo->totalBlockNum - 1) {
161         targetLenth = (uint16_t)(fileInfo->fileSize - fileOffset);
162     } else {
163         targetLenth = fileInfo->standardBlockSize;
164     }
165     frameOffset = offsetof(FileDataFrame, blockPayload);
166     fileDataFrame = (FileDataFrame *)calloc(1, frameOffset + targetLenth);
167     if (fileDataFrame == NULL) {
168         fileInfo->errCode = FILE_MANAGER_ENOMEM;
169         DFILE_LOGE(TAG, "fileDataFrame calloc failed");
170         return NULL;
171     }
172     buffer = (uint8_t *)fileDataFrame + frameOffset;
173     if (ReadFromFile(fileManager, fileInfo, fileOffset, buffer, targetLenth) != NSTACKX_EOK) {
174         free(fileDataFrame);
175         DFILE_LOGE(TAG, "read file failed");
176         return NULL;
177     }
178     fileManager->iorBytes += (uint64_t)targetLenth;
179     fileDataFrame->header.length = htons(frameOffset + targetLenth - sizeof(DFileFrameHeader));
180     fileDataFrame->fileId = htons(fileInfo->fileId);
181     fileDataFrame->blockSequence = htonl(targetSequence);
182     return fileDataFrame;
183 }
184 
GetEncryptedDataTarFrame(CryptPara * cryptPara,uint16_t fileId,FileListTask * fileList,uint16_t targetLenth)185 int32_t GetEncryptedDataTarFrame(CryptPara *cryptPara, uint16_t fileId, FileListTask *fileList, uint16_t targetLenth)
186 {
187     uint16_t frameOffset;
188     FileDataFrame *fileDataFrame = NULL;
189     uint32_t payLoadLen;
190     int32_t errCode = FILE_MANAGER_EOK;
191     uint32_t targetSequence = (uint32_t)(fileList->tarFileInfo.maxSequenceSend);
192     FileDataFrame *buffer = fileList->tarFrame;
193 
194     frameOffset = offsetof(FileDataFrame, blockPayload);
195     payLoadLen = targetLenth + GCM_ADDED_LEN;
196     fileDataFrame = (FileDataFrame *)calloc(1, frameOffset + payLoadLen);
197     if (fileDataFrame == NULL) {
198         errCode = FILE_MANAGER_ENOMEM;
199         return errCode;
200     }
201     fileDataFrame->header.length = htons(frameOffset + payLoadLen - sizeof(DFileFrameHeader));
202     fileDataFrame->fileId = htons(fileId);
203     fileDataFrame->blockSequence = htonl(targetSequence);
204     if (AesGcmEncrypt(buffer->blockPayload, targetLenth, cryptPara, fileDataFrame->blockPayload, payLoadLen) == 0) {
205         DFILE_LOGE(TAG, "AesGcmEncrypt failed, %d-%d", targetLenth, payLoadLen);
206         errCode = FILE_MANAGER_FILE_EOTHER;
207     }
208 
209     if (memcpy_s(buffer, fileList->maxFrameLength, fileDataFrame, frameOffset + payLoadLen) != EOK) {
210         DFILE_LOGE(TAG, "memcpy error");
211         errCode = FILE_MANAGER_FILE_EOTHER;
212     }
213     free(fileDataFrame);
214 
215     return errCode;
216 }
217 
GetNoEncryptedDataTarFrame(uint16_t fileId,FileListTask * fileList,uint16_t targetLenth)218 int32_t GetNoEncryptedDataTarFrame(uint16_t fileId, FileListTask *fileList, uint16_t targetLenth)
219 {
220     FileDataFrame *fileDataFrame = fileList->tarFrame;
221     if (fileDataFrame == NULL) {
222         return FILE_MANAGER_ENOMEM;
223     }
224 
225     fileDataFrame->header.length = htons(targetLenth + sizeof(FileDataFrame) - sizeof(DFileFrameHeader));
226     fileDataFrame->fileId = htons(fileId);
227     fileDataFrame->blockSequence = htonl((uint32_t)fileList->tarFileInfo.maxSequenceSend);
228     return FILE_MANAGER_EOK;
229 }
230 
GetRetranBlockInfo(FileListTask * fileList,uint16_t * fileId,uint32_t * blockSeq,uint32_t * linkSeq)231 static int32_t GetRetranBlockInfo(FileListTask *fileList, uint16_t *fileId, uint32_t *blockSeq, uint32_t *linkSeq)
232 {
233     List *curFront = NULL;
234     uint8_t isPoped;
235     SendRetranRequestNode *retranNode = NULL;
236     if (MutexListPopFront(&fileList->sendRetranList, &curFront, &isPoped) != NSTACKX_EOK) {
237         if (isPoped) {
238             retranNode = (SendRetranRequestNode *)curFront;
239             free(retranNode);
240         }
241         DFILE_LOGE(TAG, "Pop sendRetranList's head error");
242         fileList->errCode = FILE_MANAGER_EMUTEX;
243         return NSTACKX_EFAILED;
244     }
245     retranNode = (SendRetranRequestNode *)curFront;
246     *fileId = retranNode->fileId;
247     *blockSeq = retranNode->blockSequence;
248     *linkSeq = retranNode->linkSequence;
249     free(retranNode);
250     if (*fileId == 0 || *fileId > fileList->fileNum) {
251         DFILE_LOGE(TAG, "The file ID %u is illegal: totalBlockNum %u", *fileId, fileList->fileNum);
252         return NSTACKX_EFAILED;
253     }
254     return NSTACKX_EOK;
255 }
256 
CreateRetranBlockFrame(FileManager * fileManager,FileListTask * fileList)257 FileDataFrame *CreateRetranBlockFrame(FileManager *fileManager, FileListTask *fileList)
258 {
259     FileInfo *fileInfo = NULL;
260     uint16_t fileId;
261     uint32_t blockSequence, linkSequence;
262     FileDataFrame *fileDataFrame = NULL;
263 
264     if (GetRetranBlockInfo(fileList, &fileId, &blockSequence, &linkSequence) != NSTACKX_EOK) {
265         return NULL;
266     }
267 
268     if (fileList->tarFlag != NSTACKX_TRUE) {
269         fileInfo = &fileList->fileInfo[fileId - 1];
270     } else {
271         fileInfo = &fileList->tarFileInfo;
272     }
273     if (blockSequence >= fileInfo->totalBlockNum) {
274         DFILE_LOGE(TAG, "The retryBlock %u is larger than totalBlockNum %u", blockSequence, fileInfo->totalBlockNum);
275         return NULL;
276     }
277     if (fileInfo->errCode != FILE_MANAGER_EOK) {
278         DFILE_LOGE(TAG, "The processing file is error transId: %u fileId: %u", fileList->transId, fileInfo->fileId);
279         return NULL;
280     }
281 
282     if (fileList->cryptPara.keylen > 0) {
283         fileDataFrame = GetEncryptedDataFrame(fileManager, &fileList->cryptPara, fileInfo, blockSequence);
284     } else {
285         fileDataFrame = GetNoEncryptedDataFrame(fileManager, fileInfo, blockSequence);
286     }
287 
288     if (fileDataFrame == NULL) {
289         CloseFile(fileInfo);
290         NotifyFileMsg(fileList, fileInfo->fileId, FILE_MANAGER_SEND_FAIL);
291         return NULL;
292     }
293     fileList->hasUnInsetFrame = NSTACKX_TRUE;
294     fileDataFrame->header.flag |= NSTACKX_DFILE_DATA_FRAME_RETRAN_FLAG;
295     if (blockSequence == fileInfo->totalBlockNum - 1) {
296         fileDataFrame->header.flag |= NSTACKX_DFILE_DATA_FRAME_END_FLAG;
297     }
298     fileDataFrame->header.transId = htons(fileList->transId);
299     fileDataFrame->header.type = NSTACKX_DFILE_FILE_DATA_FRAME;
300 
301     /* The files with smaller file id should be closed to match the limit of the number. */
302     if (MAX_SEND_FILE_OPENED_PER_LIST <= 1 ||
303         (!fileList->tarFlag && fileList->sendFileProcessed >= MAX_SEND_FILE_OPENED_PER_LIST + fileInfo->fileId - 1)) {
304         CloseFile(fileInfo);
305     }
306     return fileDataFrame;
307 }
308 
GetTarFileInfo(FileListTask * fileList)309 static FileInfo *GetTarFileInfo(FileListTask *fileList)
310 {
311     (void)fileList;
312     return NULL;
313 }
314 
GetFileInfo(FileListTask * fileList)315 static FileInfo *GetFileInfo(FileListTask *fileList)
316 {
317     uint16_t fileId;
318     uint32_t blockSequence;
319     FileInfo *fileInfo = NULL;
320     if (fileList->tarFlag == NSTACKX_TRUE) {
321         return GetTarFileInfo(fileList);
322     }
323     if (fileList->newReadOutSet.fileId > 0) {
324         if (PthreadMutexLock(&fileList->newReadOutSet.lock) != 0) {
325             DFILE_LOGE(TAG, "pthread mutex lock error");
326             fileList->errCode = FILE_MANAGER_EMUTEX;
327             return NULL;
328         }
329         fileId = fileList->newReadOutSet.fileId;
330         blockSequence = fileList->newReadOutSet.blockSequence;
331         fileList->newReadOutSet.fileId = 0;
332         fileList->newReadOutSet.blockSequence = 0;
333         if (PthreadMutexUnlock(&fileList->newReadOutSet.lock) != 0) {
334             DFILE_LOGE(TAG, "pthread mutex unlock error");
335             fileList->errCode = FILE_MANAGER_EMUTEX;
336             return NULL;
337         }
338         if (fileId > 0 && fileId <= fileList->fileNum && blockSequence < fileList->fileInfo[fileId - 1].totalBlockNum) {
339             fileList->sendFileProcessed = (uint16_t)(fileId - 1);
340             fileList->fileInfo[fileId - 1].maxSequenceSend = (int64_t)blockSequence - 1;
341             for (uint16_t i = fileId + 1; i <= fileList->fileNum; i++) {
342                 fileList->fileInfo[i - 1].maxSequenceSend = -1;
343                 /* Close all files with larger fileId than new outset. */
344                 CloseFile(&fileList->fileInfo[i - 1]);
345             }
346             /* new outset has been set and bytesTransferred of fileList should be reset */
347             fileList->bytesTransferred = FileListGetBytesTransferred(fileList, NSTACKX_TRUE);
348         }
349     }
350     if (fileList->sendFileProcessed >= fileList->fileNum) {
351         return NULL;
352     }
353 
354     fileInfo = &fileList->fileInfo[fileList->sendFileProcessed];
355     if (fileInfo->errCode != FILE_MANAGER_EOK || fileInfo->fileSize == 0) {
356         fileList->sendFileProcessed++;
357         /* error ouccred and bytesTransferred of fileList should be reset */
358         fileList->bytesTransferred = FileListGetBytesTransferred(fileList, NSTACKX_TRUE);
359         return NULL;
360     }
361     return fileInfo;
362 }
363 
UpdateFileLisSendStatus(FileListTask * fileList,FileInfo * fileInfo,uint8_t * isEnd)364 static void UpdateFileLisSendStatus(FileListTask *fileList, FileInfo *fileInfo, uint8_t *isEnd)
365 {
366     if (fileList->bytesTransferred >=
367         fileList->bytesTransferredLastRecord + NSTACKX_KILO_BYTES * KILO_BYTES_TRANSFER_NOTICE_THRESHOLD) {
368         fileList->bytesTransferredLastRecord = fileList->bytesTransferred;
369         NotifyFileListMsg(fileList, FILE_MANAGER_TRANS_IN_PROGRESS);
370     }
371     if (fileInfo->maxSequenceSend == (int32_t)(fileInfo->totalBlockNum - 1)) {
372         /* The files with smaller file id should be closed to match the limit of the number of opened files */
373         if (fileInfo->fileId >= MAX_SEND_FILE_OPENED_PER_LIST) {
374             CloseFile(&fileList->fileInfo[fileInfo->fileId - MAX_SEND_FILE_OPENED_PER_LIST]);
375             if (!fileList->tarFlag) {
376                 /* error ouccred and bytesTransferred of fileList should be reset */
377                 fileList->bytesTransferred = FileListGetBytesTransferred(fileList, NSTACKX_TRUE);
378             }
379         }
380 
381         fileList->sendFileProcessed++;
382         *isEnd = NSTACKX_TRUE;
383     }
384 }
385 
UpdateTarFileListSendStatus(FileListTask * fileList)386 void UpdateTarFileListSendStatus(FileListTask *fileList)
387 {
388     uint64_t bytesTransFerred;
389     bytesTransFerred = FileListGetBytesTransferred(fileList, NSTACKX_TRUE);
390     if (bytesTransFerred >=
391         fileList->bytesTransferredLastRecord + NSTACKX_KILO_BYTES * KILO_BYTES_TRANSFER_NOTICE_THRESHOLD) {
392         fileList->bytesTransferredLastRecord = bytesTransFerred;
393         NotifyFileListMsg(fileList, FILE_MANAGER_TRANS_IN_PROGRESS);
394     }
395     if (fileList->tarFileInfo.maxSequenceSend == (int32_t)(fileList->tarFileInfo.totalBlockNum - 1)) {
396         fileList->sendFileProcessed = fileList->fileNum;
397         if (MAX_SEND_FILE_OPENED_PER_LIST <= 1) { // Macro maybe changed
398             FileInfo *fileInfo = GetFileInfo(fileList);
399             if (fileInfo != NULL) {
400                 CloseFile(fileInfo);
401             }
402         }
403     }
404 }
405 
CreateSendBlockFrame(FileManager * fileManager,FileListTask * fileList)406 static FileDataFrame *CreateSendBlockFrame(FileManager *fileManager, FileListTask *fileList)
407 {
408     FileInfo *fileInfo = NULL;
409     uint8_t isStartFrame = NSTACKX_FALSE;
410     uint8_t isEndFrame = NSTACKX_FALSE;
411     FileDataFrame *fileDataFrame = NULL;
412     fileInfo = GetFileInfo(fileList);
413     if (fileInfo == NULL) {
414         return NULL;
415     }
416     if (fileInfo->maxSequenceSend == -1) {
417         isStartFrame = NSTACKX_TRUE;
418     }
419     if (fileList->cryptPara.keylen > 0) {
420         fileDataFrame = GetEncryptedDataFrame(fileManager, &fileList->cryptPara, fileInfo,
421                                               (uint32_t)(fileInfo->maxSequenceSend + 1));
422     } else {
423         fileDataFrame = GetNoEncryptedDataFrame(fileManager, fileInfo, (uint32_t)(fileInfo->maxSequenceSend + 1));
424     }
425     if (fileDataFrame == NULL) {
426         DFILE_LOGE(TAG, "Can't get data from file");
427         fileList->sendFileProcessed++;
428         CloseFile(fileInfo);
429         NotifyFileMsg(fileList, fileInfo->fileId, FILE_MANAGER_SEND_FAIL);
430         return NULL;
431     }
432     fileList->hasUnInsetFrame = NSTACKX_TRUE;
433     fileInfo->maxSequenceSend++;
434     if (fileList->tarFlag != NSTACKX_TRUE) {
435         fileList->bytesTransferred += fileInfo->standardBlockSize;
436         UpdateFileLisSendStatus(fileList, fileInfo, &isEndFrame);
437     } else {
438         UpdateTarFileListSendStatus(fileList);
439     }
440     fileDataFrame->header.transId = htons(fileList->transId);
441     fileDataFrame->header.type = NSTACKX_DFILE_FILE_DATA_FRAME;
442     if (isEndFrame) {
443         fileDataFrame->header.flag |= NSTACKX_DFILE_DATA_FRAME_END_FLAG;
444     } else if (isStartFrame) {
445         fileDataFrame->header.flag |= NSTACKX_DFILE_DATA_FRAME_START_FLAG;
446     } else {
447         fileDataFrame->header.flag |= NSTACKX_DFILE_DATA_FRAME_CONTINUE_FLAG;
448     }
449     return fileDataFrame;
450 }
451 
PushFileBlockFrame(FileManager * fileManager,const FileListTask * fileList,const FileDataFrame * fileDataFrame,uint8_t isRetran,uint8_t * isAdded)452 static int32_t PushFileBlockFrame(FileManager *fileManager, const FileListTask *fileList,
453                                   const FileDataFrame *fileDataFrame,
454                                   uint8_t isRetran, uint8_t *isAdded)
455 {
456     BlockFrame *blockFrame = NULL;
457     SendBlockFrameListPara *para = &fileManager->sendBlockFrameListPara[fileList->bindedSendBlockListIdx];
458     *isAdded = NSTACKX_FALSE;
459     blockFrame = (BlockFrame *)calloc(1, sizeof(BlockFrame));
460     if (blockFrame == NULL) {
461         DFILE_LOGE(TAG, "calloc error");
462         fileManager->errCode = FILE_MANAGER_ENOMEM;
463         NotifyFileManagerMsg(fileManager, FILE_MANAGER_INNER_ERROR);
464         return NSTACKX_EFAILED;
465     }
466     blockFrame->sendLen = 0;
467     blockFrame->fileDataFrame = (FileDataFrame *)fileDataFrame;
468     blockFrame->socketIndex = fileList->socketIndex;
469 
470     if (PthreadMutexLock(&para->sendBlockFrameList.lock) != 0) {
471         free(blockFrame);
472         DFILE_LOGE(TAG, "pthread mutex lock error");
473         fileManager->errCode = FILE_MANAGER_EMUTEX;
474         goto L_ERR_FILE_MANAGER;
475     }
476     if (isRetran) {
477         ListInsertHead(para->sendRetranListTail, &blockFrame->list);
478         para->sendRetranListTail = &blockFrame->list;
479     } else {
480         ListInsertTail(&para->sendBlockFrameList.head, &blockFrame->list);
481     }
482     *isAdded = NSTACKX_TRUE;
483     para->sendBlockFrameList.size++;
484     if (PthreadMutexUnlock(&para->sendBlockFrameList.lock) != 0) {
485         DFILE_LOGE(TAG, "pthread mutex unlock error");
486         fileManager->errCode = FILE_MANAGER_EMUTEX;
487         goto L_ERR_FILE_MANAGER;
488     }
489     return NSTACKX_EOK;
490 L_ERR_FILE_MANAGER:
491     NotifyFileManagerMsg(fileManager, FILE_MANAGER_INNER_ERROR);
492     return NSTACKX_EFAILED;
493 }
494 
ClearSendFileList(FileManager * fileManager,FileListTask * fileList)495 void ClearSendFileList(FileManager *fileManager, FileListTask *fileList)
496 {
497     SendRetranRequestNode *retranNode = NULL;
498     for (uint32_t i = 0; i < fileList->fileNum; i++) {
499         CloseFile(&fileList->fileInfo[i]);
500         free(fileList->fileInfo[i].fileName);
501         fileList->fileInfo[i].fileName = NULL;
502     }
503     if (fileList->tarFlag) {
504         CloseFile(&fileList->tarFileInfo);
505     }
506     free(fileList->tarFileInfo.fileName);
507     fileList->tarFileInfo.fileName = NULL;
508     if (fileList->tarFileInfo.tarData != NULL) {
509         free(fileList->tarFileInfo.tarData);
510         fileList->tarFileInfo.tarData = NULL;
511         NSTACKX_ATOM_FETCH_SUB(&fileManager->totalPackInMemory, fileList->tarFileInfo.fileSize);
512     }
513     SemDestroy(&fileList->semStop);
514     if (PthreadMutexLock(&fileList->sendRetranList.lock) != 0) {
515         DFILE_LOGE(TAG, "pthread mutex lock error");
516     }
517     while (fileList->sendRetranList.size > 0) {
518         retranNode = (SendRetranRequestNode *)ListPopFront(&fileList->sendRetranList.head);
519         fileList->sendRetranList.size--;
520         free(retranNode);
521         retranNode = NULL;
522     }
523     if (PthreadMutexUnlock(&fileList->sendRetranList.lock) != 0) {
524         DFILE_LOGE(TAG, "pthread mutex unlock error");
525     }
526     MutexListDestory(&fileList->sendRetranList);
527     ClearCryptCtx(fileList->cryptPara.ctx);
528     PthreadMutexDestroy(&fileList->newReadOutSet.lock);
529     (void)memset_s(fileList, sizeof(FileListTask), 0, sizeof(FileListTask));
530     free(fileList);
531 }
532 
PushRetranBlockFrame(FileManager * fileManager,const FileListTask * fileList,const FileDataFrame * fileDataFrame)533 uint8_t PushRetranBlockFrame(FileManager *fileManager, const FileListTask *fileList, const FileDataFrame *fileDataFrame)
534 {
535     uint8_t ret = NSTACKX_FALSE;
536     SendBlockFrameListPara *para = &fileManager->sendBlockFrameListPara[fileList->bindedSendBlockListIdx];
537     if (fileDataFrame == NULL) {
538         DFILE_LOGE(TAG, "frame is NULL");
539         return ret;
540     }
541     CheckSendListFullAndWait(fileManager, &para->semBlockListNotFull);
542     if (CheckManager(fileManager) != NSTACKX_EOK) {
543         return ret;
544     }
545     if (PushFileBlockFrame(fileManager, fileList, fileDataFrame, NSTACKX_TRUE, &ret) != NSTACKX_EOK) {
546         DFILE_LOGE(TAG, "push retran block error");
547     }
548     return ret;
549 }
550 
PushSendBlockFrame(FileManager * fileManager,const FileListTask * fileList,const FileDataFrame * fileDataFrame)551 uint8_t PushSendBlockFrame(FileManager *fileManager, const FileListTask *fileList, const FileDataFrame *fileDataFrame)
552 {
553     uint8_t isAdded = NSTACKX_FALSE;
554 
555     SendBlockFrameListPara *para = &fileManager->sendBlockFrameListPara[fileList->bindedSendBlockListIdx];
556     if (fileDataFrame == NULL) {
557         return NSTACKX_FALSE;
558     }
559 
560     CheckSendListFullAndWait(fileManager, &para->semBlockListNotFull);
561     if (CheckManager(fileManager) != NSTACKX_EOK) {
562         return NSTACKX_FALSE;
563     }
564     if (PushFileBlockFrame(fileManager, fileList, fileDataFrame, NSTACKX_FALSE, &isAdded) != NSTACKX_EOK) {
565         return NSTACKX_FALSE;
566     }
567 
568     return isAdded;
569 }
570 
CreateSendBlockTarFrames(FileManager * fileManager,FileListTask * fileList)571 static uint8_t CreateSendBlockTarFrames(FileManager *fileManager, FileListTask *fileList)
572 {
573     (void)fileManager;
574     (void)fileList;
575     return NSTACKX_FALSE;
576 }
577 
SendTaskProcess(FileManager * fileManager,FileListTask * fileList)578 void SendTaskProcess(FileManager *fileManager, FileListTask *fileList)
579 {
580     FileDataFrame *fileDataFrame = NULL;
581     uint8_t isAdded;
582     uint8_t isEmpty;
583     SendBlockFrameListPara *para = &fileManager->sendBlockFrameListPara[fileList->bindedSendBlockListIdx];
584     while (NSTACKX_TRUE) {
585         if (CheckFilelist(fileList) != NSTACKX_EOK || CheckManager(fileManager) != NSTACKX_EOK) {
586             break;
587         }
588         isEmpty = NSTACKX_FALSE;
589         if (fileList->sendRetranList.size == 0) {
590             isEmpty = NSTACKX_TRUE;
591         }
592         if (isEmpty != NSTACKX_TRUE) {
593             fileDataFrame = CreateRetranBlockFrame(fileManager, fileList);
594             isAdded = PushRetranBlockFrame(fileManager, fileList, fileDataFrame);
595         } else if (fileList->sendFileProcessed >= fileList->fileNum && fileList->newReadOutSet.fileId == 0) {
596             SemWait(&fileList->semStop);
597             continue;
598         } else {
599             if ((fileList->tarFlag == NSTACKX_TRUE) && (fileList->tarFinished != NSTACKX_TRUE)) {
600                 isAdded = CreateSendBlockTarFrames(fileManager, fileList);
601             } else {
602                 fileDataFrame = CreateSendBlockFrame(fileManager, fileList);
603                 isAdded = PushSendBlockFrame(fileManager, fileList, fileDataFrame);
604             }
605         }
606         if (fileDataFrame != NULL) {
607             if (isAdded != NSTACKX_TRUE) {
608                 free(fileDataFrame);
609                 SemPost(&para->semBlockListNotFull);
610             }
611             fileList->hasUnInsetFrame = NSTACKX_FALSE;
612         }
613     }
614 
615     if (fileList->errCode != FILE_MANAGER_EOK) {
616         DFILE_LOGE(TAG, "send task process failed %d", fileList->errCode);
617         NotifyFileListMsg(fileList, FILE_MANAGER_SEND_FAIL);
618     }
619 }
620 
PackGetTarBlockLen(const FileListTask * fmFileList)621 uint64_t PackGetTarBlockLen(const FileListTask *fmFileList)
622 {
623     char pathSeparator = '/';
624     uint64_t tarFilesTotalLen = 0;
625     uint64_t blockCnt;
626     uint32_t i;
627     char *path = NULL;
628 
629     for (i = 0; i < fmFileList->fileNum; i++) {
630         tarFilesTotalLen += BLOCK_LEN;
631 
632         path = fmFileList->fileInfo[i].fileName;
633         if (strlen(path) > MAX_NAME_LEN) {
634             // +1 because of the string end '\0'
635             tarFilesTotalLen += BLOCK_LEN +
636                 (((strlen(path) + 1 - (long long)(path[0] == pathSeparator) + BLOCK_LEN - 1) / BLOCK_LEN) * BLOCK_LEN);
637         }
638 
639         // file body length
640         blockCnt = (fmFileList->fileInfo[i].fileSize + BLOCK_LEN - 1) / BLOCK_LEN;
641         tarFilesTotalLen += (blockCnt * BLOCK_LEN);
642     }
643 
644     // file tail paddings length
645     tarFilesTotalLen += BLOCK_LEN;
646 
647     return tarFilesTotalLen;
648 }
649 
AddTarFileInfo(const char * tarFileName,FileListTask * fmFileList,uint16_t standardBlockSize)650 static int32_t AddTarFileInfo(const char *tarFileName, FileListTask *fmFileList, uint16_t standardBlockSize)
651 {
652     uint64_t tarFilesTotalLen;
653     tarFilesTotalLen = PackGetTarBlockLen(fmFileList);
654     fmFileList->blockOffset = 0;
655     fmFileList->tarFrame = NULL;
656     fmFileList->tarFileInfo.fd = NSTACKX_INVALID_FD;
657     fmFileList->tarFileInfo.fileSize = tarFilesTotalLen;
658     fmFileList->tarFileInfo.standardBlockSize = standardBlockSize;
659     fmFileList->tarFileInfo.totalBlockNum = (uint32_t)((tarFilesTotalLen + standardBlockSize - 1) / standardBlockSize);
660     fmFileList->tarFileInfo.fileId = 1;
661     fmFileList->tarFileInfo.maxSequenceSend = -1;
662     fmFileList->tarFileInfo.tarData = NULL;
663     fmFileList->tarFileInfo.writeOffset = 0;
664     DFILE_LOGI(TAG, "tarLen: %llu, blockNum: %u, endLen: %llu", tarFilesTotalLen,
665          fmFileList->tarFileInfo.totalBlockNum, tarFilesTotalLen % standardBlockSize);
666     fmFileList->tarFileInfo.fileName = realpath(tarFileName, NULL);
667     if ((fmFileList->tarFileInfo.fileName == NULL) ||
668         (!IsAccessiblePath(fmFileList->tarFileInfo.fileName, R_OK, S_IFREG))) {
669         return NSTACKX_EFAILED;
670     }
671     fmFileList->tarFd = NULL;
672     fmFileList->totalBytes = fmFileList->tarFileInfo.fileSize;
673     return NSTACKX_EOK;
674 }
675 
AddSendFileInfo(const SendFileListInfo * fileListInfo,FileListTask * fmFileList,uint16_t standardBlockSize)676 static int32_t AddSendFileInfo(const SendFileListInfo *fileListInfo,
677                                FileListTask *fmFileList, uint16_t standardBlockSize)
678 {
679     uint16_t i;
680     FileInfo *fileInfo = NULL;
681     for (i = 0; i < fmFileList->fileNum; i++) {
682         if (fileListInfo->fileList[i] == NULL) {
683             goto L_ERR_FILE_MANAGER;
684         }
685         fileInfo = &fmFileList->fileInfo[i];
686         fileInfo->fileName = realpath(fileListInfo->fileList[i], NULL);
687         if (fileInfo->fileName == NULL || !IsAccessiblePath(fileInfo->fileName, R_OK, S_IFREG)) {
688             DFILE_LOGE(TAG, "can't get canonicalized absolute pathname, error(%d)", errno);
689             goto L_ERR_FILE_MANAGER;
690         }
691         fileInfo->fileSize = fileListInfo->fileSize[i];
692         fileInfo->standardBlockSize = standardBlockSize;
693         fileInfo->totalBlockNum = (uint32_t)(fileInfo->fileSize / standardBlockSize);
694         if (fileInfo->fileSize % standardBlockSize != 0) {
695             fileInfo->totalBlockNum++;
696         }
697         fmFileList->totalBytes += fileInfo->fileSize;
698         fileInfo->fileId = i + 1;
699         fileInfo->startOffset = fileListInfo->startOffset[i];
700         fileInfo->maxSequenceSend = -1;
701         fileInfo->fd = NSTACKX_INVALID_FD;
702         fileInfo->errCode = FILE_MANAGER_EOK;
703         fileInfo->fileOffset = 0;
704         fileInfo->tarData = NULL;
705         fileInfo->writeOffset = 0;
706     }
707 
708     if (fmFileList->tarFlag &&
709         AddTarFileInfo(fileListInfo->fileList[fmFileList->fileNum], fmFileList, standardBlockSize) != NSTACKX_EOK) {
710         goto L_ERR_FILE_MANAGER;
711     }
712 
713     return NSTACKX_EOK;
714 L_ERR_FILE_MANAGER:
715     for (i = 0; i < fmFileList->fileNum; i++) {
716         free(fmFileList->fileInfo[i].fileName);
717         fmFileList->fileInfo[i].fileName = NULL;
718     }
719     return NSTACKX_EFAILED;
720 }
721 
InitSendFilesOutSet(FileListTask * fmFileList)722 static int32_t InitSendFilesOutSet(FileListTask *fmFileList)
723 {
724     if (PthreadMutexInit(&fmFileList->newReadOutSet.lock, NULL) != 0) {
725         DFILE_LOGE(TAG, "PthreadMutexInit error");
726         return NSTACKX_EFAILED;
727     }
728     fmFileList->newReadOutSet.fileId = 0;
729     fmFileList->newReadOutSet.blockSequence = 0;
730     return NSTACKX_EOK;
731 }
732 
CreateSendFileList(const SendFileListInfo * fileListInfo,uint16_t standardBlockSize,const FileListMsgPara * msgPara)733 static FileListTask *CreateSendFileList(const SendFileListInfo *fileListInfo,
734                                         uint16_t standardBlockSize, const FileListMsgPara *msgPara)
735 {
736     FileListTask *fmFileList = NULL;
737     fmFileList = (FileListTask *)calloc(1, sizeof(FileListTask));
738     if (fmFileList == NULL) {
739         DFILE_LOGE(TAG, "file list calloc error");
740         return NULL;
741     }
742     fmFileList->transId = fileListInfo->transId;
743     fmFileList->fileNum = fileListInfo->fileNum;
744     fmFileList->tarFlag = fileListInfo->tarFlag;
745     fmFileList->smallFlag = fileListInfo->smallFlag;
746     if (SemInit(&fmFileList->semStop, 0, 0) != 0) {
747         DFILE_LOGE(TAG, "SemInit error");
748         goto L_ERR_FILE_MANAGER;
749     }
750     fmFileList->runStatus = FILE_LIST_STATUS_IDLE;
751     fmFileList->stopType = FILE_LIST_TRANSFER_FINISH;
752     fmFileList->isOccupied = NSTACKX_FALSE;
753     fmFileList->errCode = FILE_MANAGER_EOK;
754     fmFileList->sendFileProcessed = 0;
755 
756     if (MutexListInit(&fmFileList->sendRetranList, NSTACKX_MAX_RETRAN_BLOCK_NUM) != NSTACKX_EOK) {
757         DFILE_LOGE(TAG, "sendRetranList init error");
758         SemDestroy(&fmFileList->semStop);
759         goto L_ERR_FILE_MANAGER;
760     }
761 
762     if (InitSendFilesOutSet(fmFileList) != NSTACKX_EOK) {
763         SemDestroy(&fmFileList->semStop);
764         MutexListDestory(&fmFileList->sendRetranList);
765         DFILE_LOGE(TAG, "InitRetranFilesInfo error");
766         goto L_ERR_FILE_MANAGER;
767     }
768 
769     if (AddSendFileInfo(fileListInfo, fmFileList, standardBlockSize) != NSTACKX_EOK) {
770         DFILE_LOGE(TAG, "AddSendFileInfo init error");
771         SemDestroy(&fmFileList->semStop);
772         MutexListDestory(&fmFileList->sendRetranList);
773         PthreadMutexDestroy(&fmFileList->newReadOutSet.lock);
774         goto L_ERR_FILE_MANAGER;
775     }
776 
777     if (msgPara != NULL) {
778         fmFileList->msgReceiver = msgPara->msgReceiver;
779         fmFileList->context = msgPara->context;
780     }
781     return fmFileList;
782 L_ERR_FILE_MANAGER:
783     (void)memset_s(fmFileList, sizeof(FileListTask), 0, sizeof(FileListTask));
784     free(fmFileList);
785     return NULL;
786 }
787 
GetTargetSendBlockListIdx(const FileManager * fileManager)788 static uint32_t GetTargetSendBlockListIdx(const FileManager *fileManager)
789 {
790     uint32_t ret = 0;
791     uint32_t bindingNum = NSTACKX_MAX_PROCESSING_TASK_NUM;
792 
793     for (uint32_t i = 0; i < fileManager->sendFrameListNum; i++) {
794         if (fileManager->sendBlockFrameListPara[i].bandingTransNum < bindingNum) {
795             bindingNum = fileManager->sendBlockFrameListPara[i].bandingTransNum;
796             ret = i;
797         }
798     }
799     return ret;
800 }
801 
FileManagerSendFileTask(FileManager * fileManager,const SendFileListInfo * fileListInfo,const FileListMsgPara * msgPara)802 int32_t FileManagerSendFileTask(FileManager *fileManager, const SendFileListInfo *fileListInfo,
803                                 const FileListMsgPara *msgPara)
804 {
805     FileListTask *fmFileList = NULL;
806     uint16_t standardBlockSize;
807     if (CheckSenderManager(fileManager) != NSTACKX_EOK || fileListInfo == NULL ||
808         fileListInfo->fileNum == 0 || fileListInfo->fileNum > NSTACKX_DFILE_MAX_FILE_NUM) {
809         DFILE_LOGE(TAG, "Invalid input");
810         return NSTACKX_EINVAL;
811     }
812     if (fileManager->taskList.size >= fileManager->taskList.maxSize) {
813         DFILE_LOGE(TAG, "task list is full");
814         return NSTACKX_EFAILED;
815     }
816     standardBlockSize = GetStandardBlockSize(fileManager);
817     if (standardBlockSize == 0) {
818         DFILE_LOGE(TAG, "max frame length is too small");
819         return NSTACKX_EFAILED;
820     }
821 
822     fmFileList = CreateSendFileList(fileListInfo, standardBlockSize, msgPara);
823     if (fmFileList == NULL) {
824         DFILE_LOGE(TAG, "Can't creat fmFileList");
825         return NSTACKX_EFAILED;
826     }
827     fmFileList->maxFrameLength = fileManager->maxFrameLength;
828     fmFileList->epollfd = fileManager->epollfd;
829     fmFileList->eventNodeChain = fileManager->eventNodeChain;
830     if (fileManager->keyLen > 0 && SetCryptPara(fmFileList, fileManager->key, fileManager->keyLen) != NSTACKX_EOK) {
831         ClearSendFileList(fileManager, fmFileList);
832         return NSTACKX_EFAILED;
833     }
834     PeerInfo *peerinfo = ClientGetPeerInfoByTransId((DFileSession *)fileManager->context);
835     if (!peerinfo) {
836         ClearSendFileList(fileManager, fmFileList);
837         return NSTACKX_EFAILED;
838     }
839     fmFileList->socketIndex = peerinfo->socketIndex;
840     fmFileList->bindedSendBlockListIdx = GetTargetSendBlockListIdx(fileManager);
841     if (MutexListAddNode(&fileManager->taskList, &fmFileList->list, NSTACKX_FALSE) != NSTACKX_EOK) {
842         DFILE_LOGE(TAG, "Add task to list error");
843         ClearSendFileList(fileManager, fmFileList);
844         fileManager->errCode = FILE_MANAGER_EMUTEX;
845         NotifyFileManagerMsg(fileManager, FILE_MANAGER_INNER_ERROR);
846         return NSTACKX_EFAILED;
847     }
848     fileManager->totalBytes += fmFileList->totalBytes;
849     fileManager->sendBlockFrameListPara[fmFileList->bindedSendBlockListIdx].bandingTransNum++;
850     SemPost(&fileManager->semTaskListNotEmpty);
851     return NSTACKX_EOK;
852 }
853 
GetRetranFileLostBlocks(const FileListTask * fileList,uint16_t fileId,uint32_t blockSequence)854 static int32_t GetRetranFileLostBlocks(const FileListTask *fileList, uint16_t fileId, uint32_t blockSequence)
855 {
856     uint32_t ret = 0;
857 
858     if (fileList->tarFlag && fileList->tarFinished) {
859         return (int32_t)(fileList->tarFileInfo.totalBlockNum - blockSequence);
860     }
861 
862     for (uint16_t i = fileId; i <= fileList->sendFileProcessed + 1 && i <= fileList->fileNum; i++) {
863         ret += (uint32_t)(fileList->fileInfo[i - 1].maxSequenceSend + 1);
864     }
865 
866     if (ret >= blockSequence) {
867         ret -= blockSequence;
868     } else {
869         ret = 0;
870     }
871 
872     if (ret > INT32_MAX) {
873         ret = INT32_MAX;
874     }
875     return (int32_t)ret;
876 }
877 
IsValidOutSet(const FileListTask * fileList,uint16_t fileId,uint32_t blockSequence)878 static uint8_t IsValidOutSet(const FileListTask *fileList, uint16_t fileId, uint32_t blockSequence)
879 {
880     uint32_t totalBlockNum;
881     uint16_t fileNum;
882     fileNum = (fileList->tarFlag == NSTACKX_TRUE) ? 1 : fileList->fileNum;
883     if (fileId == 0 || fileId > fileNum) {
884         DFILE_LOGE(TAG, "new outset fileId is illegal");
885         return NSTACKX_FALSE;
886     }
887 
888     totalBlockNum = (fileList->tarFlag == NSTACKX_TRUE) ?
889                      fileList->tarFileInfo.totalBlockNum : fileList->fileInfo[fileId - 1].totalBlockNum;
890     if (blockSequence >= totalBlockNum) {
891         DFILE_LOGE(TAG, "new outset blockSequence is illegal");
892         return NSTACKX_FALSE;
893     }
894     return NSTACKX_TRUE;
895 }
896 
FileManagerResetSendOutSet(FileManager * fileManager,uint16_t fileId,uint32_t blockSequence,uint16_t transId)897 int32_t FileManagerResetSendOutSet(FileManager *fileManager, uint16_t fileId, uint32_t blockSequence, uint16_t transId)
898 {
899     FileListTask *fileList = NULL;
900     uint8_t isErrorOccurred;
901     int32_t ret;
902 
903     if (CheckSenderManager(fileManager) != NSTACKX_EOK ||
904         fileManager->maxFrameLength <= offsetof(FileDataFrame, blockPayload)) {
905         DFILE_LOGE(TAG, "Invalid input");
906         return NSTACKX_EINVAL;
907     }
908     fileList = GetFileListById(&fileManager->taskList, transId, &isErrorOccurred);
909     if (isErrorOccurred) {
910         DFILE_LOGE(TAG, "get target file list error");
911         goto L_ERR_FILE_MANAGER;
912     }
913 
914     if (CheckFilelistNotStop(fileList) != NSTACKX_EOK) {
915         DFILE_LOGE(TAG, "target file list is not available");
916         return NSTACKX_EFAILED;
917     }
918 
919     if (!IsValidOutSet(fileList, fileId, blockSequence)) {
920         return NSTACKX_EFAILED;
921     }
922 
923     ret = GetRetranFileLostBlocks(fileList, fileId, blockSequence);
924     if (fileList->tarFlag && fileList->tarFinished != NSTACKX_TRUE) {
925         return ret;
926     }
927     if (PthreadMutexLock(&fileList->newReadOutSet.lock) != 0) {
928         DFILE_LOGE(TAG, "pthread mutex lock error");
929         goto L_ERR_FILE_MANAGER;
930     }
931     fileList->newReadOutSet.blockSequence = blockSequence;
932     fileList->newReadOutSet.fileId = fileId;
933 
934     if (PthreadMutexUnlock(&fileList->newReadOutSet.lock) != 0) {
935         DFILE_LOGE(TAG, "pthread mutex unlock error");
936         goto L_ERR_FILE_MANAGER;
937     }
938     SemPost(&fileList->semStop);
939     return ret;
940 
941 L_ERR_FILE_MANAGER:
942     NotifyFileManagerMsg(fileManager, FILE_MANAGER_INNER_ERROR);
943     if (fileList != NULL) {
944         NotifyFileListMsg(fileList, FILE_MANAGER_SEND_FAIL);
945     }
946     return NSTACKX_EFAILED;
947 }
948 
GetSendBlockFrameListPara(FileManager * fileManager,uint32_t tid)949 static SendBlockFrameListPara *GetSendBlockFrameListPara(FileManager *fileManager, uint32_t tid)
950 {
951     SendBlockFrameListPara *para = NULL;
952 
953     if (tid < fileManager->sendFrameListNum) {
954         para = &fileManager->sendBlockFrameListPara[tid];
955         if (!ListIsEmpty(&para->sendBlockFrameList.head)) {
956             return para;
957         }
958     }
959 
960     for (uint32_t i = 0; i < fileManager->sendFrameListNum; i++) {
961         para = &fileManager->sendBlockFrameListPara[i];
962         if (!ListIsEmpty(&para->sendBlockFrameList.head)) {
963             return para;
964         }
965     }
966     return NULL;
967 }
968 
GetMultipleBlockFrame(SendBlockFrameListPara * para,BlockFrame ** block,int32_t nr)969 static int32_t GetMultipleBlockFrame(SendBlockFrameListPara *para, BlockFrame **block, int32_t nr)
970 {
971     BlockFrame *frame = NULL;
972     List *cur = NULL;
973     int32_t cnt;
974 
975     for (cnt = 0; cnt < nr; ++cnt) {
976         cur = ListPopFront(&para->sendBlockFrameList.head);
977         if (cur == NULL) {
978             break;
979         }
980         para->sendBlockFrameList.size--;
981         if (para->sendRetranListTail == cur) {
982             para->sendRetranListTail = &para->sendBlockFrameList.head;
983         }
984         if (frame != NULL) {
985             frame->list.next = cur;
986             frame = (BlockFrame *)(void *)cur;
987         } else {
988             frame = (BlockFrame *)(void *)cur;
989             *block = frame;
990         }
991     }
992     return cnt;
993 }
994 
GetDataFrameFromSendList(SendBlockFrameListPara * para,BlockFrame ** block,int32_t nr)995 static int32_t GetDataFrameFromSendList(SendBlockFrameListPara *para, BlockFrame **block, int32_t nr)
996 {
997     int32_t ret;
998 
999     if (PthreadMutexLock(&para->sendBlockFrameList.lock) != 0) {
1000         DFILE_LOGE(TAG, "pthread mutex lock error");
1001         return FILE_MANAGER_EMUTEX;
1002     }
1003 
1004     ret = GetMultipleBlockFrame(para, block, nr);
1005 
1006     if (PthreadMutexUnlock(&para->sendBlockFrameList.lock) != 0) {
1007         DFILE_LOGE(TAG, "pthread mutex unlock error");
1008     }
1009     for (int i = 0; i < ret; ++i) {
1010         SemPost(&para->semBlockListNotFull);
1011     }
1012     return ret;
1013 }
1014 
FileManagerFileRead(FileManager * fileManager,uint32_t tid,BlockFrame ** block,int32_t nr)1015 int32_t FileManagerFileRead(FileManager *fileManager, uint32_t tid, BlockFrame **block, int32_t nr)
1016 {
1017     int32_t ret;
1018     SendBlockFrameListPara *para = NULL;
1019     *block = NULL;
1020 
1021     if (CheckSenderManager(fileManager) != NSTACKX_EOK) {
1022         DFILE_LOGE(TAG, "Invalid input");
1023         return NSTACKX_EINVAL;
1024     }
1025 
1026     para = GetSendBlockFrameListPara(fileManager, tid);
1027     if (para == NULL || ListIsEmpty(&para->sendBlockFrameList.head)) {
1028         return 0;
1029     }
1030     ret = GetDataFrameFromSendList(para, block, nr);
1031     if (ret < 0) {
1032         fileManager->errCode = ret;
1033         NotifyFileManagerMsg(fileManager, FILE_MANAGER_INNER_ERROR);
1034         DFILE_LOGE(TAG, "GetDataFrameFromSendList failed");
1035         return ret;
1036     }
1037     if (*block != NULL) {
1038         RefreshBytesTransFerred(fileManager, *block);
1039     }
1040 
1041     return ret;
1042 }
1043 
InitSendBlockLists(FileManager * fileManager)1044 int32_t InitSendBlockLists(FileManager *fileManager)
1045 {
1046     uint32_t i;
1047     SendBlockFrameListPara *para = NULL;
1048     uint32_t sendListSize = fileManager->maxSendBlockListSize;
1049 
1050     for (i = 0; i < fileManager->sendFrameListNum; i++) {
1051         para = &fileManager->sendBlockFrameListPara[i];
1052         if (MutexListInit(&para->sendBlockFrameList, sendListSize) != NSTACKX_EOK) {
1053             DFILE_LOGE(TAG, "sendBlockFrameList InitList error");
1054             goto L_ERR_FILE_MANAGER;
1055         }
1056         para->sendRetranListTail = &para->sendBlockFrameList.head;
1057     }
1058     return NSTACKX_EOK;
1059 
1060 L_ERR_FILE_MANAGER:
1061     while (i > 0) {
1062         para = &fileManager->sendBlockFrameListPara[i - 1];
1063         MutexListDestory(&para->sendBlockFrameList);
1064         para->sendRetranListTail = NULL;
1065         i--;
1066     }
1067     return NSTACKX_EFAILED;
1068 }
1069 
GetMaxSendListSize(uint16_t connType)1070 uint32_t GetMaxSendListSize(uint16_t connType)
1071 {
1072     if (connType == CONNECT_TYPE_WLAN) {
1073         return NSTACKX_WLAN_SEND_BLOCK_QUEUE_MAX_LEN;
1074     } else if (connType == CONNECT_TYPE_P2P) {
1075         return NSTACKX_P2P_SEND_BLOCK_QUEUE_MAX_LEN;
1076     } else {
1077         DFILE_LOGE(TAG, "invalid connect type");
1078         return 0;
1079     }
1080 }
1081 
GetSendListNum(void)1082 uint16_t GetSendListNum(void)
1083 {
1084     return 1;
1085 }
1086 
ClearSendFrameList(FileManager * fileManager)1087 void ClearSendFrameList(FileManager *fileManager)
1088 {
1089     BlockFrame *blockFrame = NULL;
1090     uint32_t i;
1091     SendBlockFrameListPara *para = NULL;
1092     for (i = 0; i < fileManager->sendFrameListNum; i++) {
1093         para = &fileManager->sendBlockFrameListPara[i];
1094         if (PthreadMutexLock(&para->sendBlockFrameList.lock) != 0) {
1095             DFILE_LOGE(TAG, "pthread mutex lock error");
1096         }
1097         while (para->sendBlockFrameList.size > 0) {
1098             blockFrame = (BlockFrame *)ListPopFront(&para->sendBlockFrameList.head);
1099             para->sendBlockFrameList.size--;
1100             if (blockFrame != NULL) {
1101                 free(blockFrame->fileDataFrame);
1102                 free(blockFrame);
1103                 blockFrame = NULL;
1104             }
1105         }
1106         para->sendRetranListTail = &para->sendBlockFrameList.head;
1107         if (PthreadMutexUnlock(&para->sendBlockFrameList.lock) != 0) {
1108             DFILE_LOGE(TAG, "pthread mutex unlock error");
1109         }
1110         MutexListDestory(&para->sendBlockFrameList);
1111     }
1112 }
1113 
FileManagerIsLastBlockRead(FileManager * fileManager,uint16_t transId)1114 uint8_t FileManagerIsLastBlockRead(FileManager *fileManager, uint16_t transId)
1115 {
1116     FileListTask *fileList = NULL;
1117     uint8_t isErrorOccurred;
1118     if (fileManager == NULL) {
1119         return NSTACKX_FALSE;
1120     }
1121     fileList = GetFileListById(&fileManager->taskList, transId, &isErrorOccurred);
1122     if (isErrorOccurred) {
1123         fileManager->errCode = FILE_MANAGER_EMUTEX;
1124         NotifyFileManagerMsg(fileManager, FILE_MANAGER_INNER_ERROR);
1125         return NSTACKX_FALSE;
1126     }
1127     if (fileList == NULL) {
1128         return NSTACKX_FALSE;
1129     }
1130     if (fileList->newReadOutSet.fileId == 0 && fileList->sendFileProcessed == fileList->fileNum &&
1131         fileList->sendRetranList.size == 0 && !fileList->hasUnInsetFrame) {
1132         return NSTACKX_TRUE;
1133     }
1134     return NSTACKX_FALSE;
1135 }
1136 
FileManagerHasPendingDataMp(FileManager * fileManager,uint8_t socketIndex)1137 uint8_t FileManagerHasPendingDataMp(FileManager *fileManager, uint8_t socketIndex)
1138 {
1139     List *list = NULL;
1140     FileListTask *fileList = NULL;
1141     uint8_t hasPendingData = NSTACKX_FALSE;
1142 
1143     if (fileManager == NULL || fileManager->isSender != NSTACKX_TRUE) {
1144         return NSTACKX_FALSE;
1145     }
1146 
1147     if (fileManager->sendBlockFrameListPara[socketIndex].sendBlockFrameList.size > 0) {
1148         return NSTACKX_TRUE;
1149     }
1150 
1151     if (PthreadMutexLock(&fileManager->taskList.lock) != 0) {
1152         DFILE_LOGE(TAG, "pthread mutex lock error");
1153         fileManager->errCode = FILE_MANAGER_EMUTEX;
1154         NotifyFileManagerMsg(fileManager, FILE_MANAGER_INNER_ERROR);
1155         return NSTACKX_FALSE;
1156     }
1157 
1158     LIST_FOR_EACH(list, &fileManager->taskList.head) {
1159         fileList = (FileListTask *)list;
1160         if (fileList->socketIndex != socketIndex || CheckFilelistNotStop(fileList) != NSTACKX_EOK) {
1161             continue;
1162         }
1163 
1164         if (fileList->newReadOutSet.fileId > 0) {
1165             hasPendingData = NSTACKX_TRUE;
1166             break;
1167         }
1168 
1169         if (fileList->sendFileProcessed < fileList->fileNum) {
1170             hasPendingData = NSTACKX_TRUE;
1171             break;
1172         }
1173         if (fileList->sendRetranList.size > 0) {
1174             hasPendingData = NSTACKX_TRUE;
1175             break;
1176         }
1177 
1178         if (fileList->hasUnInsetFrame) {
1179             hasPendingData = NSTACKX_TRUE;
1180             break;
1181         }
1182     }
1183     if (PthreadMutexUnlock(&fileManager->taskList.lock) != 0) {
1184         DFILE_LOGE(TAG, "pthread mutex unlock error");
1185         fileManager->errCode = FILE_MANAGER_EMUTEX;
1186         NotifyFileManagerMsg(fileManager, FILE_MANAGER_INNER_ERROR);
1187     }
1188 
1189     return hasPendingData;
1190 }
1191 
FileManagerHasPendingDataInner(FileManager * fileManager)1192 uint8_t FileManagerHasPendingDataInner(FileManager *fileManager)
1193 {
1194     List *list = NULL;
1195     FileListTask *fileList = NULL;
1196     uint8_t hasPendingData = NSTACKX_FALSE;
1197 
1198     if (fileManager == NULL || fileManager->isSender != NSTACKX_TRUE) {
1199         return NSTACKX_FALSE;
1200     }
1201 
1202     if (PthreadMutexLock(&fileManager->taskList.lock) != 0) {
1203         DFILE_LOGE(TAG, "pthread mutex lock error");
1204         fileManager->errCode = FILE_MANAGER_EMUTEX;
1205         NotifyFileManagerMsg(fileManager, FILE_MANAGER_INNER_ERROR);
1206         return NSTACKX_FALSE;
1207     }
1208 
1209     LIST_FOR_EACH(list, &fileManager->taskList.head) {
1210         fileList = (FileListTask *)list;
1211         if (CheckFilelistNotStop(fileList) != NSTACKX_EOK) {
1212             continue;
1213         }
1214 
1215         if (fileList->newReadOutSet.fileId > 0) {
1216             hasPendingData = NSTACKX_TRUE;
1217             break;
1218         }
1219 
1220         if (fileList->sendFileProcessed < fileList->fileNum) {
1221             hasPendingData = NSTACKX_TRUE;
1222             break;
1223         }
1224         if (fileList->sendRetranList.size > 0) {
1225             hasPendingData = NSTACKX_TRUE;
1226             break;
1227         }
1228 
1229         if (fileList->hasUnInsetFrame) {
1230             hasPendingData = NSTACKX_TRUE;
1231             break;
1232         }
1233     }
1234     if (PthreadMutexUnlock(&fileManager->taskList.lock) != 0) {
1235         DFILE_LOGE(TAG, "pthread mutex unlock error");
1236         fileManager->errCode = FILE_MANAGER_EMUTEX;
1237         NotifyFileManagerMsg(fileManager, FILE_MANAGER_INNER_ERROR);
1238         return NSTACKX_FALSE;
1239     }
1240     for (uint32_t i = 0; i < fileManager->sendFrameListNum; i++) {
1241         if (fileManager->sendBlockFrameListPara[i].sendBlockFrameList.size > 0) {
1242             return NSTACKX_TRUE;
1243         }
1244     }
1245 
1246     return hasPendingData;
1247 }
1248 
FileManagerHasPendingData(FileManager * fileManager)1249 uint8_t FileManagerHasPendingData(FileManager *fileManager)
1250 {
1251     return FileManagerHasPendingDataInner(fileManager);
1252 }
1253 
FileManagerGetLastSequence(FileManager * fileManager,uint16_t transId,uint16_t fileId,uint32_t * sequence)1254 int32_t FileManagerGetLastSequence(FileManager *fileManager, uint16_t transId, uint16_t fileId, uint32_t *sequence)
1255 {
1256     FileListTask *fileList = NULL;
1257     uint8_t isErrorOccurred;
1258     if (fileManager == NULL || transId == 0 || fileId == 0) {
1259         DFILE_LOGE(TAG, "invalid input");
1260         return NSTACKX_EINVAL;
1261     }
1262 
1263     fileList = GetFileListById(&fileManager->taskList, transId, &isErrorOccurred);
1264     if (isErrorOccurred) {
1265         fileManager->errCode = FILE_MANAGER_EMUTEX;
1266         NotifyFileManagerMsg(fileManager, FILE_MANAGER_INNER_ERROR);
1267         DFILE_LOGE(TAG, "failed to get target fileList %hu", transId);
1268         return NSTACKX_EFAILED;
1269     }
1270     if (fileList == NULL || fileId > fileList->fileNum) {
1271         DFILE_LOGE(TAG, "failed to get target fileList %hu", transId);
1272         return NSTACKX_EFAILED;
1273     }
1274 
1275     if (fileList->fileInfo[fileId - 1].totalBlockNum == 0) {
1276         *sequence = 0;
1277     } else {
1278         *sequence = fileList->fileInfo[fileId - 1].totalBlockNum - 1;
1279     }
1280     return NSTACKX_EOK;
1281 }
1282