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