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