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.h"
17 #include "nstackx_util.h"
18 #include "nstackx_event.h"
19 #include "nstackx_dfile_log.h"
20 #include "nstackx_epoll.h"
21 #include "nstackx_dfile_session.h"
22 #include "nstackx_dfile_config.h"
23 #include "nstackx_dfile_mp.h"
24 #include "nstackx_congestion.h"
25 #include "nstackx_dfile_dfx.h"
26 #ifdef MBEDTLS_INCLUDED
27 #include "nstackx_mbedtls.h"
28 #else
29 #include "nstackx_openssl.h"
30 #endif
31 #include "nstackx_dfile_private.h"
32 #include "securec.h"
33 #include "nstackx_socket.h"
34 #ifdef DFILE_ENABLE_HIDUMP
35 #include "nstackx_getopt.h"
36 #endif
37 
38 #define TAG "nStackXDFile"
39 #define Coverity_Tainted_Set(pkt)
40 
41 #define SOCKET_SEND_BUFFER                 (0x38000 * 15)
42 #define SOCKET_RECV_BUFFER                 (0x38000 * 192)
43 
44 /* this lock will been destroy only when process exit. */
45 static pthread_mutex_t g_dFileSessionIdMutex = PTHREAD_MUTEX_INITIALIZER;
46 pthread_mutex_t g_dFileSessionChainMutex = PTHREAD_MUTEX_INITIALIZER;
47 List g_dFileSessionChain = {&(g_dFileSessionChain), &(g_dFileSessionChain)};
48 static uint16_t g_dFileSessionId = 0;
49 /* currently enabled capabilities */
50 static uint32_t g_capabilities = NSTACKX_CAPS_WLAN_CATAGORY | NSTACKX_CAPS_CHACHA;
51 /* wlan catagory from APP */
52 static uint32_t g_wlanCatagory = NSTACKX_WLAN_CAT_TCP;
53 
54 typedef struct {
55     DFileSession *session;
56     char *path;
57 } DFileSetStoragePathCtx;
58 
59 typedef struct {
60     DFileSession *session;
61     OnDFileRenameFile onRenameFile;
62 } DFileSetRenameHookCtx;
63 
64 typedef struct {
65     DFileSession *session;
66     FileListInfo *fileListInfo;
67 } DFileSendFileCtx;
68 
GetDFileSessionId(uint16_t * sessionId)69 static int32_t GetDFileSessionId(uint16_t *sessionId)
70 {
71     if (PthreadMutexLock(&g_dFileSessionIdMutex) != 0) {
72         return NSTACKX_EFAILED;
73     }
74 
75     if (g_dFileSessionId == 0) {
76         ListInitHead(&g_dFileSessionChain);
77     }
78     if (g_dFileSessionId == UINT16_MAX) {
79         g_dFileSessionId = 1;
80     } else {
81         g_dFileSessionId++;
82     }
83     *sessionId = g_dFileSessionId;
84 
85     if (PthreadMutexUnlock(&g_dFileSessionIdMutex) != 0) {
86         *sessionId = 0;
87         return NSTACKX_EFAILED;
88     }
89 
90     return NSTACKX_EOK;
91 }
92 
93 #ifdef DFILE_ENABLE_HIDUMP
GetDFileSessionNodeById(uint16_t sessionId)94 DFileSessionNode *GetDFileSessionNodeById(uint16_t sessionId)
95 #else
96 static DFileSessionNode *GetDFileSessionNodeById(uint16_t sessionId)
97 #endif
98 {
99     List *pos = NULL;
100     DFileSessionNode *node = NULL;
101     uint8_t isFound = NSTACKX_FALSE;
102     if (PthreadMutexLock(&g_dFileSessionChainMutex) != 0) {
103         DFILE_LOGE(TAG, "lock g_dFileSessionChainMutex failed");
104         return NULL;
105     }
106     LIST_FOR_EACH(pos, &g_dFileSessionChain) {
107         node = (DFileSessionNode *)pos;
108         if (node->sessionId == sessionId) {
109             isFound = NSTACKX_TRUE;
110             break;
111         }
112     }
113     if (PthreadMutexUnlock(&g_dFileSessionChainMutex) != 0) {
114         DFILE_LOGE(TAG, "unlock g_dFileSessionChainMutex failed");
115         return NULL;
116     }
117     if (isFound) {
118         return node;
119     }
120     return NULL;
121 }
122 
AddDFileSessionNode(DFileSession * session)123 static int32_t AddDFileSessionNode(DFileSession *session)
124 {
125     DFileSessionNode *node = calloc(1, sizeof(DFileSessionNode));
126     if (node == NULL) {
127         return NSTACKX_EFAILED;
128     }
129 
130     node->session = session;
131     node->sessionId = session->sessionId;
132     if (PthreadMutexLock(&g_dFileSessionChainMutex) != 0) {
133         DFILE_LOGE(TAG, "lock g_dFileSessionChainMutex failed");
134         free(node);
135         return NSTACKX_EFAILED;
136     }
137     ListInsertTail(&g_dFileSessionChain, &node->list);
138     if (PthreadMutexUnlock(&g_dFileSessionChainMutex) != 0) {
139         DFILE_LOGE(TAG, "unlock g_dFileSessionChainMutex failed");
140         ListRemoveNode(&node->list);
141         free(node);
142         return NSTACKX_EFAILED;
143     }
144     return NSTACKX_EOK;
145 }
146 
PopDFileSessionNodeById(uint16_t sessionId)147 static DFileSessionNode *PopDFileSessionNodeById(uint16_t sessionId)
148 {
149     DFileSessionNode *node = NULL;
150     List *pos = NULL;
151     List *tmp = NULL;
152     uint8_t isFound = NSTACKX_FALSE;
153     if (PthreadMutexLock(&g_dFileSessionChainMutex) != 0) {
154         DFILE_LOGE(TAG, "lock g_dFileSessionChainMutex failed");
155         return NULL;
156     }
157     LIST_FOR_EACH_SAFE(pos, tmp, &g_dFileSessionChain) {
158         node = (DFileSessionNode *)pos;
159         if (node->sessionId == sessionId) {
160             ListRemoveNode(&node->list);
161             isFound = NSTACKX_TRUE;
162             break;
163         }
164     }
165     if (PthreadMutexUnlock(&g_dFileSessionChainMutex) != 0) {
166         DFILE_LOGE(TAG, "unlock g_dFileSessionChainMutex failed");
167         if (node != NULL) {
168             ListInsertTail(&g_dFileSessionChain, &node->list);
169         }
170         return NULL;
171     }
172 
173     if (isFound) {
174         return node;
175     }
176     return NULL;
177 }
178 
CheckSessionIdValid(int32_t sessionId)179 static int32_t CheckSessionIdValid(int32_t sessionId)
180 {
181     if (sessionId < 0 || sessionId > UINT16_MAX) {
182         return NSTACKX_EINVAL;
183     }
184     return NSTACKX_EOK;
185 }
186 
CheckDFileSessionNodeValid(const DFileSessionNode * node)187 static int32_t CheckDFileSessionNodeValid(const DFileSessionNode *node)
188 {
189     if (node == NULL || node->session == NULL) {
190         return NSTACKX_EINVAL;
191     }
192     return NSTACKX_EOK;
193 }
194 
CheckFileNum(uint32_t fileNum)195 static int32_t CheckFileNum(uint32_t fileNum)
196 {
197     if (fileNum == 0 || fileNum > NSTACKX_DFILE_MAX_FILE_NUM) {
198         return NSTACKX_EINVAL;
199     }
200     return NSTACKX_EOK;
201 }
202 
DFileSetStoragePathInner(void * arg)203 static void DFileSetStoragePathInner(void *arg)
204 {
205     DFileSetStoragePathCtx *ctx = arg;
206     if (ctx->session == NULL) {
207         free(ctx->path);
208         free(ctx);
209         return;
210     }
211 
212     if (FileManagerSetWritePath(ctx->session->fileManager, ctx->path) != NSTACKX_EOK) {
213         DFILE_LOGE(TAG, "filemanager set write path failed");
214     }
215     free(ctx->path);
216     free(ctx);
217 }
218 
CheckSetStoragePathPara(int32_t sessionId,const char * path)219 static int32_t CheckSetStoragePathPara(int32_t sessionId, const char *path)
220 {
221     size_t len;
222     if (CheckSessionIdValid(sessionId) != NSTACKX_EOK || path == NULL) {
223         DFILE_LOGE(TAG, "invalid arg input");
224         return NSTACKX_EINVAL;
225     }
226 
227     len = strlen(path);
228     if (len == 0 || len > NSTACKX_MAX_PATH_LEN) {
229         DFILE_LOGE(TAG, "Invalid path name length");
230         return NSTACKX_EINVAL;
231     }
232     return NSTACKX_EOK;
233 }
234 
NSTACKX_DFileSetStoragePath(int32_t sessionId,const char * path)235 int32_t NSTACKX_DFileSetStoragePath(int32_t sessionId, const char *path)
236 {
237     /* EaglEye test */
238     Coverity_Tainted_Set((void *)&sessionId);
239     Coverity_Tainted_Set((void *)path);
240 
241     DFileSetStoragePathCtx *ctx = NULL;
242 
243     if (CheckSetStoragePathPara(sessionId, path) != NSTACKX_EOK) {
244         return NSTACKX_EINVAL;
245     }
246 
247     DFileSessionNode *node = GetDFileSessionNodeById((uint16_t)sessionId);
248     if (CheckDFileSessionNodeValid(node) != NSTACKX_EOK) {
249         DFILE_LOGE(TAG, "no session found for id %d", sessionId);
250         return NSTACKX_EINVAL;
251     }
252 
253     ctx = malloc(sizeof(DFileSetStoragePathCtx));
254     if (ctx == NULL) {
255         return NSTACKX_ENOMEM;
256     }
257 
258     /* When second parameter is NULL, realpath() uses malloc() to allocate a buffer of up to PATH_MAX bytes. */
259     ctx->path = realpath(path, NULL);
260     if (ctx->path == NULL) {
261         DFILE_LOGE(TAG, "can't get canonicalized absolute pathname");
262         free(ctx);
263         return NSTACKX_EFAILED;
264     }
265 
266     if (!IsAccessiblePath(ctx->path, W_OK, S_IFDIR)) {
267         DFILE_LOGE(TAG, "the input path isn't a valid writable folder");
268         free(ctx->path);
269         free(ctx);
270         return NSTACKX_EFAILED;
271     }
272 
273     ctx->session = node->session;
274 
275     if (PostEvent(&node->session->eventNodeChain, node->session->epollfd, DFileSetStoragePathInner, ctx) !=
276         NSTACKX_EOK) {
277         free(ctx->path);
278         free(ctx);
279         return NSTACKX_EFAILED;
280     }
281 
282     return NSTACKX_EOK;
283 }
284 
HasRepeatedNumber(const uint16_t * data,uint16_t len)285 static uint8_t HasRepeatedNumber(const uint16_t *data, uint16_t len)
286 {
287     uint16_t i, j;
288     for (i = 0; i < len; i++) {
289         for (j = i + 1; j < len; j++) {
290             if (data[i] == data[j]) {
291                 return NSTACKX_TRUE;
292             }
293         }
294     }
295     return NSTACKX_FALSE;
296 }
297 
298 typedef struct {
299     DFileSession *session;
300     char *pathList[NSTACKX_MAX_STORAGE_PATH_NUM];
301     uint16_t pathType[NSTACKX_MAX_STORAGE_PATH_NUM];
302     uint16_t pathNum;
303 } DFileSetStoragePathListCtx;
304 
ClearStoragePathListCtx(DFileSetStoragePathListCtx * ctx)305 static void ClearStoragePathListCtx(DFileSetStoragePathListCtx *ctx)
306 {
307     if (ctx == NULL) {
308         return;
309     }
310     for (uint16_t i = 0; i < ctx->pathNum; i++) {
311         free(ctx->pathList[i]);
312         ctx->pathList[i] = NULL;
313     }
314     free(ctx);
315 }
316 
DFileSetStoragePathListInner(void * arg)317 static void DFileSetStoragePathListInner(void *arg)
318 {
319     DFileSetStoragePathListCtx *ctx = arg;
320 
321     if (ctx == NULL) {
322         return;
323     }
324 
325     if (ctx->session == NULL) {
326         ClearStoragePathListCtx(ctx);
327         return;
328     }
329 
330     if (FileManagerSetWritePathList(ctx->session->fileManager, ctx->pathList, ctx->pathType, ctx->pathNum) !=
331         NSTACKX_EOK) {
332         ClearStoragePathListCtx(ctx);
333         return;
334     }
335 
336     /* if set filemanager write path list successfully, the pathList menmber will be freed in filemanager */
337     free(ctx);
338 }
339 
CreateStoragePathListCtx(const DFileSession * session,const char * path[],const uint16_t * pathType,uint16_t pathNum)340 DFileSetStoragePathListCtx *CreateStoragePathListCtx(const DFileSession *session, const char *path[],
341                                                      const uint16_t *pathType, uint16_t pathNum)
342 {
343     DFileSetStoragePathListCtx *ctx = NULL;
344     uint16_t i, pos;
345 
346     if (pathNum > NSTACKX_MAX_STORAGE_PATH_NUM) {
347         DFILE_LOGE(TAG, "invalid pathNum");
348         return NULL;
349     }
350 
351     ctx = malloc(sizeof(DFileSetStoragePathListCtx));
352     if (ctx == NULL) {
353         return NULL;
354     }
355 
356     for (i = 0; i < pathNum; i++) {
357         /* When second parameter is NULL, realpath() uses malloc() to allocate a buffer of up to PATH_MAX bytes. */
358         ctx->pathList[i] = realpath(path[i], NULL);
359         if (ctx->pathList[i] == NULL) {
360             DFILE_LOGE(TAG, "can't get canonicalized absolute pathname");
361             pos = i;
362             goto L_ERR;
363         }
364         if (!IsAccessiblePath(ctx->pathList[i], W_OK, S_IFDIR)) {
365             DFILE_LOGE(TAG, "the input path isn't a valid writable folder");
366             pos = i + 1;
367             goto L_ERR;
368         }
369         ctx->pathType[i] = pathType[i];
370     }
371     ctx->pathNum = pathNum;
372     ctx->session = (DFileSession *)session;
373     return ctx;
374 
375 L_ERR:
376     while (pos > 0) {
377         free(ctx->pathList[pos - 1]);
378         ctx->pathList[pos - 1] = NULL;
379         pos--;
380     }
381     free(ctx);
382     return NULL;
383 }
384 
CheckSetStoragePathListPara(int32_t sessionId,const char * path[],const uint16_t * pathType,uint16_t pathNum)385 static int32_t CheckSetStoragePathListPara(int32_t sessionId, const char *path[], const uint16_t *pathType,
386                                            uint16_t pathNum)
387 {
388     if (CheckSessionIdValid(sessionId) != NSTACKX_EOK || path == NULL || pathType == NULL || pathNum == 0 ||
389         pathNum > NSTACKX_MAX_STORAGE_PATH_NUM) {
390         DFILE_LOGE(TAG, "invalid arg input");
391         return NSTACKX_EINVAL;
392     }
393 
394     if (HasRepeatedNumber(pathType, pathNum)) {
395         DFILE_LOGE(TAG, "has repeated type");
396         return NSTACKX_EINVAL;
397     }
398     return NSTACKX_EOK;
399 }
400 
NSTACKX_DFileSetStoragePathList(int32_t sessionId,const char * path[],const uint16_t * pathType,uint16_t pathNum)401 int32_t NSTACKX_DFileSetStoragePathList(int32_t sessionId, const char *path[], const uint16_t *pathType,
402                                         uint16_t pathNum)
403 {
404     /* EaglEye test */
405     Coverity_Tainted_Set((void *)&sessionId);
406     Coverity_Tainted_Set((void *)path);
407     Coverity_Tainted_Set((void *)pathType);
408     Coverity_Tainted_Set((void *)&pathNum);
409 
410     DFileSetStoragePathListCtx *ctx = NULL;
411 
412     if (CheckSetStoragePathListPara(sessionId, path, pathType, pathNum) != NSTACKX_EOK) {
413         return NSTACKX_EINVAL;
414     }
415 
416     DFileSessionNode *node = GetDFileSessionNodeById((uint16_t)sessionId);
417     if (CheckDFileSessionNodeValid(node) != NSTACKX_EOK) {
418         DFILE_LOGE(TAG, "no session found for id %d", sessionId);
419         return NSTACKX_EINVAL;
420     }
421 
422     ctx = CreateStoragePathListCtx(node->session, path, pathType, pathNum);
423     if (ctx == NULL) {
424         return NSTACKX_ENOMEM;
425     }
426 
427     if (PostEvent(&node->session->eventNodeChain, node->session->epollfd, DFileSetStoragePathListInner, ctx) !=
428         NSTACKX_EOK) {
429         ClearStoragePathListCtx(ctx);
430         ctx = NULL;
431         return NSTACKX_EFAILED;
432     }
433     return NSTACKX_EOK;
434 }
435 
AddFileList(DFileSession * session,FileListInfo * fileListInfo)436 static inline void AddFileList(DFileSession *session, FileListInfo *fileListInfo)
437 {
438 #ifdef NSTACKX_SMALL_FILE_SUPPORT
439     if (fileListInfo->smallFlag == NSTACKX_TRUE) {
440         ListInsertTail(&session->smallFileLists, &fileListInfo->list);
441         session->smallListPendingCnt++;
442     } else {
443         ListInsertTail(&session->pendingFileLists, &fileListInfo->list);
444         session->fileListPendingCnt++;
445     }
446 #else
447     ListInsertTail(&session->pendingFileLists, &fileListInfo->list);
448     session->fileListPendingCnt++;
449 #endif
450 }
451 
DFileSendFileFail(void * arg)452 static void DFileSendFileFail(void *arg)
453 {
454     DFileSendFileCtx *ctx = arg;
455     DFileSession *session = ctx->session;
456     DFileMsg data;
457 
458     (void)memset_s(&data, sizeof(data), 0, sizeof(data));
459     data.errorCode = NSTACKX_EINVAL;
460     data.fileList.files = (const char **)ctx->fileListInfo->files;
461     data.fileList.fileNum = ctx->fileListInfo->fileNum;
462     data.fileList.userData = ctx->fileListInfo->userData;
463     NotifyMsgRecver(session, DFILE_ON_FILE_SEND_FAIL, &data);
464     DestroyFileListInfo(ctx->fileListInfo);
465     free(ctx);
466 }
467 
DFileSendFileInner(void * arg)468 static void DFileSendFileInner(void *arg)
469 {
470     DFileSendFileCtx *ctx = arg;
471     DFileSession *session = ctx->session;
472     DFileMsg data;
473 
474     DFileSendFileBeginEvent();
475 
476     (void)memset_s(&data, sizeof(data), 0, sizeof(data));
477     if (session == NULL) {
478         data.errorCode = NSTACKX_EINVAL;
479         DFILE_LOGE(TAG, "session is NULL");
480         goto L_END;
481     }
482 #ifdef NSTACKX_SMALL_FILE_SUPPORT
483     uint32_t totalCnt = session->fileListProcessingCnt + session->fileListPendingCnt + session->smallListProcessingCnt +
484         session->smallListPendingCnt;
485 #else
486     uint32_t totalCnt = session->fileListProcessingCnt + session->fileListPendingCnt;
487 #endif
488     DFILE_LOGI(TAG, "recv filelist fileNum %u tarFlag %hhu path %s, total %u", ctx->fileListInfo->fileNum,
489         ctx->fileListInfo->tarFlag, ctx->fileListInfo->files[0], totalCnt + 1);
490     CalculateSessionTransferRatePrepare(session);
491     if (session->fileListProcessingCnt + session->smallListProcessingCnt >= NSTACKX_FILE_MANAGER_THREAD_NUM) {
492         AddFileList(session, ctx->fileListInfo);
493     } else {
494         int32_t ret = DFileStartTrans(session, ctx->fileListInfo);
495         if (ret != NSTACKX_EOK) {
496             data.errorCode = ret;
497             DFILE_LOGE(TAG, "DFileStartTrans fail, error: %d", ret);
498             goto L_END;
499         }
500     }
501 
502     free(ctx);
503     return;
504 
505 L_END:
506     data.fileList.files = (const char **)ctx->fileListInfo->files;
507     data.fileList.fileNum = ctx->fileListInfo->fileNum;
508     data.fileList.userData = ctx->fileListInfo->userData;
509     NotifyMsgRecver(session, DFILE_ON_FILE_SEND_FAIL, &data);
510     DestroyFileListInfo(ctx->fileListInfo);
511     free(ctx);
512 }
513 
IsValidStringArray(const char * str[],uint32_t fileNum,size_t maxLen)514 static uint8_t IsValidStringArray(const char *str[], uint32_t fileNum, size_t maxLen)
515 {
516     if (str == NULL || fileNum == 0) {
517         return NSTACKX_FALSE;
518     }
519     for (uint32_t i = 0; i < fileNum; i++) {
520         if (str[i] == NULL) {
521             return NSTACKX_FALSE;
522         }
523         size_t len = strlen(str[i]);
524         if (len == 0 || len > maxLen) {
525             return NSTACKX_FALSE;
526         }
527     }
528     return NSTACKX_TRUE;
529 }
530 
CheckSendFilesPara(int32_t sessionId,const char * files[],uint32_t fileNum,const char * userData)531 static int32_t CheckSendFilesPara(int32_t sessionId, const char *files[], uint32_t fileNum, const char *userData)
532 {
533     size_t userDataLen;
534     if (CheckSessionIdValid(sessionId) != NSTACKX_EOK ||
535         !IsValidStringArray(files, fileNum, NSTACKX_MAX_FILE_NAME_LEN)) {
536         return NSTACKX_EINVAL;
537     }
538 
539     if (CheckFileNum(fileNum) != NSTACKX_EOK) {
540         DFILE_LOGE(TAG, "fileNum to send is 0 or too large");
541         return NSTACKX_EINVAL;
542     }
543 
544     if (userData == NULL) {
545         userDataLen = 0;
546         DFILE_LOGW(TAG, "send file with no user data.");
547     } else {
548         userDataLen = strlen(userData);
549     }
550 
551     if (userDataLen > NSTACKX_MAX_USER_DATA_SIZE) {
552         DFILE_LOGE(TAG, "send file with too long user data len");
553         return NSTACKX_EINVAL;
554     }
555     return NSTACKX_EOK;
556 }
557 
SetVtransInfo(DFileSendFileCtx * ctx,DFileRebuildFileList * rFilelist,uint16_t index)558 void SetVtransInfo(DFileSendFileCtx *ctx, DFileRebuildFileList *rFilelist, uint16_t index)
559 {
560     if (rFilelist->realTransId > 0) {
561         ctx->fileListInfo->vtransFlag = NSTACKX_TRUE;
562         ctx->fileListInfo->vtransTotalNum = rFilelist->transNum;
563         ctx->fileListInfo->vtransRealTransId = rFilelist->realTransId;
564         ctx->fileListInfo->vtransRealFileId = rFilelist->realFileId[index];
565         ctx->fileListInfo->vtransTotalFileNum = rFilelist->totalFileNum;
566         ctx->fileListInfo->vtransTotalFileSize = rFilelist->totalFileSize;
567     }
568 }
569 
SendFilesInner(int32_t sessionId,const char * files[],const char * remotePath[],uint32_t fileNum,const char * userData)570 int32_t SendFilesInner(int32_t sessionId, const char *files[], const char *remotePath[],
571     uint32_t fileNum, const char *userData)
572 {
573     DFileRebuildFileList rFilelist;
574 
575     DFileSessionNode *node = GetDFileSessionNodeById((uint16_t)sessionId);
576     if (CheckDFileSessionNodeValid(node) != NSTACKX_EOK) {
577         DFILE_LOGE(TAG, "no session found for id %d", sessionId);
578         return NSTACKX_EINVAL;
579     }
580     if (RebuildFilelist(files, remotePath, fileNum, node->session, &rFilelist) != NSTACKX_EOK) {
581         return NSTACKX_EFAILED;
582     }
583     for (uint16_t i = 0; i < rFilelist.transNum; i++) {
584         DFileSendFileCtx *ctx = malloc(sizeof(DFileSendFileCtx));
585         if (ctx == NULL) {
586             DFILE_LOGE(TAG, "malloc ctx error: NULL");
587             return NSTACKX_ENOMEM;
588         }
589         ctx->session = node->session;
590 
591         FileListPara para = NEW_FILE_LIST_PARA(&(rFilelist.files[i]), (remotePath ? &(rFilelist.remotePath[i]) : NULL),
592             (rFilelist.realTransId ? 1 : fileNum), userData,
593             NSTACKX_FALSE, &(rFilelist.startOffset[i]), &(rFilelist.fileSize[i]));
594         ctx->fileListInfo = CreateFileListInfo(&para);
595         if (ctx->fileListInfo == NULL) {
596             DFILE_LOGE(TAG, "CreateFileListInfo error: NULL");
597             free(ctx);
598             return NSTACKX_ENOMEM;
599         }
600         SetVtransInfo(ctx, &rFilelist, i);
601 
602         ctx->fileListInfo->noticeFileNameType = remotePath ? NOTICE_FULL_FILE_NAME_TYPE : NOTICE_FILE_NAME_TYPE;
603         ctx->fileListInfo->pathType = NSTACKX_RESERVED_PATH_TYPE;
604         ctx->fileListInfo->tarFlag = NSTACKX_FALSE;
605         ctx->fileListInfo->smallFlag = NSTACKX_FALSE;
606         int32_t ret = PostEvent(&node->session->eventNodeChain, node->session->epollfd, DFileSendFileInner, ctx);
607         if (ret != NSTACKX_EOK) {
608             DestroyFileListInfo(ctx->fileListInfo);
609             free(ctx);
610             return ret;
611         }
612     }
613 
614     node->session->allTaskCount++;
615 
616     return NSTACKX_EOK;
617 }
618 
NSTACKX_DFileSendFiles(int32_t sessionId,const char * files[],uint32_t fileNum,const char * userData)619 int32_t NSTACKX_DFileSendFiles(int32_t sessionId, const char *files[], uint32_t fileNum, const char *userData)
620 {
621     /* EaglEye test */
622     Coverity_Tainted_Set((void *)&sessionId);
623     Coverity_Tainted_Set((void *)files);
624     Coverity_Tainted_Set((void *)&fileNum);
625     Coverity_Tainted_Set((void *)userData);
626 
627     if (CheckSendFilesPara(sessionId, files, fileNum, userData) != NSTACKX_EOK) {
628         return NSTACKX_EINVAL;
629     }
630 
631     return SendFilesInner(sessionId, files, NULL, fileNum, userData);
632 }
633 
CheckSendFilesWithRemotePathPara(int32_t sessionId,const char * files[],const char * remotePath[],uint32_t fileNum,const char * userData)634 static int32_t CheckSendFilesWithRemotePathPara(int32_t sessionId, const char *files[], const char *remotePath[],
635                                                 uint32_t fileNum, const char *userData)
636 {
637     if (CheckSessionIdValid(sessionId) != NSTACKX_EOK ||
638         !IsValidStringArray(files, fileNum, NSTACKX_MAX_FILE_NAME_LEN) ||
639         !IsValidStringArray(remotePath, fileNum, NSTACKX_MAX_REMOTE_PATH_LEN)) {
640         DFILE_LOGE(TAG, "invalid arg input");
641         return NSTACKX_EINVAL;
642     }
643     if (CheckFileNum(fileNum) != NSTACKX_EOK) {
644         DFILE_LOGE(TAG, "fileNum to send is 0 or too large");
645         return NSTACKX_EINVAL;
646     }
647 
648     if (userData != NULL && strlen(userData) > NSTACKX_MAX_USER_DATA_SIZE) {
649         DFILE_LOGE(TAG, "send file with too long user data len");
650         return NSTACKX_EINVAL;
651     }
652     return NSTACKX_EOK;
653 }
654 
NSTACKX_DFileSendFilesWithRemotePath(int32_t sessionId,const char * files[],const char * remotePath[],uint32_t fileNum,const char * userData)655 int32_t NSTACKX_DFileSendFilesWithRemotePath(int32_t sessionId, const char *files[], const char *remotePath[],
656                                              uint32_t fileNum, const char *userData)
657 {
658     /* EaglEye test */
659     Coverity_Tainted_Set((void *)&sessionId);
660     Coverity_Tainted_Set((void *)files);
661     Coverity_Tainted_Set((void *)remotePath);
662     Coverity_Tainted_Set((void *)&fileNum);
663     Coverity_Tainted_Set((void *)userData);
664 
665     if (remotePath == NULL) {
666         return NSTACKX_DFileSendFiles(sessionId, files, fileNum, userData);
667     }
668 
669     if (CheckSendFilesWithRemotePathPara(sessionId, files, remotePath, fileNum, userData) != NSTACKX_EOK) {
670         return NSTACKX_EINVAL;
671     }
672 
673     return SendFilesInner(sessionId, files, remotePath, fileNum, userData);
674 }
675 
CheckSendFilesWithRemotePathAndType(int32_t sessionId,NSTACKX_FilesInfo * filesInfo)676 static int32_t CheckSendFilesWithRemotePathAndType(int32_t sessionId, NSTACKX_FilesInfo *filesInfo)
677 {
678     if (CheckSessionIdValid(sessionId) != NSTACKX_EOK) {
679         return NSTACKX_EINVAL;
680     }
681     if (filesInfo == NULL || CheckFileNum(filesInfo->fileNum) != NSTACKX_EOK) {
682         return NSTACKX_EINVAL;
683     }
684     if (filesInfo->pathType == NSTACKX_RESERVED_PATH_TYPE) {
685         return NSTACKX_EINVAL;
686     }
687     if (!IsValidStringArray(filesInfo->files, filesInfo->fileNum, NSTACKX_MAX_FILE_NAME_LEN)) {
688         return NSTACKX_EINVAL;
689     }
690     if (filesInfo->tarFlag == NSTACKX_TRUE) {
691         /* when tarFlag is set, only remotePath[0] will be accessed */
692         if (!IsValidStringArray(filesInfo->remotePath, 1, NSTACKX_MAX_REMOTE_PATH_LEN)) {
693             return NSTACKX_EINVAL;
694         }
695     } else {
696         if (!IsValidStringArray(filesInfo->remotePath, filesInfo->fileNum, NSTACKX_MAX_REMOTE_PATH_LEN)) {
697             return NSTACKX_EINVAL;
698         }
699     }
700     if (filesInfo->userData != NULL && strlen(filesInfo->userData) > NSTACKX_MAX_USER_DATA_SIZE) {
701         DFILE_LOGE(TAG, "send file with too long user data len");
702         return NSTACKX_EINVAL;
703     }
704     return NSTACKX_EOK;
705 }
706 
PostSendFailAsync(int32_t sessionId,const NSTACKX_FilesInfo * filesInfo)707 static void PostSendFailAsync(int32_t sessionId, const NSTACKX_FilesInfo *filesInfo)
708 {
709     const char *firstFileName = NULL;
710     if (CheckSessionIdValid(sessionId) != NSTACKX_EOK || filesInfo == NULL) {
711         return;
712     }
713     if (filesInfo->tarFlag == NSTACKX_TRUE) {
714         firstFileName = filesInfo->remotePath[0];
715     } else {
716         firstFileName = filesInfo->files[0];
717     }
718     if (firstFileName == NULL) {
719         return;
720     }
721     DFileSessionNode *node = GetDFileSessionNodeById((uint16_t)sessionId);
722     if (CheckDFileSessionNodeValid(node) != NSTACKX_EOK) {
723         DFILE_LOGE(TAG, "no session found for id %d", sessionId);
724         return;
725     }
726     DFileSendFileCtx *ctx = calloc(1, sizeof(DFileSendFileCtx));
727     if (ctx == NULL) {
728         return;
729     }
730     ctx->session = node->session;
731     ctx->fileListInfo = calloc(1, sizeof(FileListInfo));
732     if (ctx->fileListInfo == NULL) {
733         goto L_ERR;
734     }
735     ctx->fileListInfo->fileNum = 1;
736     ctx->fileListInfo->files = calloc(1, sizeof(char *));
737     if (ctx->fileListInfo->files == NULL) {
738         goto L_ERR;
739     }
740     ctx->fileListInfo->files[0] = calloc(1, strlen(firstFileName) + 1);
741     if (ctx->fileListInfo->files[0] == NULL) {
742         goto L_ERR;
743     }
744     if (memcpy_s(ctx->fileListInfo->files[0], strlen(firstFileName) + 1,
745         firstFileName, strlen(firstFileName)) != NSTACKX_EOK) {
746         DFILE_LOGE(TAG, "memcpy_s failed");
747         goto L_ERR;
748     }
749     if (PostEvent(&node->session->eventNodeChain, node->session->epollfd, DFileSendFileFail, ctx) == NSTACKX_EOK) {
750         return;
751     }
752 L_ERR:
753     DestroyFileListInfo(ctx->fileListInfo);
754     free(ctx);
755 }
756 
PackPrepareTar(const char * remotePath,char * tarName,uint32_t maxNameLen)757 static int32_t PackPrepareTar(const char *remotePath, char *tarName, uint32_t maxNameLen)
758 {
759     (void)remotePath;
760     (void)tarName;
761     (void)maxNameLen;
762     return NSTACKX_EOK;
763 }
764 
NSTACKX_DFileSendFilesWithRemotePathAndType(int32_t sessionId,NSTACKX_FilesInfo * filesInfo)765 int32_t NSTACKX_DFileSendFilesWithRemotePathAndType(int32_t sessionId, NSTACKX_FilesInfo *filesInfo)
766 {
767     /* EaglEye test */
768     Coverity_Tainted_Set((void *)filesInfo);
769 
770     char tarName[PATH_MAX + 1] = {0};
771     if (CheckSendFilesWithRemotePathAndType(sessionId, filesInfo) != NSTACKX_EOK) {
772         PostSendFailAsync(sessionId, filesInfo);
773         return NSTACKX_EINVAL;
774     }
775 
776     if (filesInfo->tarFlag == NSTACKX_TRUE) {
777         DFILE_LOGE(TAG, "warning: tarflag is not supported now");
778         (void)PackPrepareTar(filesInfo->remotePath[0], tarName, PATH_MAX);
779         return NSTACKX_NOTSUPPORT;
780     }
781 
782     DFileSessionNode *node = GetDFileSessionNodeById((uint16_t)sessionId);
783     if (CheckDFileSessionNodeValid(node) != NSTACKX_EOK) {
784         DFILE_LOGE(TAG, "no session found for id %d", sessionId);
785         return NSTACKX_EINVAL;
786     }
787 
788     DFileSendFileCtx *ctx = malloc(sizeof(DFileSendFileCtx));
789     if (ctx == NULL) {
790         return NSTACKX_ENOMEM;
791     }
792     ctx->session = node->session;
793     FileListPara fileListPara = NEW_FILE_LIST_PARA(filesInfo->files, filesInfo->remotePath, filesInfo->fileNum,
794         filesInfo->userData, filesInfo->tarFlag, NULL, NULL);
795     ctx->fileListInfo = CreateFileListInfo(&fileListPara);
796     if (ctx->fileListInfo == NULL) {
797         free(ctx);
798         ctx = NULL;
799         PostSendFailAsync(sessionId, filesInfo);
800         return NSTACKX_ENOMEM;
801     }
802 #ifdef NSTACKX_SMALL_FILE_SUPPORT
803     ctx->fileListInfo->smallFlag = filesInfo->smallFlag;
804 #else
805     ctx->fileListInfo->smallFlag = NSTACKX_FALSE;
806 #endif
807     ctx->fileListInfo->noSyncFlag = NSTACKX_TRUE;
808     ctx->fileListInfo->noticeFileNameType = NOTICE_FULL_FILE_NAME_TYPE;
809     ctx->fileListInfo->pathType = filesInfo->pathType;
810     ctx->fileListInfo->tarFile = strdup(tarName);
811 
812     int32_t ret = PostEvent(&node->session->eventNodeChain, node->session->epollfd, DFileSendFileInner, ctx);
813     if (ret != NSTACKX_EOK) {
814         DestroyFileListInfo(ctx->fileListInfo);
815         free(ctx);
816         ctx = NULL;
817         return ret;
818     }
819     return NSTACKX_EOK;
820 }
821 
DFileSessionBaseInit(DFileSession * session,DFileSessionType type,DFileMsgReceiver msgReceiver,uint16_t sessionId)822 static void DFileSessionBaseInit(DFileSession *session, DFileSessionType type, DFileMsgReceiver msgReceiver,
823     uint16_t sessionId)
824 {
825     uint32_t i;
826 
827     session->sessionId = sessionId;
828     session->transFlag = NSTACKX_FALSE;
829     session->bindType = INIT_STATUS;
830     session->sessionType = type;
831     session->msgReceiver = msgReceiver;
832     session->peerInfoCnt = 0;
833     ListInitHead(&session->eventNodeChain);
834     ListInitHead(&session->dFileTransChain);
835     ListInitHead(&session->peerInfoChain);
836     ListInitHead(&session->outboundQueue);
837     ListInitHead(&session->inboundQueue);
838     ListInitHead(&session->pendingFileLists);
839     ListInitHead(&session->vtransManagerList);
840 #ifdef NSTACKX_SMALL_FILE_SUPPORT
841     ListInitHead(&session->smallFileLists);
842 #endif
843 
844     for (i = 0; i < NSTACKX_FILE_MANAGER_THREAD_NUM; i++) {
845         session->transSlot[i].isWorking = NSTACKX_FALSE;
846         session->transSlot[i].transId = 0;
847         session->transSlot[i].peerInfo = NULL;
848     }
849 
850     for (i = 0; i < NSTACKX_MAX_CLIENT_SEND_THREAD_NUM; i++) {
851         ListInitHead(&session->freeIovList[i]);
852     }
853 }
854 
DFileSessionMutexInit(DFileSession * session)855 static int32_t DFileSessionMutexInit(DFileSession *session)
856 {
857     if (session == NULL) {
858         return NSTACKX_EFAILED;
859     }
860     if (PthreadMutexInit(&session->outboundQueueLock, NULL) != 0) {
861         goto L_ERR_OUTBOUND_QUEUE_LOCK;
862     }
863     if (PthreadMutexInit(&session->inboundQueueLock, NULL) != 0) {
864         goto L_ERR_INBOUND_QUEUE_LOCK;
865     }
866 
867     if (PthreadMutexInit(&session->transIdLock, NULL) != 0) {
868         goto L_ERR_TRANS_ID_LOCK;
869     }
870 
871     if (PthreadMutexInit(&session->backPressLock, NULL) != 0) {
872         goto L_ERR_BACKPRESS_LOCK;
873     }
874 
875     if (MutexListInit(&session->transferDoneAckList, MAX_TRANSFERDONE_ACK_NODE_COUNT) != NSTACKX_EOK) {
876         DFILE_LOGE(TAG, "transferDoneAckList InitList error");
877         goto L_ERR_TRANS_DONE_ACK_LOCK;
878     }
879 
880     if (MutexListInit(&session->tranIdStateList, MAX_TRANSTATELISTSIZE) != NSTACKX_EOK) {
881         DFILE_LOGE(TAG, "tranIdStateList InitList error");
882         goto L_ERR_TRANS_STATE_LOCK;
883     }
884     return NSTACKX_EOK;
885 L_ERR_TRANS_STATE_LOCK:
886     MutexListDestory(&session->transferDoneAckList);
887 L_ERR_TRANS_DONE_ACK_LOCK:
888     PthreadMutexDestroy(&session->backPressLock);
889 L_ERR_BACKPRESS_LOCK:
890     PthreadMutexDestroy(&session->transIdLock);
891 L_ERR_TRANS_ID_LOCK:
892     PthreadMutexDestroy(&session->inboundQueueLock);
893 L_ERR_INBOUND_QUEUE_LOCK:
894     PthreadMutexDestroy(&session->outboundQueueLock);
895 L_ERR_OUTBOUND_QUEUE_LOCK:
896     return NSTACKX_EFAILED;
897 }
898 
PostSessionCreate(DFileSession * session)899 static inline void PostSessionCreate(DFileSession *session)
900 {
901     session->capability = g_capabilities;
902     session->wlanCatagory = g_wlanCatagory;
903 
904     DFILE_LOGI(TAG, "current capabilities tcp:%d", CapsTcp(session));
905 }
906 
DFileSessionCreate(DFileSessionType type,DFileMsgReceiver msgReceiver)907 static DFileSession *DFileSessionCreate(DFileSessionType type, DFileMsgReceiver msgReceiver)
908 {
909     uint16_t sessionId = 0;
910     if (GetDFileSessionId(&sessionId) != NSTACKX_EOK) {
911         return NULL;
912     }
913 
914     DFileSession *session = calloc(1, sizeof(DFileSession));
915     if (session == NULL) {
916         return NULL;
917     }
918 
919     if (type == DFILE_SESSION_TYPE_CLIENT) {
920         DFileClientCreateEvent();
921     }
922     if (type == DFILE_SESSION_TYPE_SERVER) {
923         DFileServerCreateEvent();
924     }
925 
926     DFileSessionBaseInit(session, type, msgReceiver, sessionId);
927 
928     if (InitOutboundQueueWait(session) != NSTACKX_EOK) {
929         goto L_ERR_SEM;
930     }
931 
932     session->epollfd = CreateEpollDesc();
933     if (!IsEpollDescValid(session->epollfd)) {
934         goto L_ERR_EPOLL;
935     }
936 
937     session->recvBuffer = calloc(1, NSTACKX_RECV_BUFFER_LEN);
938     if (session->recvBuffer == NULL) {
939         DFILE_LOGE(TAG, "can not get memory");
940         goto L_ERR_RECVBUFFER;
941     }
942 
943     if (DFileSessionMutexInit(session) != NSTACKX_EOK) {
944         goto L_ERR_MUTEX;
945     }
946     PostSessionCreate(session);
947     return session;
948 L_ERR_MUTEX:
949     free(session->recvBuffer);
950 L_ERR_RECVBUFFER:
951     CloseEpollDesc(session->epollfd);
952 L_ERR_EPOLL:
953     DestroyOutboundQueueWait(session);
954 L_ERR_SEM:
955     free(session);
956     return NULL;
957 }
958 
DFileClearTransferDoneAckList(DFileSession * session)959 static void DFileClearTransferDoneAckList(DFileSession *session)
960 {
961     List *pos = NULL;
962     List *tmp = NULL;
963     TransferDoneAckNode *transferDoneAckNode = NULL;
964     if (PthreadMutexLock(&session->transferDoneAckList.lock) != 0) {
965         DFILE_LOGE(TAG, "pthread mutex lock error");
966         return;
967     }
968     LIST_FOR_EACH_SAFE(pos, tmp, &session->transferDoneAckList.head) {
969         transferDoneAckNode = (TransferDoneAckNode *)pos;
970         ListRemoveNode(&transferDoneAckNode->list);
971         free(transferDoneAckNode);
972         session->transferDoneAckList.size--;
973     }
974     if (PthreadMutexUnlock(&session->transferDoneAckList.lock) != 0) {
975         DFILE_LOGE(TAG, "pthread mutex unlock error");
976         return;
977     }
978     return;
979 }
980 
DFileSessionClean(DFileSession * session)981 static void DFileSessionClean(DFileSession *session)
982 {
983     List *tmp = NULL;
984     List *pos = NULL;
985     PeerInfo *peerInfo = NULL;
986 
987     LIST_FOR_EACH_SAFE(pos, tmp, &session->peerInfoChain) {
988         peerInfo = (PeerInfo *)pos;
989         if (peerInfo->settingTimer != NULL) {
990             TimerDelete(peerInfo->settingTimer);
991             peerInfo->settingTimer = NULL;
992         }
993         ListRemoveNode(&peerInfo->list);
994         free(peerInfo);
995     }
996     if (IsEpollDescValid(session->epollfd)) {
997         CloseEpollDesc(session->epollfd);
998         session->epollfd = INVALID_EPOLL_DESC;
999     }
1000     DestroyOutboundQueueWait(session);
1001     PthreadMutexDestroy(&session->inboundQueueLock);
1002     PthreadMutexDestroy(&session->outboundQueueLock);
1003     PthreadMutexDestroy(&session->transIdLock);
1004     PthreadMutexDestroy(&session->backPressLock);
1005     DFileClearTransferDoneAckList(session);
1006     MutexListDestory(&session->transferDoneAckList);
1007     MutexListDestory(&session->tranIdStateList);
1008     free(session->recvBuffer);
1009     free(session);
1010     return;
1011 }
1012 
DFileRecverInit(DFileSession * session,struct sockaddr_in * sockAddr,uint8_t socketIndex)1013 static int32_t DFileRecverInit(DFileSession *session, struct sockaddr_in *sockAddr, uint8_t socketIndex)
1014 {
1015     SocketProtocol protocol;
1016 
1017     if (CapsTcp(session)) {
1018         protocol = NSTACKX_PROTOCOL_TCP;
1019     } else {
1020         protocol = NSTACKX_PROTOCOL_UDP;
1021     }
1022 
1023     Socket *socket = ServerSocket(protocol, sockAddr);
1024     if (socket == NULL) {
1025         return NSTACKX_EFAILED;
1026     }
1027 
1028     /* Note: If the monitoring method is not select, this restriction should be removed */
1029     if (CheckFdSetSize(socket->sockfd) != NSTACKX_EOK) {
1030         DFILE_LOGE(TAG, "CheckFdSetSize failed");
1031         CloseSocket(socket);
1032         return NSTACKX_EFAILED;
1033     }
1034 
1035     session->socket[socketIndex] = socket;
1036     session->protocol = protocol;
1037     DFILE_LOGI(TAG, "create server socket %d protocol is %d", socket->sockfd, protocol);
1038     int32_t optVal = 0;
1039     socklen_t optLen = sizeof(optVal);
1040     if (getsockopt(socket->sockfd, SOL_SOCKET, SO_RCVBUF, (void *)&optVal, &optLen) == 0) {
1041         DFILE_LOGI(TAG, "default recv buf is %d bytes", optVal);
1042     }
1043 
1044     return NSTACKX_EOK;
1045 }
1046 
DFileRecverDestory(DFileSession * session)1047 static void DFileRecverDestory(DFileSession *session)
1048 {
1049     CloseSocket(session->socket[0]);
1050     CloseSocket(session->socket[1]);
1051     session->socket[0] = NULL;
1052     session->socket[1] = NULL;
1053 }
1054 
StartDFileThreads(DFileSession * session)1055 static int32_t StartDFileThreads(DFileSession *session)
1056 {
1057     if (CreateReceiverPipe(session) != NSTACKX_EOK) {
1058         DFILE_LOGE(TAG, "Create pipe failed");
1059         goto L_ERR_PIPE;
1060     }
1061 
1062     if (EventModuleInit(&session->eventNodeChain, session->epollfd) != NSTACKX_EOK) {
1063         DFILE_LOGE(TAG, "Event module init failed!");
1064         goto L_ERR_EVENT;
1065     }
1066 
1067     if (StartDFileThreadsInner(session) == NSTACKX_EOK) {
1068         return NSTACKX_EOK;
1069     }
1070 
1071     EventNodeChainClean(&session->eventNodeChain);
1072     CloseEpollDesc(session->epollfd);
1073     session->epollfd = INVALID_EPOLL_DESC;
1074 L_ERR_EVENT:
1075     DestroyReceiverPipe(session);
1076 L_ERR_PIPE:
1077     return NSTACKX_EFAILED;
1078 }
1079 
StopDFileThreads(DFileSession * session)1080 static void StopDFileThreads(DFileSession *session)
1081 {
1082     /* Notify main loop thread to terminate */
1083     if (PostEvent(&session->eventNodeChain, session->epollfd, TerminateMainThreadInner, session) != NSTACKX_EOK) {
1084         DFileSessionSetTerminateFlag(session);
1085 
1086         /* Notify sender thread to terminate */
1087         PostOutboundQueueWait(session);
1088 
1089         /* Unblock "select" and notify receiver thread to terminate */
1090         NotifyPipeEvent(session);
1091     }
1092 
1093     /* Terminate 3 handling threads */
1094     PthreadJoin(session->tid, NULL);
1095     session->tid = INVALID_TID;
1096 
1097     PthreadJoin(session->senderTid[0], NULL);
1098     session->senderTid[0] = INVALID_TID;
1099 
1100     PthreadJoin(session->receiverTid, NULL);
1101     session->receiverTid = INVALID_TID;
1102     PthreadJoin(session->controlTid, NULL);
1103     session->controlTid = INVALID_TID;
1104 
1105     /* Terminate file IO thread */
1106     StopFileManagerThreads(session->fileManager);
1107     /* Clear event callback */
1108     ClearEvent(&session->eventNodeChain, session->epollfd);
1109     EventNodeChainClean(&session->eventNodeChain);
1110     CloseEpollDesc(session->epollfd);
1111     session->epollfd = INVALID_EPOLL_DESC;
1112     DestroyReceiverPipe(session);
1113 }
1114 
StartSessionRunning(DFileSession * session,uint16_t SendThreadNum)1115 int32_t StartSessionRunning(DFileSession *session, uint16_t SendThreadNum)
1116 {
1117     session->clientSendThreadNum = SendThreadNum;
1118     if (StartDFileThreads(session) != NSTACKX_EOK) {
1119         return NSTACKX_EFAILED;
1120     }
1121     if (AddDFileSessionNode(session) != NSTACKX_EOK) {
1122         return NSTACKX_EFAILED;
1123     }
1124 
1125     return NSTACKX_EOK;
1126 }
1127 
NSTACKX_DFileInit(void)1128 static int32_t NSTACKX_DFileInit(void)
1129 {
1130     if (SocketModuleInit() != NSTACKX_EOK) {
1131         return NSTACKX_EFAILED;
1132     }
1133     if (CongModuleInit() != NSTACKX_EOK) {
1134         goto L_ERR_CONG;
1135     }
1136 #ifdef NSTACKX_WITH_LITEOS
1137     EpollEventPtrInit();
1138 #endif
1139 
1140     return NSTACKX_EOK;
1141 
1142 L_ERR_CONG:
1143     SocketModuleClean();
1144     DFILE_LOGE(TAG, "fail to create dfile server ");
1145     return NSTACKX_EFAILED;
1146 }
1147 
NSTACKX_DFileServer(struct sockaddr_in * localAddr,socklen_t addrLen,const uint8_t * key,uint32_t keyLen,DFileMsgReceiver msgReceiver)1148 int32_t NSTACKX_DFileServer(struct sockaddr_in *localAddr, socklen_t addrLen, const uint8_t *key, uint32_t keyLen,
1149                             DFileMsgReceiver msgReceiver)
1150 {
1151     /* EaglEye test */
1152     Coverity_Tainted_Set((void *)localAddr);
1153     Coverity_Tainted_Set((void *)&addrLen);
1154     Coverity_Tainted_Set((void *)key);
1155     Coverity_Tainted_Set((void *)&keyLen);
1156     Coverity_Tainted_Set((void *)msgReceiver);
1157 
1158     DFILE_LOGI(TAG, "Begin to create dfile server ");
1159     DFileSession *session = NULL;
1160     struct sockaddr_in sockAddr;
1161 
1162     if (localAddr == NULL || localAddr->sin_family != AF_INET || sizeof(struct sockaddr_in) != addrLen) {
1163         return NSTACKX_EFAILED;
1164     }
1165     if (NSTACKX_DFileInit() != NSTACKX_EOK) {
1166         return NSTACKX_EFAILED;
1167     }
1168     session = DFileSessionCreate(DFILE_SESSION_TYPE_SERVER, msgReceiver);
1169     if (session == NULL) {
1170         goto L_ERR_SESSION;
1171     }
1172 
1173     (void)memset_s(&sockAddr, sizeof(sockAddr), 0, sizeof(sockAddr));
1174     sockAddr.sin_port = htons(localAddr->sin_port);
1175     sockAddr.sin_addr.s_addr = htonl(localAddr->sin_addr.s_addr);
1176     if (DFileRecverInit(session, &sockAddr, 0) != NSTACKX_EOK) {
1177         goto L_ERR_RECVER_INIT;
1178     }
1179 
1180     if (CreateFileManager(session, key, keyLen, NSTACKX_FALSE, CONNECT_TYPE_NONE) != NSTACKX_EOK) {
1181         goto L_ERR_FILE_MANAGER;
1182     }
1183 
1184     if (StartSessionRunning(session, 1) != NSTACKX_EOK) {
1185         goto L_ERR_THREAD;
1186     }
1187 
1188     return session->sessionId;
1189 L_ERR_THREAD:
1190     StopFileManagerThreads(session->fileManager);
1191     FileManagerDestroy(session->fileManager);
1192 L_ERR_FILE_MANAGER:
1193     DFileRecverDestory(session);
1194 L_ERR_RECVER_INIT:
1195     DFileSessionClean(session);
1196 L_ERR_SESSION:
1197     CongModuleClean();
1198     SocketModuleClean();
1199     DFILE_LOGE(TAG, "fail to create dfile server ");
1200     return NSTACKX_EFAILED;
1201 }
1202 
DFileSenderInitWithTargetDev(DFileSession * session,const struct sockaddr_in * sockAddr,uint16_t * connType,const char * localInterface,uint8_t socketIndex)1203 static int32_t DFileSenderInitWithTargetDev(DFileSession *session, const struct sockaddr_in *sockAddr,
1204                                             uint16_t *connType, const char *localInterface, uint8_t socketIndex)
1205 {
1206     SocketProtocol protocol;
1207 
1208     protocol = CapsTcp(session) ? NSTACKX_PROTOCOL_TCP : NSTACKX_PROTOCOL_UDP;
1209 
1210     Socket *socket = ClientSocketWithTargetDev(protocol, sockAddr, localInterface);
1211     if (socket == NULL) {
1212         DFILE_LOGE(TAG, "socket is null");
1213         return NSTACKX_EFAILED;
1214     }
1215 
1216     /* Note: If the monitoring method is not select, this restriction should be removed */
1217     if (CheckFdSetSize(socket->sockfd) != NSTACKX_EOK) {
1218         DFILE_LOGE(TAG, "CheckFdSetSize failed");
1219         CloseSocket(socket);
1220         return NSTACKX_EFAILED;
1221     }
1222 
1223     session->socket[socketIndex] = socket;
1224     session->protocol = protocol;
1225 
1226     if (CapsTcp(session)) {
1227         SetTcpKeepAlive(socket->sockfd);
1228     }
1229 
1230     int32_t ret = GetConnectionType(socket->srcAddr.sin_addr.s_addr, socket->dstAddr.sin_addr.s_addr,
1231                                     connType);
1232     if (ret != NSTACKX_EOK) {
1233         DFILE_LOGE(TAG, "get connect type failed, ret = %d", ret);
1234         goto L_ERR_PEER_INFO;
1235     }
1236     if ((*connType != CONNECT_TYPE_P2P && *connType != CONNECT_TYPE_WLAN)) {
1237         *connType = CONNECT_TYPE_WLAN;
1238         DFILE_LOGI(TAG, "connet type isn't wlan or p2p, and will be set to wlan by default");
1239     }
1240     PeerInfo *peerInfo = CreatePeerInfo(session, &socket->dstAddr, 0, *connType, socketIndex);
1241     if (peerInfo == NULL) {
1242         goto L_ERR_PEER_INFO;
1243     }
1244     ListInsertTail(&session->peerInfoChain, &peerInfo->list);
1245     *connType = peerInfo->connType;
1246     return NSTACKX_EOK;
1247 
1248 L_ERR_PEER_INFO:
1249     CloseSocket(session->socket[0]);
1250     CloseSocket(session->socket[1]);
1251     session->socket[0] = NULL;
1252     session->socket[1] = NULL;
1253     return NSTACKX_EFAILED;
1254 }
1255 
DFileSenderDestory(DFileSession * session)1256 static void DFileSenderDestory(DFileSession *session)
1257 {
1258     CloseSocket(session->socket[0]);
1259     CloseSocket(session->socket[1]);
1260     session->socket[0] = NULL;
1261     session->socket[1] = NULL;
1262 
1263     List *pos = NULL;
1264     List *tmp = NULL;
1265     LIST_FOR_EACH_SAFE(pos, tmp, &session->peerInfoChain) {
1266         PeerInfo *peerInfo = (PeerInfo *)pos;
1267         ListRemoveNode(&peerInfo->list);
1268         free(peerInfo);
1269         session->peerInfoCnt--;
1270     }
1271 }
1272 
InitSockaddr(const struct sockaddr_in * inSockAddr,struct sockaddr_in * sockAddr)1273 static inline void InitSockaddr(const struct sockaddr_in *inSockAddr, struct sockaddr_in *sockAddr)
1274 {
1275     (void)memset_s(sockAddr, sizeof(*sockAddr), 0, sizeof(*sockAddr));
1276     sockAddr->sin_family = AF_INET;
1277     sockAddr->sin_port = htons(inSockAddr->sin_port);
1278     sockAddr->sin_addr.s_addr = htonl(inSockAddr->sin_addr.s_addr);
1279 }
1280 
GetClientSendThreadNum(uint16_t connType)1281 static uint16_t GetClientSendThreadNum(uint16_t connType)
1282 {
1283     if (connType == CONNECT_TYPE_WLAN) {
1284         return NSTACKX_WLAN_CLIENT_SEND_THREAD_NUM;
1285     } else {
1286         return 1;
1287     }
1288 }
1289 
CheckSessionPara(NSTACKX_SessionPara * sessionPara)1290 static int32_t CheckSessionPara(NSTACKX_SessionPara *sessionPara)
1291 {
1292     if (sessionPara == NULL) {
1293         return NSTACKX_EFAILED;
1294     }
1295 
1296     if (sessionPara->addr == NULL ||
1297         sessionPara->addr->sin_family != AF_INET ||
1298         sessionPara->addrLen != sizeof(struct sockaddr_in)) {
1299         return NSTACKX_EFAILED;
1300     }
1301 
1302     return NSTACKX_EOK;
1303 }
1304 
SendSettingToServer(DFileSession * session)1305 void SendSettingToServer(DFileSession *session)
1306 {
1307     List *pos = NULL;
1308     PeerInfo *peerInfo = NULL;
1309     LIST_FOR_EACH(pos, &session->peerInfoChain) {
1310         peerInfo = (PeerInfo *)pos;
1311         peerInfo->state = SETTING_NEGOTIATING;
1312         DFileSessionSendSetting(peerInfo);
1313     }
1314 }
1315 
NSTACKX_DFileClientWithTargetDev(NSTACKX_SessionPara * para)1316 int32_t NSTACKX_DFileClientWithTargetDev(NSTACKX_SessionPara *para)
1317 {
1318     /* EaglEye test */
1319     Coverity_Tainted_Set((void *)para);
1320 
1321     DFILE_LOGI(TAG, "begin to Create Dfile client");
1322     struct sockaddr_in sockAddr;
1323 
1324     if (CheckSessionPara(para) != NSTACKX_EOK) {
1325         return NSTACKX_EFAILED;
1326     }
1327     InitSockaddr(para->addr, &sockAddr);
1328 
1329     if (SocketModuleInit() != NSTACKX_EOK) {
1330         return NSTACKX_EFAILED;
1331     }
1332     if (CongModuleInit() != NSTACKX_EOK) {
1333         goto L_ERR_CONG;
1334     }
1335     DFileSession *session = DFileSessionCreate(DFILE_SESSION_TYPE_CLIENT, para->msgReceiver);
1336     if (session == NULL) {
1337         goto L_ERR_SESSION;
1338     }
1339     uint16_t type = CONNECT_TYPE_NONE;
1340     if (DFileSenderInitWithTargetDev(session, &sockAddr, &type, para->localInterfaceName, 0) != NSTACKX_EOK) {
1341         goto L_ERR_SENDER_INIT;
1342     }
1343 
1344     if (CreateFileManager(session, para->key, para->keyLen, NSTACKX_TRUE, type) != NSTACKX_EOK) {
1345         goto L_ERR_FILE_MANAGER;
1346     }
1347 
1348     if (StartSessionRunning(session, GetClientSendThreadNum(type)) != NSTACKX_EOK) {
1349         goto L_ERR_THREAD;
1350     }
1351 
1352     SendSettingToServer(session);
1353 
1354     return session->sessionId;
1355 L_ERR_THREAD:
1356     StopFileManagerThreads(session->fileManager);
1357     FileManagerDestroy(session->fileManager);
1358 L_ERR_FILE_MANAGER:
1359     DFileSenderDestory(session);
1360 L_ERR_SENDER_INIT:
1361     DFileSessionClean(session);
1362 L_ERR_SESSION:
1363     CongModuleClean();
1364 L_ERR_CONG:
1365     SocketModuleClean();
1366     DFILE_LOGE(TAG, "fail to create dfile client");
1367     return NSTACKX_EFAILED;
1368 }
1369 
NSTACKX_DFileClient(struct sockaddr_in * srvAddr,socklen_t addrLen,const uint8_t * key,uint32_t keyLen,DFileMsgReceiver msgReceiver)1370 int32_t NSTACKX_DFileClient(struct sockaddr_in *srvAddr, socklen_t addrLen, const uint8_t *key, uint32_t keyLen,
1371                             DFileMsgReceiver msgReceiver)
1372 {
1373     /* EaglEye test */
1374     Coverity_Tainted_Set((void *)srvAddr);
1375     Coverity_Tainted_Set((void *)&addrLen);
1376     Coverity_Tainted_Set((void *)key);
1377     Coverity_Tainted_Set((void *)&keyLen);
1378     Coverity_Tainted_Set((void *)msgReceiver);
1379 
1380     NSTACKX_SessionPara sessionPara;
1381 
1382     (void)memset_s(&sessionPara, sizeof(sessionPara), 0, sizeof(sessionPara));
1383     sessionPara.addr = srvAddr;
1384     sessionPara.addrLen = addrLen;
1385     sessionPara.key = key;
1386     sessionPara.keyLen = keyLen;
1387     sessionPara.msgReceiver = msgReceiver;
1388     sessionPara.localInterfaceName = NULL;
1389 #ifdef NSTACKX_WITH_LITEOS
1390     EpollEventPtrInit();
1391 #endif
1392     return NSTACKX_DFileClientWithTargetDev(&sessionPara);
1393 }
1394 
ClearPendingFileList(DFileSession * session)1395 static inline void ClearPendingFileList(DFileSession *session)
1396 {
1397     List *tmp = NULL;
1398     List *pos = NULL;
1399     LIST_FOR_EACH_SAFE(pos, tmp, &session->pendingFileLists) {
1400         FileListInfo *fileListInfo = (FileListInfo *)pos;
1401         ListRemoveNode(&fileListInfo->list);
1402         DestroyFileListInfo(fileListInfo);
1403     }
1404 }
1405 
1406 #ifdef NSTACKX_SMALL_FILE_SUPPORT
ClearSmallFileList(DFileSession * session)1407 static inline void ClearSmallFileList(DFileSession *session)
1408 {
1409     List *tmp = NULL;
1410     List *pos = NULL;
1411     LIST_FOR_EACH_SAFE(pos, tmp, &session->smallFileLists) {
1412         FileListInfo *fileListInfo = (FileListInfo *)pos;
1413         ListRemoveNode(&fileListInfo->list);
1414         DestroyFileListInfo(fileListInfo);
1415     }
1416 }
1417 #endif
1418 
ClearTransChain(DFileSession * session)1419 static inline void ClearTransChain(DFileSession *session)
1420 {
1421     while (!ListIsEmpty(&session->dFileTransChain)) {
1422         DFileTrans *trans = (DFileTrans *)ListPopFront(&session->dFileTransChain);
1423         DFileTransDestroy(trans);
1424     }
1425 }
1426 
ClearOutboundQueue(DFileSession * session)1427 static inline void ClearOutboundQueue(DFileSession *session)
1428 {
1429     List *tmp = NULL;
1430     List *pos = NULL;
1431     LIST_FOR_EACH_SAFE(pos, tmp, &session->outboundQueue) {
1432         QueueNode *node = (QueueNode *)pos;
1433         ListRemoveNode(&node->list);
1434         free(node->frame);
1435         free(node);
1436     }
1437 }
1438 
ClearInboundQueue(DFileSession * session)1439 static inline void ClearInboundQueue(DFileSession *session)
1440 {
1441     List *tmp = NULL;
1442     List *pos = NULL;
1443     LIST_FOR_EACH_SAFE(pos, tmp, &session->inboundQueue) {
1444         QueueNode *node = (QueueNode *)pos;
1445         ListRemoveNode(&node->list);
1446         free(node->frame);
1447         free(node);
1448     }
1449 }
1450 
1451 
NSTACKX_DFileClose(int32_t sessionId)1452 void NSTACKX_DFileClose(int32_t sessionId)
1453 {
1454     /* EaglEye test */
1455     Coverity_Tainted_Set((void *)&sessionId);
1456 
1457     DFILE_LOGI(TAG, "begin to close session");
1458     if (CheckSessionIdValid(sessionId) != NSTACKX_EOK) {
1459         DFILE_LOGE(TAG, "invalid session id (%d) for close", sessionId);
1460         return;
1461     }
1462 
1463     DFileSessionNode *sessionNode = PopDFileSessionNodeById((uint16_t)sessionId);
1464     if (CheckDFileSessionNodeValid(sessionNode) != NSTACKX_EOK) {
1465         DFILE_LOGE(TAG, "no session found for id %d", sessionId);
1466         return;
1467     }
1468 
1469     StopDFileThreads(sessionNode->session);
1470     ClearPendingFileList(sessionNode->session);
1471 #ifdef NSTACKX_SMALL_FILE_SUPPORT
1472     ClearSmallFileList(sessionNode->session);
1473 #endif
1474     ClearTransChain(sessionNode->session);
1475     ClearOutboundQueue(sessionNode->session);
1476     ClearInboundQueue(sessionNode->session);
1477     ClearTransStateList(sessionNode->session);
1478     FileManagerDestroy(sessionNode->session->fileManager);
1479     CloseSocket(sessionNode->session->socket[0]);
1480     CloseSocket(sessionNode->session->socket[1]);
1481     if (sessionNode->session->sessionType == DFILE_SESSION_TYPE_SERVER) {
1482         if (sessionNode->session->acceptSocket != NULL) {
1483             CloseSocket(sessionNode->session->acceptSocket);
1484         }
1485     }
1486 
1487     DFileSessionClean(sessionNode->session);
1488     free(sessionNode);
1489     CongModuleClean();
1490     SocketModuleClean();
1491     DFILE_LOGI(TAG, "finish to close session");
1492 }
1493 
DFileSetRenameHookInner(void * arg)1494 static void DFileSetRenameHookInner(void *arg)
1495 {
1496     DFileSetRenameHookCtx *ctx = arg;
1497     if (ctx->session == NULL) {
1498         free(ctx);
1499         return;
1500     }
1501     ctx->session->onRenameFile = ctx->onRenameFile;
1502     free(ctx);
1503 }
1504 
NSTACKX_DFileSetRenameHook(int32_t sessionId,OnDFileRenameFile onRenameFile)1505 int32_t NSTACKX_DFileSetRenameHook(int32_t sessionId, OnDFileRenameFile onRenameFile)
1506 {
1507     /* EaglEye test */
1508     Coverity_Tainted_Set((void *)&sessionId);
1509     Coverity_Tainted_Set((void *)onRenameFile);
1510     DFileSetRenameHookCtx *ctx = NULL;
1511 
1512     if (CheckSessionIdValid(sessionId) != NSTACKX_EOK || onRenameFile == NULL) {
1513         DFILE_LOGE(TAG, "invalid arg input");
1514         return NSTACKX_EINVAL;
1515     }
1516 
1517     DFileSessionNode *node = GetDFileSessionNodeById((uint16_t)sessionId);
1518     if (CheckDFileSessionNodeValid(node) != NSTACKX_EOK) {
1519         DFILE_LOGE(TAG, "no session found for id %d", sessionId);
1520         return NSTACKX_EINVAL;
1521     }
1522 
1523     ctx = malloc(sizeof(DFileSetRenameHookCtx));
1524     if (ctx == NULL) {
1525         return NSTACKX_ENOMEM;
1526     }
1527     ctx->session = node->session;
1528     ctx->onRenameFile = onRenameFile;
1529 
1530     if (PostEvent(&node->session->eventNodeChain, node->session->epollfd, DFileSetRenameHookInner, ctx) !=
1531         NSTACKX_EOK) {
1532         free(ctx);
1533         return NSTACKX_EFAILED;
1534     }
1535 
1536     return NSTACKX_EOK;
1537 }
1538 
1539 static DFileLogImpl g_userLogImpl;
1540 
LogWrapper(const char * tag,uint32_t level,const char * format,va_list args)1541 static void LogWrapper(const char *tag, uint32_t level, const char *format, va_list args)
1542 {
1543     if (g_userLogImpl) {
1544         g_userLogImpl(tag, level, format, args);
1545     }
1546 }
1547 
NSTACKX_DFileRegisterLog(DFileLogImpl logImpl)1548 int32_t NSTACKX_DFileRegisterLog(DFileLogImpl logImpl)
1549 {
1550     if (logImpl == NULL) {
1551         (void)printf("NULL pointer\n");
1552         return NSTACKX_EFAILED;
1553     }
1554     g_userLogImpl = logImpl;
1555     SetLogImpl(LogWrapper);
1556     return NSTACKX_EOK;
1557 }
1558 
NSTACKX_DFileGetCapabilities(void)1559 uint32_t NSTACKX_DFileGetCapabilities(void)
1560 {
1561     return g_capabilities;
1562 }
1563 
NSTACKX_DFileSetCapabilities(uint32_t capabilities,uint32_t value)1564 int32_t NSTACKX_DFileSetCapabilities(uint32_t capabilities, uint32_t value)
1565 {
1566     /* EaglEye test */
1567     Coverity_Tainted_Set((void *)&capabilities);
1568     Coverity_Tainted_Set((void *)&value);
1569 
1570     /* unused para */
1571     (void)(capabilities);
1572     (void)(value);
1573     return NSTACKX_EOK;
1574 }
1575 
1576 #ifdef DFILE_ENABLE_HIDUMP
NSTACKX_DFileDump(uint32_t argc,const char ** arg,void * softObj,DFileDumpFunc dump)1577 int32_t NSTACKX_DFileDump(uint32_t argc, const char **arg, void *softObj, DFileDumpFunc dump)
1578 {
1579     int32_t ret = 0, c = 0;
1580     char *message = NULL;
1581     char *opt = NULL;
1582     size_t size = 0;
1583     message = (char *)malloc(DUMP_INFO_MAX * sizeof(char));
1584     if (message == NULL) {
1585         DFILE_LOGE(TAG, "malloc failed");
1586         return NSTACKX_EFAILED;
1587     }
1588     (void)memset_s(message, DUMP_INFO_MAX, 0, DUMP_INFO_MAX);
1589 
1590     NstackGetOptMsg optMsg;
1591     (void)NstackInitGetOptMsg(&optMsg);
1592 
1593     while ((c = NstackGetOpt(&optMsg, argc, arg, "s:m:hl")) != NSTACK_GETOPT_END_OF_STR) {
1594         switch (c) {
1595             case 'h':
1596                 ret = HidumpHelp(message, &size);
1597                 break;
1598             case 'l':
1599                 ret = HidumpList(message, &size);
1600                 break;
1601             case 'm':
1602                 opt = (char *)NstackGetOptArgs(&optMsg);
1603                 ret = HidumpMessage(message, &size, opt);
1604                 break;
1605             case 's':
1606                 opt = (char *)NstackGetOptArgs(&optMsg);
1607                 ret = HidumpInformation(message, &size, opt);
1608                 break;
1609             default:
1610                 DFILE_LOGE(TAG, "unknown option");
1611                 ret = HidumpHelp(message, &size);
1612                 break;
1613         }
1614         if (ret != NSTACKX_EOK) {
1615             free(message);
1616             return ret;
1617         }
1618         dump(softObj, message, size);
1619         (void)memset_s(message, DUMP_INFO_MAX, 0, DUMP_INFO_MAX);
1620     }
1621     free(message);
1622     return ret;
1623 }
1624 #endif
1625 
NSTACKX_DFileSetEventFunc(void * softObj,DFileEventFunc func)1626 void NSTACKX_DFileSetEventFunc(void *softObj, DFileEventFunc func)
1627 {
1628     DFileSetEvent(softObj, func);
1629 }
1630 
NSTACKX_DFileRegisterLogCallback(DFileLogCallback userLogCallback)1631 int32_t NSTACKX_DFileRegisterLogCallback(DFileLogCallback userLogCallback)
1632 {
1633     if (userLogCallback == NULL) {
1634         DFILE_LOGE(TAG, "logImpl null");
1635         return NSTACKX_EFAILED;
1636     }
1637     int32_t ret = SetLogCallback(userLogCallback);
1638     return ret;
1639 }
1640 
NSTACKX_DFileRegisterDefaultLog(void)1641 void NSTACKX_DFileRegisterDefaultLog(void)
1642 {
1643     SetDefaultLogCallback();
1644     return;
1645 }
1646 
NSTACKX_DFileSessionGetFileList(int32_t sessionId)1647 int32_t NSTACKX_DFileSessionGetFileList(int32_t sessionId)
1648 {
1649     return NSTACKX_EOK;
1650 }
1651 
NSTACKX_DFileSetSessionOpt(int32_t sessionId,const DFileOpt * opt)1652 int32_t NSTACKX_DFileSetSessionOpt(int32_t sessionId, const DFileOpt *opt)
1653 {
1654     return NSTACKX_EOK;
1655 }