• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 #include <semaphore.h>
16 #include <stdio.h>
17 
18 #include "br_proxy.h"
19 #include "comm_log.h"
20 #include "hilog/log.h"
21 #include "napi/native_api.h"
22 #include "securec.h"
23 #include "softbus_adapter_mem.h"
24 #include "softbus_error_code.h"
25 #include "softbus_napi_utils.h"
26 #include "softbus_utils.h"
27 #include "trans_log.h"
28 
29 #define ARGS_SIZE_1         1
30 #define ARGS_SIZE_2         2
31 #define ARGS_SIZE_3         3
32 #define ARGS_INDEX_0        0
33 #define ARGS_INDEX_1        1
34 #define ARGS_INDEX_2        2
35 #define FUNC_NAME_MAX_LEN   22
36 
37 typedef struct {
38     napi_env env;
39     napi_async_work work;
40     napi_deferred deferred;
41     BrProxyChannelInfo channelInfo;
42     int32_t channelId;
43     int32_t openResult;
44     int32_t ret;
45     int32_t sessionId;
46 } AsyncOpenChannelData;
47 
48 static SoftBusMutex g_sessionIdLock;
49 static SoftBusList *g_sessionList = NULL;
50 
51 typedef struct {
52     int32_t sessionId;
53     int32_t channelId;
54     int32_t openResult;
55     sem_t *sem;
56     ListNode node;
57 } SessionInfo;
58 
GetSessionId(void)59 static int32_t GetSessionId(void)
60 {
61     static int32_t sessionId = 0;
62     int32_t id = 0;
63 
64     if (SoftBusMutexLock(&g_sessionIdLock) != SOFTBUS_OK) {
65         TRANS_LOGE(TRANS_SVC, "[br_proxy] get sessionId lock fail");
66         return SOFTBUS_LOCK_ERR;
67     }
68     id = ++sessionId;
69     (void)SoftBusMutexUnlock(&g_sessionIdLock);
70     return id;
71 }
72 
SessionInit(void)73 static int32_t SessionInit(void)
74 {
75     static bool initSuccess = false;
76     if (initSuccess) {
77         return SOFTBUS_OK;
78     }
79     g_sessionList = CreateSoftBusList();
80     if (g_sessionList == NULL) {
81         TRANS_LOGE(TRANS_SDK, "[br_proxy] init list failed");
82         return SOFTBUS_CREATE_LIST_ERR;
83     }
84 
85     SoftBusMutexAttr mutexAttr;
86     mutexAttr.type = SOFTBUS_MUTEX_RECURSIVE;
87     if (SoftBusMutexInit(&g_sessionIdLock, &mutexAttr) != SOFTBUS_OK) {
88         TRANS_LOGE(TRANS_SVC, "[br_proxy] init lock failed");
89         DestroySoftBusList(g_sessionList);
90         return SOFTBUS_TRANS_INIT_FAILED;
91     }
92     initSuccess = true;
93     TRANS_LOGI(TRANS_SDK, "[br_proxy] init trans session success");
94     return SOFTBUS_OK;
95 }
96 
AddSessionToList(int32_t sessionId)97 static int32_t AddSessionToList(int32_t sessionId)
98 {
99     int32_t ret = SOFTBUS_OK;
100     SessionInfo *info = (SessionInfo *)SoftBusCalloc(sizeof(SessionInfo));
101     if (info == NULL) {
102         TRANS_LOGE(TRANS_SDK, "[br_proxy] calloc failed");
103         return SOFTBUS_MALLOC_ERR;
104     }
105     info->sem = (sem_t *)SoftBusCalloc(sizeof(sem_t));
106     if (info->sem == NULL) {
107         TRANS_LOGE(TRANS_SDK, "[br_proxy] calloc failed");
108         ret = SOFTBUS_LOCK_ERR;
109         goto EXIT_FREE_INFO;
110     }
111     info->sessionId = sessionId;
112     sem_init(info->sem, 0, 0);
113     ListInit(&info->node);
114     if (SoftBusMutexLock(&(g_sessionList->lock)) != SOFTBUS_OK) {
115         TRANS_LOGE(TRANS_SDK, "[br_proxy] lock failed");
116         ret = SOFTBUS_LOCK_ERR;
117         goto EXIT_ERR;
118     }
119     ListAdd(&g_sessionList->list, &info->node);
120     g_sessionList->cnt++;
121     TRANS_LOGI(TRANS_SDK, "[br_proxy] add session node success, cnt:%{public}d", g_sessionList->cnt);
122     (void)SoftBusMutexUnlock(&g_sessionList->lock);
123     return SOFTBUS_OK;
124 
125 EXIT_ERR:
126     SoftBusFree(info->sem);
127 EXIT_FREE_INFO:
128     SoftBusFree(info);
129     return ret;
130 }
131 
UpdateListBySessionId(int32_t sessionId,int32_t channelId,int32_t openResult)132 static int32_t UpdateListBySessionId(int32_t sessionId, int32_t channelId, int32_t openResult)
133 {
134     if (g_sessionList == NULL) {
135         TRANS_LOGE(TRANS_SDK, "[br_proxy] not init");
136         return SOFTBUS_NO_INIT;
137     }
138     if (SoftBusMutexLock(&(g_sessionList->lock)) != SOFTBUS_OK) {
139         TRANS_LOGE(TRANS_SDK, "[br_proxy] lock failed");
140         return SOFTBUS_LOCK_ERR;
141     }
142     SessionInfo *nodeInfo = NULL;
143     LIST_FOR_EACH_ENTRY(nodeInfo, &(g_sessionList->list), SessionInfo, node) {
144         if (nodeInfo->sessionId != sessionId) {
145             continue;
146         }
147         nodeInfo->channelId = channelId;
148         nodeInfo->openResult = openResult;
149         (void)SoftBusMutexUnlock(&(g_sessionList->lock));
150         return SOFTBUS_OK;
151     }
152     TRANS_LOGE(TRANS_SDK, "[br_proxy] not find sessionId:%{public}d", sessionId);
153     (void)SoftBusMutexUnlock(&(g_sessionList->lock));
154     return SOFTBUS_NOT_FIND;
155 }
156 
GetSessionInfoBySessionId(int32_t sessionId,SessionInfo * info)157 static int32_t GetSessionInfoBySessionId(int32_t sessionId, SessionInfo *info)
158 {
159     if (g_sessionList == NULL || info == NULL) {
160         TRANS_LOGE(TRANS_SDK, "[br_proxy] invalid param");
161         return SOFTBUS_INVALID_PARAM;
162     }
163     if (SoftBusMutexLock(&(g_sessionList->lock)) != SOFTBUS_OK) {
164         TRANS_LOGE(TRANS_SDK, "[br_proxy] lock failed");
165         return SOFTBUS_LOCK_ERR;
166     }
167     SessionInfo *nodeInfo = NULL;
168     LIST_FOR_EACH_ENTRY(nodeInfo, &(g_sessionList->list), SessionInfo, node) {
169         if (nodeInfo->sessionId != sessionId) {
170             continue;
171         }
172         if (memcpy_s(info, sizeof(SessionInfo), nodeInfo, sizeof(SessionInfo)) != EOK) {
173             (void)SoftBusMutexUnlock(&(g_sessionList->lock));
174             return SOFTBUS_MEM_ERR;
175         }
176         info->sem = nodeInfo->sem;
177         (void)SoftBusMutexUnlock(&(g_sessionList->lock));
178         return SOFTBUS_OK;
179     }
180     TRANS_LOGE(TRANS_SDK, "[br_proxy] not find sessionId:%{public}d", sessionId);
181     (void)SoftBusMutexUnlock(&(g_sessionList->lock));
182     return SOFTBUS_NOT_FIND;
183 }
184 
DeleteSessionById(int32_t sessionId)185 static int32_t DeleteSessionById(int32_t sessionId)
186 {
187     if (g_sessionList == NULL) {
188         TRANS_LOGE(TRANS_SDK, "[br_proxy] not init");
189         return SOFTBUS_NO_INIT;
190     }
191     if (SoftBusMutexLock(&(g_sessionList->lock)) != SOFTBUS_OK) {
192         TRANS_LOGE(TRANS_SDK, "[br_proxy] lock failed");
193         return SOFTBUS_LOCK_ERR;
194     }
195     SessionInfo *sessionNode = NULL;
196     SessionInfo *sessionNodeNext = NULL;
197     LIST_FOR_EACH_ENTRY_SAFE(sessionNode, sessionNodeNext, &(g_sessionList->list), SessionInfo, node) {
198         if (sessionNode->sessionId != sessionId) {
199             continue;
200         }
201         sem_destroy(sessionNode->sem);
202         TRANS_LOGI(TRANS_SDK, "[br_proxy] by sessionId:%{public}d delete node success, cnt:%{public}d",
203             sessionNode->sessionId, g_sessionList->cnt);
204         ListDelete(&sessionNode->node);
205         SoftBusFree(sessionNode->sem);
206         SoftBusFree(sessionNode);
207         g_sessionList->cnt--;
208         (void)SoftBusMutexUnlock(&(g_sessionList->lock));
209         return SOFTBUS_OK;
210     }
211     (void)SoftBusMutexUnlock(&(g_sessionList->lock));
212     return SOFTBUS_NOT_FIND;
213 }
214 
215 static void OnDataReceived(int32_t channelId, const char* data, uint32_t dataLen);
216 static void OnChannelStatusChanged(int32_t channelId, int32_t state);
ChannelOpened(int32_t sessionId,int32_t channelId,int32_t result)217 static int32_t ChannelOpened(int32_t sessionId, int32_t channelId, int32_t result)
218 {
219     TRANS_LOGI(TRANS_SDK, "[br_proxy] sessionId:%{public}d.", sessionId);
220     int32_t ret = UpdateListBySessionId(sessionId, channelId, result);
221     if (ret != SOFTBUS_OK) {
222         TRANS_LOGI(TRANS_SDK, "[br_proxy] ret:%{public}d.", ret);
223         return ret;
224     }
225     SessionInfo info;
226     ret = GetSessionInfoBySessionId(sessionId, &info);
227     if (ret != SOFTBUS_OK) {
228         return ret;
229     }
230     sem_post(info.sem);
231     return SOFTBUS_OK;
232 }
233 
OpenProxyChannelExecute(napi_env env,void * data)234 static void OpenProxyChannelExecute(napi_env env, void* data)
235 {
236     BrProxyChannelInfo channelInfo;
237     AsyncOpenChannelData* asyncData = (AsyncOpenChannelData*)data;
238     if (memcpy_s(channelInfo.peerBRMacAddr, sizeof(channelInfo.peerBRMacAddr),
239         asyncData->channelInfo.peerBRMacAddr, sizeof(asyncData->channelInfo.peerBRMacAddr)) != EOK ||
240         memcpy_s(channelInfo.peerBRUuid, sizeof(channelInfo.peerBRUuid),
241             asyncData->channelInfo.peerBRUuid, sizeof(asyncData->channelInfo.peerBRUuid)) != EOK) {
242         asyncData->ret = SOFTBUS_MEM_ERR;
243         return;
244     }
245     channelInfo.recvPri = asyncData->channelInfo.recvPri;
246     IBrProxyListener listener = {
247         .onChannelOpened = ChannelOpened,
248         .onDataReceived = OnDataReceived,
249         .onChannelStatusChanged = OnChannelStatusChanged,
250     };
251     int32_t ret = AddSessionToList(asyncData->sessionId);
252     if (ret != SOFTBUS_OK) {
253         asyncData->ret = ret;
254         return;
255     }
256     ret = OpenBrProxy(asyncData->sessionId, &channelInfo, &listener);
257     asyncData->ret = ret;
258     if (ret != SOFTBUS_OK) {
259         TRANS_LOGI(TRANS_SDK, "[br_proxy] ret:%{public}d.", ret);
260         return;
261     }
262     SessionInfo info;
263     ret = GetSessionInfoBySessionId(asyncData->sessionId, &info);
264     if (ret != SOFTBUS_OK) {
265         asyncData->ret = ret;
266         return;
267     }
268     sem_wait(info.sem);
269     ret = GetSessionInfoBySessionId(asyncData->sessionId, &info);
270     if (ret != SOFTBUS_OK) {
271         asyncData->ret = ret;
272         return;
273     }
274     asyncData->channelId = info.channelId;
275     asyncData->openResult = info.openResult;
276 }
277 
OpenProxyChannelComplete(napi_env env,napi_status status,void * data)278 static void OpenProxyChannelComplete(napi_env env, napi_status status, void* data)
279 {
280     AsyncOpenChannelData* asyncData = (AsyncOpenChannelData*)data;
281     napi_status napiStatus;
282     napi_value channelIdValue;
283     int32_t ret = asyncData->ret;
284     int32_t openResult = asyncData->openResult;
285     int32_t sessionId = asyncData->sessionId;
286 
287     if (ret != SOFTBUS_OK) {
288         napi_reject_deferred(env, asyncData->deferred, GetBusinessError(env, ret));
289         goto exit;
290     }
291 
292     if (openResult != SOFTBUS_OK) {
293         napi_reject_deferred(env, asyncData->deferred, GetBusinessError(env, openResult));
294         goto exit;
295     }
296 
297     napiStatus = napi_create_int32(env, asyncData->channelId, &channelIdValue);
298     if (napiStatus != napi_ok) {
299         goto cleanup;
300     }
301 
302     napiStatus = napi_resolve_deferred(env, asyncData->deferred, channelIdValue);
303 cleanup:
304     if (napiStatus != napi_ok) {
305         napi_reject_deferred(env, asyncData->deferred, NULL);
306     }
307 exit:
308     DeleteSessionById(sessionId);
309     napi_delete_async_work(env, asyncData->work);
310     SoftBusFree(asyncData);
311 }
312 
GetChannelInfoParam(napi_env env,napi_value arg,AsyncOpenChannelData * asyncData)313 static int32_t GetChannelInfoParam(napi_env env, napi_value arg, AsyncOpenChannelData *asyncData)
314 {
315     napi_status status;
316     napi_value peerBRMacAddrValue;
317     napi_value peerBRUuidValue;
318     size_t strLen;
319     size_t macLen;
320     size_t uuidLen;
321     napi_value linkTypeValue;
322     status = napi_get_named_property(env, arg, "linkType", &linkTypeValue);
323     if (status != napi_ok) {
324         goto EXIT;
325     }
326     status = napi_get_value_int32(env, linkTypeValue, &asyncData->channelInfo.linktype);
327     if (status != napi_ok) {
328         goto EXIT;
329     }
330     if (napi_get_named_property(env, arg, "peerDevAddr", &peerBRMacAddrValue) != napi_ok ||
331         napi_get_named_property(env, arg, "peerUuid", &peerBRUuidValue) != napi_ok) {
332         TRANS_LOGE(TRANS_SDK, "[br_proxy] Failed to get linkType property");
333         goto EXIT;
334     }
335     if (napi_get_value_string_utf8(env, peerBRMacAddrValue, NULL, 0, &macLen) != napi_ok ||
336         napi_get_value_string_utf8(env, peerBRUuidValue, NULL, 0, &uuidLen)) {
337         goto EXIT;
338     }
339     if (macLen < MAC_MIN_LENGTH || (macLen > MAC_MAX_LENGTH && macLen != MAC_SHA256_LEN)) {
340         TRANS_LOGE(TRANS_SDK, "[br_proxy] mac len is wrong, macLen:%{public}zu", macLen);
341         goto EXIT;
342     }
343     if (uuidLen != UUID_STD_LENGTH && uuidLen != UUID_NO_HYPHEN_LENGTH) {
344         TRANS_LOGE(TRANS_SDK, "[br_proxy] uuid len is wrong, uuidLen:%{public}zu", uuidLen);
345         goto EXIT;
346     }
347 
348     if (napi_get_value_string_utf8(env, peerBRMacAddrValue, asyncData->channelInfo.peerBRMacAddr,
349         sizeof(asyncData->channelInfo.peerBRMacAddr), &strLen) != napi_ok) {
350         goto EXIT;
351     }
352     if (napi_get_value_string_utf8(env, peerBRUuidValue, asyncData->channelInfo.peerBRUuid,
353         sizeof(asyncData->channelInfo.peerBRUuid), &strLen) != napi_ok) {
354         goto EXIT;
355     }
356     return SOFTBUS_OK;
357 EXIT:
358     ThrowErrFromC2Js(env, SOFTBUS_TRANS_BR_PROXY_INVALID_PARAM);
359     return SOFTBUS_TRANS_BR_PROXY_INVALID_PARAM;
360 }
361 
StartWork(napi_env env,AsyncOpenChannelData * asyncData)362 static int32_t StartWork(napi_env env, AsyncOpenChannelData *asyncData)
363 {
364     napi_status status;
365     napi_value resourceName;
366     status = napi_create_string_utf8(env, "OpenProxyChannelAsyncWork", NAPI_AUTO_LENGTH, &resourceName);
367     if (status != napi_ok) {
368         napi_reject_deferred(env, asyncData->deferred, NULL);
369         return SOFTBUS_NO_INIT;
370     }
371 
372     status = napi_create_async_work(env, NULL, resourceName, OpenProxyChannelExecute, OpenProxyChannelComplete,
373         asyncData, &asyncData->work);
374     if (status != napi_ok) {
375         napi_reject_deferred(env, asyncData->deferred, NULL);
376         return SOFTBUS_NO_INIT;
377     }
378     status = napi_queue_async_work(env, asyncData->work);
379     if (status != napi_ok) {
380         napi_reject_deferred(env, asyncData->deferred, NULL);
381         napi_delete_async_work(env, asyncData->work);
382         return SOFTBUS_NO_INIT;
383     }
384     return SOFTBUS_OK;
385 }
386 
NapiOpenProxyChannel(napi_env env,napi_callback_info info)387 napi_value NapiOpenProxyChannel(napi_env env, napi_callback_info info)
388 {
389     napi_status status;
390     size_t argc = ARGS_SIZE_1;
391     napi_value args[ARGS_SIZE_1];
392     napi_value thisArg;
393     void* data;
394     status = napi_get_cb_info(env, info, &argc, args, &thisArg, &data);
395     if (status != napi_ok || argc < ARGS_SIZE_1) {
396         napi_throw_error(env, NULL, "Invalid arguments");
397         return NULL;
398     }
399     napi_valuetype valuetype;
400     status = napi_typeof(env, args[0], &valuetype);
401     if (status != napi_ok || valuetype != napi_object) {
402         napi_throw_error(env, NULL, "Argument must be an object");
403         return NULL;
404     }
405     AsyncOpenChannelData* asyncData = (AsyncOpenChannelData*)SoftBusCalloc(sizeof(AsyncOpenChannelData));
406     if (asyncData == NULL) {
407         napi_throw_error(env, NULL, "Memory allocation failed");
408         return NULL;
409     }
410     asyncData->env = env;
411 
412     if (GetChannelInfoParam(env, args[0], asyncData) != SOFTBUS_OK || SessionInit() != SOFTBUS_OK) {
413         goto EXIT;
414     }
415     int32_t sessionId = GetSessionId();
416     if (sessionId <= 0) {
417         goto EXIT;
418     }
419     asyncData->sessionId = sessionId;
420     napi_value promise;
421     status = napi_create_promise(env, &asyncData->deferred, &promise);
422     if (status != napi_ok) {
423         napi_throw_error(env, NULL, "Failed to create promise");
424         goto EXIT;
425     }
426     int32_t ret = StartWork(env, asyncData);
427     if (ret != SOFTBUS_OK) {
428         goto EXIT;
429     }
430     return promise;
431 EXIT:
432     SoftBusFree(asyncData);
433     return NULL;
434 }
435 
ChannelStateEnumInit(napi_env env,napi_value exports)436 napi_value ChannelStateEnumInit(napi_env env, napi_value exports)
437 {
438     napi_status status;
439     napi_value typeEnum;
440     status = napi_create_object(env, &typeEnum);
441     if (status != napi_ok) {
442         return NULL;
443     }
444 
445     napi_value typeValue;
446     if (napi_create_int32(env, CHANNEL_WAIT_RESUME, &typeValue) != napi_ok ||
447         napi_set_named_property(env, typeEnum, "CHANNEL_WAIT_RESUME", typeValue)) {
448         return NULL;
449     }
450 
451     if (napi_create_int32(env, CHANNEL_RESUME, &typeValue) != napi_ok ||
452         napi_set_named_property(env, typeEnum, "CHANNEL_RESUME", typeValue) != napi_ok) {
453         return NULL;
454     }
455 
456     if (napi_create_int32(env, CHANNEL_EXCEPTION_SOFTWARE_FAILED, &typeValue) != napi_ok ||
457         napi_set_named_property(env, typeEnum, "CHANNEL_EXCEPTION_SOFTWARE_FAILED", typeValue) != napi_ok) {
458         return NULL;
459     }
460 
461     if (napi_create_int32(env, CHANNEL_BR_NO_PAIRED, &typeValue) != napi_ok ||
462         napi_set_named_property(env, typeEnum, "CHANNEL_BR_NO_PAIRED", typeValue) != napi_ok) {
463         return NULL;
464     }
465 
466     status = napi_set_named_property(env, exports, "ChannelState", typeEnum);
467     if (status != napi_ok) {
468         return NULL;
469     }
470 
471     return exports;
472 }
473 
NapiCloseProxyChannel(napi_env env,napi_callback_info info)474 napi_value NapiCloseProxyChannel(napi_env env, napi_callback_info info)
475 {
476     napi_status status;
477     size_t argc = ARGS_SIZE_1;
478     napi_value args[ARGS_SIZE_1];
479     napi_value thisArg;
480     void* data;
481     status = napi_get_cb_info(env, info, &argc, args, &thisArg, &data);
482     if (status != napi_ok || argc < ARGS_SIZE_1) {
483         ThrowErrFromC2Js(env, SOFTBUS_TRANS_BR_PROXY_INVALID_PARAM);
484         return NULL;
485     }
486     napi_valuetype valuetype;
487     status = napi_typeof(env, args[0], &valuetype);
488     if (status != napi_ok || valuetype != napi_number) {
489         ThrowErrFromC2Js(env, SOFTBUS_TRANS_BR_PROXY_INVALID_PARAM);
490         return NULL;
491     }
492     int32_t channelId;
493     status = napi_get_value_int32(env, args[0], &channelId);
494     if (status != napi_ok) {
495         ThrowErrFromC2Js(env, SOFTBUS_TRANS_BR_PROXY_INVALID_PARAM);
496         return NULL;
497     }
498     double value;
499     status = napi_get_value_double(env, args[0], &value);
500     if (status != napi_ok) {
501         ThrowErrFromC2Js(env, SOFTBUS_TRANS_BR_PROXY_INVALID_PARAM);
502         return NULL;
503     }
504     int32_t intValue = (int32_t)value;
505     bool isInteger = (double)intValue == value;
506     if (!isInteger) {
507         ThrowErrFromC2Js(env, SOFTBUS_TRANS_BR_PROXY_INVALID_PARAM);
508         return NULL;
509     }
510     int32_t ret = CloseBrProxy(channelId);
511     if (ret != SOFTBUS_OK) {
512         ThrowErrFromC2Js(env, ret);
513         return NULL;
514     }
515     napi_value undefined;
516     status = napi_get_undefined(env, &undefined);
517     if (status != napi_ok) {
518         napi_throw_error(env, NULL, "Failed to get undefined value.");
519         return NULL;
520     }
521     return undefined;
522 }
523 
524 typedef struct {
525     napi_env env;
526     napi_async_work work;
527     napi_deferred deferred;
528     int32_t channelId;
529     char* data;
530     size_t dataLength;
531     int32_t ret;
532 } AsyncSendData;
533 
AsyncWorkExecute(napi_env env,void * data)534 static void AsyncWorkExecute(napi_env env, void* data)
535 {
536     AsyncSendData* asyncData = (AsyncSendData*)data;
537     int32_t ret = SendBrProxyData(asyncData->channelId, asyncData->data, asyncData->dataLength);
538     asyncData->ret = ret;
539 }
540 
AsyncWorkComplete(napi_env env,napi_status status,void * data)541 static void AsyncWorkComplete(napi_env env, napi_status status, void* data)
542 {
543     AsyncSendData* asyncData = (AsyncSendData*)data;
544     napi_status napiStatus;
545 
546     if (asyncData->ret != SOFTBUS_OK) {
547         napi_reject_deferred(env, asyncData->deferred, GetBusinessError(env, asyncData->ret));
548         goto cleanup;
549     }
550 
551     napi_value undefined;
552     napiStatus = napi_get_undefined(env, &undefined);
553     if (napiStatus != napi_ok) {
554         napi_reject_deferred(env, asyncData->deferred, NULL);
555         goto cleanup;
556     }
557     napiStatus = napi_resolve_deferred(env, asyncData->deferred, undefined);
558     if (napiStatus != napi_ok) {
559         napi_reject_deferred(env, asyncData->deferred, NULL);
560     }
561 cleanup:
562     SoftBusFree(asyncData->data);
563     napi_delete_async_work(env, asyncData->work);
564     SoftBusFree(asyncData);
565 }
566 
ChanneIdIsInt(napi_env env,napi_value * args)567 static bool ChanneIdIsInt(napi_env env, napi_value *args)
568 {
569     double value;
570     napi_status status = napi_get_value_double(env, args[0], &value);
571     if (status != napi_ok) {
572         return false;
573     }
574     int32_t intValue = (int32_t)value;
575     bool isInteger = (double)intValue == value;
576     return isInteger;
577 }
578 
GetSendParam(napi_env env,napi_callback_info info,AsyncSendData * asyncData)579 static int32_t GetSendParam(napi_env env, napi_callback_info info, AsyncSendData *asyncData)
580 {
581     size_t argc = ARGS_SIZE_2;
582     napi_value args[ARGS_SIZE_2];
583     napi_value thisArg;
584     void* data;
585     napi_status status = napi_get_cb_info(env, info, &argc, args, &thisArg, &data);
586     if (status != napi_ok || argc < ARGS_SIZE_2) {
587         goto EXIT;
588     }
589     napi_valuetype valueTypeNum;
590     status = napi_typeof(env, args[0], &valueTypeNum);
591     if (status != napi_ok || valueTypeNum != napi_number) {
592         goto EXIT;
593     }
594     status = napi_get_value_int32(env, args[0], &asyncData->channelId);
595     if (status != napi_ok) {
596         goto EXIT;
597     }
598 
599     if (!ChanneIdIsInt(env, args)) {
600         goto EXIT;
601     }
602     napi_valuetype valueTypeBuffer;
603     status = napi_typeof(env, args[1], &valueTypeBuffer);
604     if (status != napi_ok) {
605         goto EXIT;
606     }
607     void* bufferData;
608     status = napi_get_arraybuffer_info(env, args[1], &bufferData, &asyncData->dataLength);
609     if (status != napi_ok || asyncData->dataLength == 0) {
610         goto EXIT;
611     }
612     asyncData->data = (char*)SoftBusCalloc(asyncData->dataLength);
613     if (asyncData->data == NULL) {
614         ThrowErrFromC2Js(env, SOFTBUS_MEM_ERR);
615         return SOFTBUS_TRANS_BR_PROXY_INVALID_PARAM;
616     }
617     if (memcpy_s(asyncData->data, asyncData->dataLength, bufferData, asyncData->dataLength) != EOK) {
618         SoftBusFree(asyncData->data);
619         ThrowErrFromC2Js(env, SOFTBUS_MEM_ERR);
620         return SOFTBUS_TRANS_BR_PROXY_INVALID_PARAM;
621     }
622     return SOFTBUS_OK;
623 EXIT:
624     ThrowErrFromC2Js(env, SOFTBUS_TRANS_BR_PROXY_INVALID_PARAM);
625     return SOFTBUS_TRANS_BR_PROXY_INVALID_PARAM;
626 }
627 
SendDataAsync(napi_env env,napi_callback_info info)628 napi_value SendDataAsync(napi_env env, napi_callback_info info)
629 {
630     napi_status status;
631     napi_value promise;
632     AsyncSendData* asyncData = (AsyncSendData*)SoftBusCalloc(sizeof(AsyncSendData));
633     if (asyncData == NULL) {
634         napi_throw_error(env, NULL, "Memory allocation failed");
635         return NULL;
636     }
637     asyncData->env = env;
638 
639     int32_t ret = GetSendParam(env, info, asyncData);
640     if (ret != SOFTBUS_OK) {
641         SoftBusFree(asyncData);
642         return NULL;
643     }
644 
645     status = napi_create_promise(env, &asyncData->deferred, &promise);
646     if (status != napi_ok) {
647         napi_throw_error(env, NULL, "Failed to create promise");
648         goto cleanup;
649     }
650 
651     napi_value resourceName;
652     status = napi_create_string_utf8(env, "SendDataAsyncWork", NAPI_AUTO_LENGTH, &resourceName);
653     if (status != napi_ok) {
654         napi_reject_deferred(env, asyncData->deferred, NULL);
655         goto cleanup;
656     }
657     status = napi_create_async_work(env, NULL, resourceName, AsyncWorkExecute, AsyncWorkComplete,
658         asyncData, &asyncData->work);
659     if (status != napi_ok) {
660         napi_reject_deferred(env, asyncData->deferred, NULL);
661         goto cleanup;
662     }
663     status = napi_queue_async_work(env, asyncData->work);
664     if (status != napi_ok) {
665         napi_reject_deferred(env, asyncData->deferred, NULL);
666         napi_delete_async_work(env, asyncData->work);
667         goto cleanup;
668     }
669     return promise;
670 cleanup:
671     SoftBusFree(asyncData->data);
672     SoftBusFree(asyncData);
673     return NULL;
674 }
675 
676 static napi_threadsafe_function tsfn_data_received = NULL;
677 static napi_threadsafe_function tsfn_channel_status = NULL;
678 
679 typedef struct {
680     int32_t channelId;
681     char* data;
682     uint32_t dataLen;
683 } DataReceiveArgs;
684 
685 typedef struct {
686     int32_t channelId;
687     int32_t status;
688 } ChannelStatusArgs;
689 
DataReceivedCallback(napi_env env,napi_value callback,void * context,void * data)690 static void DataReceivedCallback(napi_env env, napi_value callback, void *context, void *data)
691 {
692     DataReceiveArgs* args = (DataReceiveArgs*)data;
693     napi_value dataInfo;
694     napi_status status = napi_create_object(env, &dataInfo);
695     if (status != napi_ok) {
696         goto cleanup;
697     }
698 
699     napi_value channelIdValue;
700     status = napi_create_int32(env, args->channelId, &channelIdValue);
701     if (status != napi_ok) {
702         goto cleanup;
703     }
704 
705     status = napi_set_named_property(env, dataInfo, "channelId", channelIdValue);
706     if (status != napi_ok) {
707         goto cleanup;
708     }
709 
710     napi_value arrayBuffer;
711     void *dataBuffer;
712     status = napi_create_arraybuffer(env, args->dataLen, &dataBuffer, &arrayBuffer);
713     if (status != napi_ok) {
714         goto cleanup;
715     }
716     if (memcpy_s(dataBuffer, args->dataLen, args->data, args->dataLen) != EOK) {
717         goto cleanup;
718     }
719     status = napi_set_named_property(env, dataInfo, "data", arrayBuffer);
720     if (status != napi_ok) {
721         goto cleanup;
722     }
723     napi_value result;
724     napi_value args_array[1] = {dataInfo};
725     status = napi_call_function(env, NULL, callback, 1, args_array, &result);
726 cleanup:
727     SoftBusFree(args->data);
728     SoftBusFree(args);
729 }
730 
ChannelStatusCallback(napi_env env,napi_value callback,void * context,void * data)731 static void ChannelStatusCallback(napi_env env, napi_value callback, void *context, void *data)
732 {
733     ChannelStatusArgs* args = (ChannelStatusArgs*)data;
734 
735     napi_value statusInfo;
736     napi_status status = napi_create_object(env, &statusInfo);
737     if (status != napi_ok) {
738         goto cleanup;
739     }
740 
741     napi_value channelIdValue;
742     status = napi_create_int32(env, args->channelId, &channelIdValue);
743     if (status != napi_ok) {
744         goto cleanup;
745     }
746 
747     status = napi_set_named_property(env, statusInfo, "channelId", channelIdValue);
748     if (status != napi_ok) {
749         goto cleanup;
750     }
751 
752     napi_value statusValue;
753     status = napi_create_int32(env, args->status, &statusValue);
754     if (status != napi_ok) {
755         goto cleanup;
756     }
757 
758     status = napi_set_named_property(env, statusInfo, "state", statusValue);
759     if (status != napi_ok) {
760         goto cleanup;
761     }
762 
763     napi_value result;
764     napi_value args_array[1] = {statusInfo};
765     status = napi_call_function(env, NULL, callback, 1, args_array, &result);
766 cleanup:
767     SoftBusFree(args);
768 }
769 
OnDataReceived(int32_t channelId,const char * data,uint32_t dataLen)770 static void OnDataReceived(int32_t channelId, const char* data, uint32_t dataLen)
771 {
772     if (tsfn_data_received == NULL) {
773         return;
774     }
775 
776     DataReceiveArgs* args = (DataReceiveArgs*)SoftBusCalloc(sizeof(DataReceiveArgs));
777     if (args == NULL) {
778         return;
779     }
780     args->channelId = channelId;
781     args->dataLen = dataLen;
782     args->data = (char *)SoftBusCalloc(dataLen);
783     if (args->data == NULL) {
784         SoftBusFree(args);
785         return;
786     }
787 
788     if (memcpy_s(args->data, dataLen, data, dataLen) != EOK) {
789         SoftBusFree(args->data);
790         SoftBusFree(args);
791         return;
792     }
793 
794     napi_status status = napi_call_threadsafe_function(tsfn_data_received, args, napi_tsfn_nonblocking);
795     if (status != napi_ok) {
796         SoftBusFree(args->data);
797         SoftBusFree(args);
798     }
799 }
800 
OnChannelStatusChanged(int32_t channelId,int32_t status)801 static void OnChannelStatusChanged(int32_t channelId, int32_t status)
802 {
803     if (tsfn_channel_status == NULL) {
804         return;
805     }
806 
807     ChannelStatusArgs* args = (ChannelStatusArgs*)SoftBusCalloc(sizeof(ChannelStatusArgs));
808     if (args == NULL) {
809         return;
810     }
811 
812     args->channelId = channelId;
813     args->status = status;
814 
815     napi_status ret = napi_call_threadsafe_function(tsfn_channel_status, args, napi_tsfn_nonblocking);
816     if (ret != napi_ok) {
817         SoftBusFree(args);
818     }
819 }
820 
SetCallbackInternal(napi_env env,napi_value callback,int32_t channelId,ListenerType type)821 static void SetCallbackInternal(napi_env env, napi_value callback, int32_t channelId, ListenerType type)
822 {
823     int32_t ret;
824     switch (type) {
825         case DATA_RECEIVE:
826             if (tsfn_data_received != NULL) {
827                 napi_release_threadsafe_function(tsfn_data_received, napi_tsfn_abort);
828                 tsfn_data_received = NULL;
829             }
830             napi_create_threadsafe_function(
831                 env, callback, NULL, "DataReceived",
832                 0, 1, NULL, NULL, NULL,
833                 DataReceivedCallback, &tsfn_data_received);
834             ret = SetListenerState(channelId, DATA_RECEIVE, true);
835             ThrowErrFromC2Js(env, ret);
836             break;
837         case CHANNEL_STATE:
838             if (tsfn_channel_status != NULL) {
839                 napi_release_threadsafe_function(tsfn_channel_status, napi_tsfn_abort);
840                 tsfn_channel_status = NULL;
841             }
842             napi_create_threadsafe_function(
843                 env, callback, NULL, "ChannelStatus",
844                 0, 1, NULL, NULL, NULL,
845                 ChannelStatusCallback, &tsfn_channel_status);
846             ret = SetListenerState(channelId, CHANNEL_STATE, true);
847             ThrowErrFromC2Js(env, ret);
848             break;
849         default:
850             break;
851     }
852 }
853 
On(napi_env env,napi_callback_info info)854 napi_value On(napi_env env, napi_callback_info info)
855 {
856     size_t argc = ARGS_SIZE_3;
857     napi_value args[ARGS_SIZE_3];
858     napi_status status = napi_get_cb_info(env, info, &argc, args, NULL, NULL);
859     if (status != napi_ok || argc != ARGS_SIZE_3) {
860         goto EXIT;
861     }
862     char type[FUNC_NAME_MAX_LEN];
863     size_t typeLen;
864     status = napi_get_value_string_utf8(env, args[ARGS_INDEX_0], type, sizeof(type), &typeLen);
865     if (status != napi_ok) {
866         goto EXIT;
867     }
868     int32_t channelId;
869     status = napi_get_value_int32(env, args[ARGS_INDEX_1], &channelId);
870     if (status != napi_ok) {
871         goto EXIT;
872     }
873     double value;
874     status = napi_get_value_double(env, args[ARGS_INDEX_1], &value);
875     if (status != napi_ok) {
876         goto EXIT;
877     }
878     int32_t intValue = (int32_t)value;
879     bool isInteger = (double)intValue == value;
880     if (!isInteger) {
881         goto EXIT;
882     }
883     napi_valuetype funcType;
884     status = napi_typeof(env, args[ARGS_INDEX_2], &funcType);
885     if (status != napi_ok || funcType != napi_function) {
886         goto EXIT;
887     }
888     if (strcmp(type, "receiveData") == 0) {
889         SetCallbackInternal(env, args[ARGS_INDEX_2], channelId, DATA_RECEIVE);
890     } else if (strcmp(type, "channelStateChange") == 0) {
891         SetCallbackInternal(env, args[ARGS_INDEX_2], channelId, CHANNEL_STATE);
892     } else {
893         goto EXIT;
894     }
895     return NULL;
896 EXIT:
897     ThrowErrFromC2Js(env, SOFTBUS_TRANS_BR_PROXY_INVALID_PARAM);
898     return NULL;
899 }
900 
GetOffParam(napi_env env,napi_value * args,size_t argc,int32_t * channelId)901 static int32_t GetOffParam(napi_env env, napi_value *args, size_t argc, int32_t *channelId)
902 {
903     if (channelId == NULL) {
904         return SOFTBUS_TRANS_BR_PROXY_INVALID_PARAM;
905     }
906 
907     napi_status status = napi_get_value_int32(env, args[ARGS_INDEX_1], channelId);
908     if (status != napi_ok) {
909         return SOFTBUS_TRANS_BR_PROXY_INVALID_PARAM;
910     }
911     double value;
912     status = napi_get_value_double(env, args[ARGS_INDEX_1], &value);
913     if (status != napi_ok) {
914         return SOFTBUS_TRANS_BR_PROXY_INVALID_PARAM;
915     }
916     int32_t intValue = (int32_t)value;
917     bool isInteger = (double)intValue == value;
918     if (!isInteger) {
919         return SOFTBUS_TRANS_BR_PROXY_INVALID_PARAM;
920     }
921     if (argc != ARGS_SIZE_3) {
922         return SOFTBUS_OK;
923     }
924     napi_valuetype funcType;
925     status = napi_typeof(env, args[ARGS_INDEX_2], &funcType);
926     if (status != napi_ok || funcType != napi_function) {
927         return SOFTBUS_TRANS_BR_PROXY_INVALID_PARAM;
928     }
929     return SOFTBUS_OK;
930 }
931 
Off(napi_env env,napi_callback_info info)932 napi_value Off(napi_env env, napi_callback_info info)
933 {
934     size_t argc = ARGS_SIZE_3;
935     napi_value args[ARGS_SIZE_3];
936     napi_status status = napi_get_cb_info(env, info, &argc, args, NULL, NULL);
937     if (status != napi_ok || argc < ARGS_SIZE_2) {
938         goto EXIT;
939     }
940     char type[FUNC_NAME_MAX_LEN];
941     size_t typeLen;
942     status = napi_get_value_string_utf8(env, args[ARGS_INDEX_0], type, sizeof(type), &typeLen);
943     if (status != napi_ok) {
944         goto EXIT;
945     }
946     int32_t channelId = 0;
947     int32_t ret = GetOffParam(env, args, argc, &channelId);
948     if (ret != SOFTBUS_OK) {
949         goto EXIT;
950     }
951 
952     if (strcmp(type, "receiveData") == 0) {
953         if (tsfn_data_received != NULL) {
954             napi_release_threadsafe_function(tsfn_data_received, napi_tsfn_abort);
955             tsfn_data_received = NULL;
956         }
957         ret = SetListenerState(channelId, DATA_RECEIVE, false);
958         ThrowErrFromC2Js(env, ret);
959     } else if (strcmp(type, "channelStateChange") == 0) {
960         if (tsfn_channel_status != NULL) {
961             napi_release_threadsafe_function(tsfn_channel_status, napi_tsfn_abort);
962             tsfn_channel_status = NULL;
963         }
964         ret = SetListenerState(channelId, CHANNEL_STATE, false);
965         ThrowErrFromC2Js(env, ret);
966     }
967     return NULL;
968 EXIT:
969     ThrowErrFromC2Js(env, SOFTBUS_TRANS_BR_PROXY_INVALID_PARAM);
970     return NULL;
971 }
972 
LinkTypeEnumInit(napi_env env,napi_value exports)973 napi_value LinkTypeEnumInit(napi_env env, napi_value exports)
974 {
975     napi_status status;
976     napi_value typeEnum;
977     status = napi_create_object(env, &typeEnum);
978     if (status != napi_ok) {
979         return NULL;
980     }
981 
982     napi_value typeValue;
983     status = napi_create_int32(env, LINK_BR, &typeValue);
984     if (status != napi_ok) {
985         return NULL;
986     }
987     status = napi_set_named_property(env, typeEnum, "LINK_BR", typeValue);
988     if (status != napi_ok) {
989         return NULL;
990     }
991     status = napi_set_named_property(env, exports, "LinkType", typeEnum);
992     if (status != napi_ok) {
993         return NULL;
994     }
995 
996     return exports;
997 }
998 
NapiSoftbusTransInit(napi_env env,napi_value exports)999 static napi_value NapiSoftbusTransInit(napi_env env, napi_value exports)
1000 {
1001     napi_status status;
1002     napi_value fn;
1003     status = napi_create_function(env, NULL, NAPI_AUTO_LENGTH, NapiOpenProxyChannel, NULL, &fn);
1004     if (status != napi_ok) {
1005         return NULL;
1006     }
1007     status = napi_set_named_property(env, exports, "openProxyChannel", fn);
1008     if (status != napi_ok) {
1009         return NULL;
1010     }
1011     status = napi_create_function(env, NULL, NAPI_AUTO_LENGTH, NapiCloseProxyChannel, NULL, &fn);
1012     if (status != napi_ok) {
1013         return NULL;
1014     }
1015     status = napi_set_named_property(env, exports, "closeProxyChannel", fn);
1016     if (status != napi_ok) {
1017         return NULL;
1018     }
1019     status = napi_create_function(env, NULL, NAPI_AUTO_LENGTH, SendDataAsync, NULL, &fn);
1020     if (status != napi_ok) {
1021         return NULL;
1022     }
1023     status = napi_set_named_property(env, exports, "sendData", fn);
1024     if (status != napi_ok) {
1025         return NULL;
1026     }
1027     if (ChannelStateEnumInit(env, exports) == NULL || LinkTypeEnumInit(env, exports) == NULL) {
1028         return NULL;
1029     }
1030     status = napi_create_function(env, NULL, NAPI_AUTO_LENGTH, On, NULL, &fn);
1031     if (status != napi_ok) {
1032         return NULL;
1033     }
1034     status = napi_set_named_property(env, exports, "on", fn);
1035     if (status != napi_ok) {
1036         return NULL;
1037     }
1038     status = napi_create_function(env, NULL, NAPI_AUTO_LENGTH, Off, NULL, &fn);
1039     if (status != napi_ok) {
1040         return NULL;
1041     }
1042     status = napi_set_named_property(env, exports, "off", fn);
1043     if (status != napi_ok) {
1044         return NULL;
1045     }
1046     return exports;
1047 }
1048 
1049 /*
1050  * Module definition
1051  */
1052 static napi_module g_module = {
1053     .nm_version = 1,
1054     .nm_flags = 0,
1055     .nm_filename = "distributedsched.proxyChannelManager",
1056     .nm_register_func = NapiSoftbusTransInit,
1057     .nm_modname = "distributedsched.proxyChannelManager",
1058     .nm_priv = ((void *)0),
1059     .reserved = { 0 }
1060 };
1061 
1062 /*
1063  * Module registration
1064  */
RegisterSoftbusTransModule(void)1065 __attribute__((constructor)) void RegisterSoftbusTransModule(void)
1066 {
1067     napi_module_register(&g_module);
1068 }
1069 
DestructSoftbusTransModule(void)1070 __attribute__((destructor)) void DestructSoftbusTransModule(void)
1071 {
1072     if (tsfn_data_received != NULL) {
1073         napi_release_threadsafe_function(tsfn_data_received, napi_tsfn_abort);
1074         tsfn_data_received = NULL;
1075     }
1076 
1077     if (tsfn_channel_status != NULL) {
1078         napi_release_threadsafe_function(tsfn_channel_status, napi_tsfn_abort);
1079         tsfn_channel_status = NULL;
1080     }
1081 }