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