1 /*
2 * Copyright (C) 2021 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
16 #include "napi_bluetooth_spp_client.h"
17 #include "securec.h"
18 #include <unistd.h>
19 #include <uv.h>
20
21 namespace OHOS {
22 namespace Bluetooth {
23 const int sleepTime = 5;
24 std::map<int, std::shared_ptr<NapiSppClient>> NapiSppClient::clientMap;
25 int NapiSppClient::count = 0;
26
SppConnect(napi_env env,napi_callback_info info)27 napi_value NapiSppClient::SppConnect(napi_env env, napi_callback_info info)
28 {
29 HILOGI("SppConnect called");
30 size_t expectedArgsCount = ARGS_SIZE_THREE;
31 size_t argc = expectedArgsCount;
32 napi_value argv[ARGS_SIZE_THREE] = {0};
33
34 napi_value ret = nullptr;
35 napi_get_undefined(env, &ret);
36
37 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
38 if (argc != expectedArgsCount && argc != expectedArgsCount - CALLBACK_SIZE) {
39 HILOGE("Requires 2 or 3 arguments.");
40 return ret;
41 }
42
43 std::string deviceId;
44 if (!ParseString(env, deviceId, argv[PARAM0])) {
45 HILOGE("Wrong argument type. String expected.");
46 return ret;
47 }
48
49 SppConnectCallbackInfo *callbackInfo = new SppConnectCallbackInfo();
50 callbackInfo->env_ = env;
51 callbackInfo->sppOption_ = GetSppOptionFromJS(env, argv[PARAM1]);
52 callbackInfo->deviceId_ = deviceId;
53
54 napi_value promise = nullptr;
55
56 if (argc == expectedArgsCount) {
57 // Callback mode
58 HILOGI("SppConnect callback mode");
59 napi_valuetype valueType = napi_undefined;
60 napi_typeof(env, argv[PARAM2], &valueType);
61 if (valueType != napi_function) {
62 HILOGE("Wrong argument type. Function expected.");
63 delete callbackInfo;
64 callbackInfo = nullptr;
65 return ret;
66 }
67 napi_create_reference(env, argv[PARAM2], 1, &callbackInfo->callback_);
68 napi_get_undefined(env, &promise);
69 } else {
70 // Promise mode
71 HILOGI("SppConnect promise mode");
72 napi_create_promise(env, &callbackInfo->deferred_, &promise);
73 }
74
75 napi_value resource = nullptr;
76 napi_create_string_utf8(env, "SppConnect", NAPI_AUTO_LENGTH, &resource);
77
78 napi_create_async_work(
79 env, nullptr, resource,
80 [](napi_env env, void* data) {
81 HILOGI("SppConnect execute");
82 SppConnectCallbackInfo* callbackInfo = (SppConnectCallbackInfo*)data;
83 callbackInfo->device_ = std::make_shared<BluetoothRemoteDevice>(callbackInfo->deviceId_, 0);
84 callbackInfo->client_ = std::make_shared<SppClientSocket>(*callbackInfo->device_,
85 UUID::FromString(callbackInfo->sppOption_->uuid_),
86 callbackInfo->sppOption_->type_, callbackInfo->sppOption_->secure_);
87 HILOGI("SppConnect client_ constructed");
88 if (callbackInfo->client_->Connect() == BtStatus::BT_SUCCESS) {
89 HILOGI("SppConnect successfully");
90 callbackInfo->errorCode_ = CODE_SUCCESS;
91 } else {
92 HILOGI("SppConnect failed");
93 callbackInfo->errorCode_ = CODE_FAILED;
94 }
95 },
96 [](napi_env env, napi_status status, void* data) {
97 HILOGI("SppConnect execute back");
98 SppConnectCallbackInfo* callbackInfo = (SppConnectCallbackInfo*)data;
99 napi_value result[ARGS_SIZE_TWO] = {0};
100 napi_value callback = 0;
101 napi_value undefined = 0;
102 napi_value callResult = 0;
103 napi_get_undefined(env, &undefined);
104
105 if (callbackInfo->errorCode_ == CODE_SUCCESS) {
106 HILOGI("SppConnect execute back success");
107 std::shared_ptr<NapiSppClient> client = std::make_shared<NapiSppClient>();
108 client->device_ = callbackInfo->device_;
109 client->id_ = NapiSppClient::count++;
110 napi_create_int32(env, client->id_, &result[PARAM1]);
111 client->client_ = callbackInfo->client_;
112 clientMap.insert(std::make_pair(client->id_, client));
113 HILOGI("SppConnect execute back successfully");
114 } else {
115 napi_get_undefined(env, &result[PARAM1]);
116 HILOGI("SppConnect execute back failed");
117 }
118
119 if (callbackInfo->callback_) {
120 // Callback mode
121 HILOGI("SppConnect execute Callback mode");
122 result[PARAM0] = GetCallbackErrorValue(callbackInfo->env_, callbackInfo->errorCode_);
123 napi_get_reference_value(env, callbackInfo->callback_, &callback);
124 napi_call_function(env, undefined, callback, ARGS_SIZE_TWO, result, &callResult);
125 napi_delete_reference(env, callbackInfo->callback_);
126 } else {
127 if (callbackInfo->errorCode_ == CODE_SUCCESS) {
128 // Promise mode
129 HILOGI("SppConnect execute Promise mode successfully");
130 napi_resolve_deferred(env, callbackInfo->deferred_, result[PARAM1]);
131 } else {
132 HILOGI("SppConnect execute Promise mode failed");
133 napi_reject_deferred(env, callbackInfo->deferred_, result[PARAM1]);
134 }
135 }
136 napi_delete_async_work(env, callbackInfo->asyncWork_);
137 delete callbackInfo;
138 callbackInfo = nullptr;
139 },
140 (void*)callbackInfo,
141 &callbackInfo->asyncWork_);
142 napi_queue_async_work(env, callbackInfo->asyncWork_);
143 return ret;
144 }
145
SppCloseClientSocket(napi_env env,napi_callback_info info)146 napi_value NapiSppClient::SppCloseClientSocket(napi_env env, napi_callback_info info)
147 {
148 HILOGI("SppCloseClientSocket called");
149 size_t expectedArgsCount = ARGS_SIZE_ONE;
150 size_t argc = expectedArgsCount;
151 napi_value argv[ARGS_SIZE_ONE] = {0};
152 napi_value thisVar = nullptr;
153 bool isOK = false;
154 napi_value ret = nullptr;
155
156 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
157 if (argc != expectedArgsCount) {
158 HILOGE("Requires 1 argument.");
159 return ret;
160 }
161
162 std::shared_ptr<NapiSppClient> client = nullptr;
163 int id = -1;
164 ParseInt32(env, id, argv[PARAM0]);
165
166 if (clientMap[id]) {
167 client = clientMap[id];
168 } else {
169 HILOGE("no such key in map.");
170 return ret;
171 }
172
173 if (client->client_) {
174 client->client_->Close();
175 isOK = true;
176 }
177 clientMap.erase(id);
178 napi_get_boolean(env, isOK, &ret);
179 return ret;
180 }
181
SppWrite(napi_env env,napi_callback_info info)182 napi_value NapiSppClient::SppWrite(napi_env env, napi_callback_info info)
183 {
184 napi_value ret = nullptr;
185 napi_get_undefined(env, &ret);
186 size_t expectedArgsCount = ARGS_SIZE_TWO;
187 size_t argc = expectedArgsCount;
188 napi_value argv[ARGS_SIZE_TWO] = {0};
189 napi_value thisVar = nullptr;
190 char* totalBuf = nullptr;
191 size_t totalSize = 0;
192 bool isOK = false;
193 int id = -1;
194 napi_get_boolean(env, isOK, &ret);
195
196 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
197 if (argc != expectedArgsCount) {
198 HILOGE("Requires 3 argument.");
199 return ret;
200 }
201
202 ParseInt32(env, id, argv[PARAM0]);
203
204 if (!ParseArrayBuffer(env, (uint8_t**)(&totalBuf), totalSize, argv[PARAM1])) {
205 HILOGE("ParseArrayBuffer failed");
206 return ret;
207 }
208
209 if (clientMap[id]) {
210 OHOS::Bluetooth::OutputStream outputStream = clientMap[id]->client_->GetOutputStream();
211
212 while (totalSize) {
213 int result = outputStream.Write(totalBuf, totalSize);
214 if (result > 0) {
215 totalSize = totalSize - result;
216 totalBuf += result;
217 isOK = true;
218 } else if (result < 0) {
219 HILOGI("Write socket exception!");
220 return ret;
221 }
222 }
223 } else {
224 HILOGI("Client socket not exit!");
225 }
226 napi_get_boolean(env, isOK, &ret);
227 return ret;
228 }
On(napi_env env,napi_callback_info info)229 void NapiSppClient::On(napi_env env, napi_callback_info info)
230 {
231 HILOGI("On is called");
232
233 size_t expectedArgsCount = ARGS_SIZE_THREE;
234 size_t argc = expectedArgsCount;
235 napi_value argv[ARGS_SIZE_THREE] = {0};
236 napi_value thisVar = nullptr;
237 int id = -1;
238
239 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
240 if (argc != expectedArgsCount) {
241 HILOGE("Requires 3 argument.");
242 return;
243 }
244 std::string type;
245 ParseString(env, type, argv[PARAM0]);
246 std::shared_ptr<BluetoothCallbackInfo> callbackInfo;
247 if (type.c_str() == STR_BT_SPP_READ) {
248 callbackInfo = std::make_shared<BufferCallbackInfo>();
249 } else {
250 callbackInfo = std::make_shared<BluetoothCallbackInfo>();
251 }
252 callbackInfo->env_ = env;
253
254 napi_valuetype valueType1 = napi_undefined;
255 napi_valuetype valueType2 = napi_undefined;
256 napi_typeof(env, argv[PARAM1], &valueType1);
257 napi_typeof(env, argv[PARAM2], &valueType2);
258 if (valueType1 != napi_number && valueType2 != napi_function) {
259 HILOGE("Wrong argument type. Function expected.");
260 return;
261 }
262
263 napi_create_reference(env, argv[PARAM2], 1, &callbackInfo->callback_);
264
265 ParseInt32(env, id, argv[PARAM1]);
266 std::shared_ptr<NapiSppClient> client = clientMap[id];
267 if (!client) {
268 HILOGI("client is nullptr");
269 return;
270 }
271 client->sppReadFlag = true;
272 client->callbackInfos_[type] = callbackInfo;
273 HILOGI("sppRead begin");
274 client->thread_ = std::make_shared<std::thread>(sppRead, id);
275 client->thread_->detach();
276 return;
277 }
278
Off(napi_env env,napi_callback_info info)279 void NapiSppClient::Off(napi_env env, napi_callback_info info)
280 {
281 size_t expectedArgsCount = ARGS_SIZE_THREE;
282 size_t argc = expectedArgsCount;
283 napi_value argv[ARGS_SIZE_THREE] = {0};
284 napi_value thisVar = nullptr;
285 int id = -1;
286
287 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
288 if (argc != expectedArgsCount) {
289 HILOGE("Requires 3 argument.");
290 return;
291 }
292
293 std::string type;
294 ParseString(env, type, argv[PARAM0]);
295
296 ParseInt32(env, id, argv[PARAM1]);
297 std::shared_ptr<NapiSppClient> client = clientMap[id];
298 if (!client) {
299 HILOGI("client is nullptr");
300 return;
301 }
302 client->callbackInfos_[type] = nullptr;
303 client->sppReadFlag = false;
304 sleep(sleepTime);
305 return;
306 }
307
sppRead(int id)308 void NapiSppClient::sppRead(int id)
309 {
310 HILOGI("sppRead is called");
311 OHOS::Bluetooth::InputStream inputStream = clientMap[id]->client_->GetInputStream();
312 char buf[1024];
313 int ret = 0;
314 bool isRead = true;
315 while (isRead) {
316 if (clientMap[id] == nullptr) {
317 isRead = false;
318 break;
319 }
320 isRead = clientMap[id]->sppReadFlag;
321 HILOGI("inputStream.Read start");
322 while (true) {
323 memset_s(buf, sizeof(buf), 0, sizeof(buf));
324 ret = inputStream.Read(buf, sizeof(buf));
325 HILOGI("inputStream.Read end");
326 if (ret <= 0) {
327 HILOGI("inputStream.Read failed");
328 isRead = false;
329 break;
330 } else {
331 HILOGI("napi_call_function begin");
332 std::shared_ptr<BufferCallbackInfo> callbackInfo =
333 std::static_pointer_cast<BufferCallbackInfo>(clientMap[id]->callbackInfos_[STR_BT_SPP_READ]);
334
335 callbackInfo->info_ = ret;
336 memcpy_s(callbackInfo->buffer_, sizeof(callbackInfo->buffer_), buf, ret);
337
338 uv_loop_s *loop = nullptr;
339 napi_get_uv_event_loop(callbackInfo->env_, &loop);
340 uv_work_t *work = new uv_work_t;
341 work->data = (void*)callbackInfo.get();
342
343 uv_queue_work(
344 loop,
345 work,
346 [](uv_work_t *work) {},
347 [](uv_work_t *work, int status) {
348 BufferCallbackInfo *callbackInfo = (BufferCallbackInfo *)work->data;
349 int size = callbackInfo->info_;
350 uint8_t* totalBuf = (uint8_t*) malloc(size);
351 memcpy_s(totalBuf, size, callbackInfo->buffer_, size);
352 napi_value result = nullptr;
353 uint8_t* bufferData = nullptr;
354 napi_create_arraybuffer(callbackInfo->env_ , size, (void**)&bufferData, &result);
355 memcpy_s(bufferData, size, totalBuf, size);
356 free(totalBuf);
357
358 napi_value callback = nullptr;
359 napi_value undefined = nullptr;
360 napi_value callResult = nullptr;
361 napi_get_undefined(callbackInfo->env_, &undefined);
362 napi_get_reference_value(callbackInfo->env_, callbackInfo->callback_, &callback);
363 napi_call_function(callbackInfo->env_, undefined, callback, ARGS_SIZE_ONE, &result, &callResult);
364 delete work;
365 work = nullptr;
366 }
367 );
368 }
369 }
370 }
371 return;
372 }
373 } // namespace Bluetooth
374 } // namespace OHOS