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 }