• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 #ifndef LOG_TAG
16 #define LOG_TAG "bt_napi_socket_spp_server"
17 #endif
18 
19 #include "napi_bluetooth_error.h"
20 #include "napi_bluetooth_utils.h"
21 #include "napi_bluetooth_spp_server.h"
22 #include "bluetooth_errorcode.h"
23 #include "hitrace_meter.h"
24 
25 namespace OHOS {
26 namespace Bluetooth {
27 const int num_20 = 20;
28 using namespace std;
29 int NapiSppServer::count = 0;
30 std::map<int, std::shared_ptr<NapiSppServer>> NapiSppServer::serverMap;
31 
DefineSppFunctions(napi_env env,napi_value exports)32 void DefineSppFunctions(napi_env env, napi_value exports)
33 {
34     SppPropertyValueInit(env, exports);
35     napi_property_descriptor desc[] = {
36         DECLARE_NAPI_FUNCTION("sppListen", NapiSppServer::SppListen),
37         DECLARE_NAPI_FUNCTION("sppAccept", NapiSppServer::SppAccept),
38         DECLARE_NAPI_FUNCTION("sppConnect", NapiSppClient::SppConnect),
39         DECLARE_NAPI_FUNCTION("sppCloseServerSocket", NapiSppServer::SppCloseServerSocket),
40         DECLARE_NAPI_FUNCTION("sppCloseClientSocket", NapiSppClient::SppCloseClientSocket),
41         DECLARE_NAPI_FUNCTION("sppWrite", NapiSppClient::SppWrite),
42         DECLARE_NAPI_FUNCTION("getDeviceId", NapiSppClient::GetDeviceId),
43         DECLARE_NAPI_FUNCTION("getL2capPsm", NapiSppServer::getL2capPsm),
44 #ifdef BLUETOOTH_API_SINCE_10
45         DECLARE_NAPI_FUNCTION("on", NapiSppServer::RegisterSocketObserver),
46         DECLARE_NAPI_FUNCTION("off", NapiSppServer::DeRegisterSocketObserver),
47         DECLARE_NAPI_FUNCTION("sppWriteAsync", NapiSppClient::SppWriteAsync),
48         DECLARE_NAPI_FUNCTION("sppReadAsync", NapiSppClient::SppReadAsync),
49 #endif
50     };
51     HITRACE_METER_NAME(HITRACE_TAG_OHOS, "spp:napi_define_properties");
52     napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
53 }
54 
RegisterSocketObserver(napi_env env,napi_callback_info info)55 napi_value NapiSppServer::RegisterSocketObserver(napi_env env, napi_callback_info info)
56 {
57     return NapiSppClient::On(env, info);
58 }
59 
DeRegisterSocketObserver(napi_env env,napi_callback_info info)60 napi_value NapiSppServer::DeRegisterSocketObserver(napi_env env, napi_callback_info info)
61 {
62     return NapiSppClient::Off(env, info);
63 }
64 
SppTypeInit(napi_env env)65 napi_value SppTypeInit(napi_env env)
66 {
67     HILOGD("enter");
68     napi_value sppType = nullptr;
69     napi_create_object(env, &sppType);
70     SetNamedPropertyByInteger(env, sppType, SppType::SPP_RFCOMM, "SPP_RFCOMM");
71     SetNamedPropertyByInteger(env, sppType, SppType::SPP_L2CAP, "SPP_L2CAP");
72     SetNamedPropertyByInteger(env, sppType, SppType::SPP_L2CAP_BLE, "SPP_L2CAP_BLE");
73     return sppType;
74 }
75 
SppPropertyValueInit(napi_env env,napi_value exports)76 void SppPropertyValueInit(napi_env env, napi_value exports)
77 {
78     napi_value sppTypeObj = SppTypeInit(env);
79     napi_property_descriptor exportFuncs[] = {
80         DECLARE_NAPI_PROPERTY("SppType", sppTypeObj),
81     };
82     HITRACE_METER_NAME(HITRACE_TAG_OHOS, "spp:napi_define_properties");
83     napi_define_properties(env, exports, sizeof(exportFuncs) / sizeof(*exportFuncs), exportFuncs);
84 }
85 
CheckSppListenParams(napi_env env,napi_callback_info info,string & name,SppListenCallbackInfo * callbackInfo)86 static napi_status CheckSppListenParams(
87     napi_env env, napi_callback_info info, string &name, SppListenCallbackInfo *callbackInfo)
88 {
89     HILOGD("enter");
90     size_t argc = ARGS_SIZE_THREE;
91     napi_value argv[ARGS_SIZE_THREE] = {0};
92 
93     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
94     NAPI_BT_RETURN_IF((argc != ARGS_SIZE_THREE && argc != ARGS_SIZE_THREE - CALLBACK_SIZE),
95         "Requires 2 or 3 arguments.", napi_invalid_arg);
96     NAPI_BT_RETURN_IF(!ParseString(env, name, argv[PARAM0]),
97         "Wrong argument type. String expected.", napi_invalid_arg);
98 
99     callbackInfo->env_ = env;
100     callbackInfo->sppOption_ = GetSppOptionFromJS(env, argv[PARAM1]);
101     NAPI_BT_RETURN_IF((callbackInfo->sppOption_ == nullptr), "GetSppOptionFromJS faild.", napi_invalid_arg);
102     callbackInfo->name_ = name;
103 
104     napi_value promise = nullptr;
105 
106     if (argc == ARGS_SIZE_THREE) {
107         HILOGI("callback mode");
108         napi_valuetype valueType = napi_undefined;
109         NAPI_BT_CALL_RETURN(napi_typeof(env, argv[PARAM2], &valueType));
110         NAPI_BT_RETURN_IF(valueType != napi_function, "Wrong argument type. Function expected.", napi_invalid_arg);
111         napi_create_reference(env, argv[PARAM2], 1, &callbackInfo->callback_);
112         napi_get_undefined(env, &promise);
113     } else {
114         HILOGI("promise mode");
115         napi_create_promise(env, &callbackInfo->deferred_, &promise);
116     }
117     return napi_ok;
118 }
119 
SppListen(napi_env env,napi_callback_info info)120 napi_value NapiSppServer::SppListen(napi_env env, napi_callback_info info)
121 {
122     HILOGD("enter");
123     string name;
124     SppListenCallbackInfo *callbackInfo = new (std::nothrow) SppListenCallbackInfo();
125     NAPI_BT_ASSERT_RETURN_UNDEF(env, callbackInfo != nullptr, BT_ERR_INVALID_PARAM);
126     auto status = CheckSppListenParams(env, info, name, callbackInfo);
127     if (status != napi_ok) {
128         delete callbackInfo;
129         callbackInfo = nullptr;
130     }
131     NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
132 
133     napi_value resource = nullptr;
134     napi_create_string_utf8(env, "SppListen", NAPI_AUTO_LENGTH, &resource);
135 
136     napi_create_async_work(
137         env, nullptr, resource,
138         [](napi_env env, void* data) {
139             HILOGI("SppListen execute");
140             SppListenCallbackInfo* callbackInfo = static_cast<SppListenCallbackInfo*>(data);
141             callbackInfo->server_ = std::make_shared<ServerSocket>(callbackInfo->name_,
142                 UUID::FromString(callbackInfo->sppOption_->uuid_), callbackInfo->sppOption_->type_,
143                 callbackInfo->sppOption_->secure_, callbackInfo->sppOption_->psm_);
144             int errorCode = callbackInfo->server_->Listen();
145             HILOGI("SppListen ServerSocket constructor end");
146             if (callbackInfo->server_ ->GetStringTag() != "") {
147                 HILOGI("SppListen execute listen success");
148                 callbackInfo->errorCode_ = CODE_SUCCESS;
149             } else {
150                 HILOGI("SppListen execute listen failed");
151                 callbackInfo->errorCode_ = errorCode;
152             }
153         },
154         [](napi_env env, napi_status status, void* data) {
155             HILOGI("SppListen execute back");
156             SppListenCallbackInfo* callbackInfo = static_cast<SppListenCallbackInfo*>(data);
157             napi_value result[ARGS_SIZE_TWO] = {0};
158             napi_value callback = 0;
159             napi_value undefined = 0;
160             napi_value callResult = 0;
161             napi_get_undefined(env, &undefined);
162 
163             if (callbackInfo->errorCode_ == CODE_SUCCESS) {
164                 HILOGI("SppListen execute back listen success");
165                 std::shared_ptr<NapiSppServer> server =  std::make_shared<NapiSppServer>();
166                 server->id_ = NapiSppServer::count++;
167                 napi_create_int32(env, server->id_, &result[PARAM1]);
168                 server->server_ = callbackInfo->server_;
169                 serverMap.insert(std::make_pair(server->id_, server));
170             } else {
171                 HILOGI("SppListen execute back listen failed");
172                 napi_get_undefined(env, &result[PARAM1]);
173             }
174 
175             if (callbackInfo->callback_) {
176                 HILOGI("SppListen execute back listen Callback mode success");
177                 result[PARAM0] = GetCallbackErrorValue(callbackInfo->env_, callbackInfo->errorCode_);
178                 napi_get_reference_value(env, callbackInfo->callback_, &callback);
179                 napi_call_function(env, undefined, callback, ARGS_SIZE_TWO, result, &callResult);
180                 napi_delete_reference(env, callbackInfo->callback_);
181             } else {
182                 if (callbackInfo->errorCode_ == CODE_SUCCESS) {
183                     HILOGI("SppListen execute back listen Promise mode success");
184                     napi_resolve_deferred(env, callbackInfo->deferred_, result[PARAM1]);
185                 } else {
186                     HILOGI("SppListen execute back listen Promise mode failed");
187                     napi_reject_deferred(env, callbackInfo->deferred_, result[PARAM1]);
188                 }
189             }
190             napi_delete_async_work(env, callbackInfo->asyncWork_);
191             delete callbackInfo;
192             callbackInfo = nullptr;
193         },
194         static_cast<void*>(callbackInfo),
195         &callbackInfo->asyncWork_);
196 
197     napi_queue_async_work(env, callbackInfo->asyncWork_);
198 
199     return NapiGetUndefinedRet(env);
200 }
201 
CheckSppAcceptParams(napi_env env,napi_callback_info info,int32_t & serverSocketNum,SppAcceptCallbackInfo * callbackInfo)202 static napi_status CheckSppAcceptParams(
203     napi_env env, napi_callback_info info, int32_t &serverSocketNum, SppAcceptCallbackInfo *callbackInfo)
204 {
205     HILOGD("enter");
206     size_t argc = ARGS_SIZE_TWO;
207     napi_value argv[ARGS_SIZE_TWO] = {0};
208 
209     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
210     NAPI_BT_RETURN_IF((argc != ARGS_SIZE_TWO && argc != ARGS_SIZE_TWO - CALLBACK_SIZE),
211         "Requires 1 or 2 arguments.", napi_invalid_arg);
212     NAPI_BT_RETURN_IF(!ParseInt32(env, serverSocketNum, argv[PARAM0]),
213         "Wrong argument type. int expected.", napi_invalid_arg);
214 
215     std::shared_ptr<NapiSppServer> server = NapiSppServer::serverMap[serverSocketNum];
216     if (!server) {
217         HILOGE("server is null");
218         return napi_invalid_arg;
219     }
220     callbackInfo->env_ = env;
221     callbackInfo->server_ = server->server_;
222 
223     napi_value promise = nullptr;
224 
225     if (argc == ARGS_SIZE_TWO) {
226         HILOGI("callback mode");
227         napi_valuetype valueType = napi_undefined;
228         NAPI_BT_CALL_RETURN(napi_typeof(env, argv[PARAM1], &valueType));
229         NAPI_BT_RETURN_IF(valueType != napi_function, "Wrong argument type. Function expected.", napi_invalid_arg);
230         napi_create_reference(env, argv[PARAM1], 1, &callbackInfo->callback_);
231         napi_get_undefined(env, &promise);
232     } else {
233         HILOGI("promise mode");
234         napi_create_promise(env, &callbackInfo->deferred_, &promise);
235     }
236     return napi_ok;
237 }
238 
SppAccept(napi_env env,napi_callback_info info)239 napi_value NapiSppServer::SppAccept(napi_env env, napi_callback_info info)
240 {
241     HILOGD("enter");
242     int32_t serverSocketNum = -1;
243     SppAcceptCallbackInfo *callbackInfo = new (std::nothrow) SppAcceptCallbackInfo();
244     NAPI_BT_ASSERT_RETURN_UNDEF(env, callbackInfo != nullptr, BT_ERR_INVALID_PARAM);
245     auto status = CheckSppAcceptParams(env, info, serverSocketNum, callbackInfo);
246     if (status != napi_ok) {
247         delete callbackInfo;
248         callbackInfo = nullptr;
249     }
250     NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
251 
252     napi_value resource = nullptr;
253     napi_create_string_utf8(env, "SppAccept", NAPI_AUTO_LENGTH, &resource);
254 
255     napi_create_async_work(
256         env, nullptr, resource,
257         [](napi_env env, void* data) {
258             HILOGI("SppAccept execute");
259             SppAcceptCallbackInfo* callbackInfo = static_cast<SppAcceptCallbackInfo*>(data);
260             callbackInfo->client_ = callbackInfo->server_->Accept(num_20);
261             if (callbackInfo->client_ != nullptr) {
262                 callbackInfo->errorCode_ = CODE_SUCCESS;
263             } else {
264                 callbackInfo->errorCode_ = CODE_FAILED;
265             }
266         },
267         [](napi_env env, napi_status status, void* data) {
268             HILOGI("SppAccept execute back");
269             SppAcceptCallbackInfo* callbackInfo = static_cast<SppAcceptCallbackInfo*>(data);
270             napi_value result[ARGS_SIZE_TWO] = {0};
271             napi_value callback = 0;
272             napi_value undefined = 0;
273             napi_value callResult = 0;
274             napi_get_undefined(env, &undefined);
275 
276             if (callbackInfo->errorCode_ == CODE_SUCCESS) {
277                 std::shared_ptr<NapiSppClient> client =  std::make_shared<NapiSppClient>();
278                 client->id_ = NapiSppClient::count++;
279                 napi_create_int32(env, client->id_, &result[PARAM1]);
280                 client->client_ = callbackInfo->client_;
281                 NapiSppClient::clientMap.insert(std::make_pair(client->id_, client));
282             } else {
283                 napi_get_undefined(env, &result[PARAM1]);
284             }
285 
286             if (callbackInfo->callback_) {
287                 result[PARAM0] = GetCallbackErrorValue(callbackInfo->env_, callbackInfo->errorCode_);
288                 napi_get_reference_value(env, callbackInfo->callback_, &callback);
289                 napi_call_function(env, undefined, callback, ARGS_SIZE_TWO, result, &callResult);
290                 napi_delete_reference(env, callbackInfo->callback_);
291             } else {
292                 if (callbackInfo->errorCode_ == CODE_SUCCESS) {
293                     napi_resolve_deferred(env, callbackInfo->deferred_, result[PARAM1]);
294                 } else {
295                     napi_reject_deferred(env, callbackInfo->deferred_, result[PARAM1]);
296                 }
297             }
298             napi_delete_async_work(env, callbackInfo->asyncWork_);
299             delete callbackInfo;
300             callbackInfo = nullptr;
301         },
302         static_cast<void*>(callbackInfo),
303         &callbackInfo->asyncWork_);
304 
305     napi_queue_async_work(env, callbackInfo->asyncWork_);
306 
307     return NapiGetUndefinedRet(env);
308 }
309 
CheckSppCloseServerSockeParams(napi_env env,napi_callback_info info,int & id)310 static napi_status CheckSppCloseServerSockeParams(napi_env env, napi_callback_info info, int &id)
311 {
312     HILOGD("enter");
313     size_t argc = ARGS_SIZE_ONE;
314     napi_value argv[ARGS_SIZE_ONE] = {0};
315     napi_value thisVar = nullptr;
316 
317     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
318     NAPI_BT_RETURN_IF((argc != ARGS_SIZE_ONE), "Requires 1 arguments.", napi_invalid_arg);
319     NAPI_BT_RETURN_IF(!ParseInt32(env, id, argv[PARAM0]), "Wrong argument type. int expected.", napi_invalid_arg);
320     return napi_ok;
321 }
322 
SppCloseServerSocket(napi_env env,napi_callback_info info)323 napi_value NapiSppServer::SppCloseServerSocket(napi_env env, napi_callback_info info)
324 {
325     HILOGD("enter");
326     int id =  -1;
327     auto status = CheckSppCloseServerSockeParams(env, info, id);
328     NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
329 
330     bool isOK = false;
331 
332     std::shared_ptr<NapiSppServer> server = nullptr;
333     std::shared_ptr<NapiSppClient> client = nullptr;
334 
335     if (NapiSppClient::clientMap[id] != nullptr) {
336         client = NapiSppClient::clientMap[id];
337         if (client->client_) {
338             client->client_->Close();
339             NapiSppClient::clientMap.erase(id);
340         }
341     } else {
342         HILOGE("no such key in clientMap.");
343     }
344 
345     if (serverMap[id] != nullptr) {
346         server = serverMap[id];
347         if (server->server_) {
348             server->server_->Close();
349             serverMap.erase(id);
350             isOK = true;
351         }
352     } else {
353         HILOGE("no such key in serverMap.");
354     }
355 
356     return NapiGetBooleanRet(env, isOK);
357 }
358 
CheckSppFdParams(napi_env env,napi_callback_info info,int & id)359 static napi_status CheckSppFdParams(napi_env env, napi_callback_info info, int &id)
360 {
361     size_t argc = ARGS_SIZE_ONE;
362     napi_value argv[ARGS_SIZE_ONE] = {0};
363 
364     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
365     NAPI_BT_RETURN_IF(argc != ARGS_SIZE_ONE, "Requires 1 arguments.", napi_invalid_arg);
366     NAPI_BT_RETURN_IF(!ParseInt32(env, id, argv[PARAM0]), "Wrong argument type. int expected.", napi_invalid_arg);
367     return napi_ok;
368 }
369 
getL2capPsm(napi_env env,napi_callback_info info)370 napi_value NapiSppServer::getL2capPsm(napi_env env, napi_callback_info info)
371 {
372     HILOGD("enter");
373     int id = -1;
374     auto status = CheckSppFdParams(env, info, id);
375     NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
376     auto server = serverMap[id];
377     NAPI_BT_ASSERT_RETURN_UNDEF(env, server != nullptr, BT_ERR_INVALID_PARAM);
378     NAPI_BT_ASSERT_RETURN_UNDEF(env, server->server_ != nullptr, BT_ERR_INVALID_PARAM);
379     int32_t l2capPsm = server->server_->GetL2capPsm();
380     napi_value result = nullptr;
381     napi_create_int32(env, l2capPsm, &result);
382     return result;
383 }
384 
385 } // namespace Bluetooth
386 } // namespace OHOS
387