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