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(¶);
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 }