• 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 #include "napi_bluetooth_gatt_server.h"
16 #include "bluetooth_gatt_service.h"
17 #include "bluetooth_host.h"
18 #include "bluetooth_log.h"
19 #include "bluetooth_utils.h"
20 #include "napi_bluetooth_ble.h"
21 #include "napi_bluetooth_ble_utils.h"
22 #include "napi_bluetooth_error.h"
23 #include "napi_bluetooth_utils.h"
24 #include "napi_event_subscribe_module.h"
25 #include "../parser/napi_parser_utils.h"
26 
27 namespace OHOS {
28 namespace Bluetooth {
29 using namespace std;
30 
31 std::vector<std::string> NapiGattServer::deviceList_;
32 std::mutex NapiGattServer::deviceListMutex_;
33 thread_local napi_ref NapiGattServer::consRef_ = nullptr;
34 
CreateGattServer(napi_env env,napi_callback_info info)35 napi_value NapiGattServer::CreateGattServer(napi_env env, napi_callback_info info)
36 {
37     HILOGI("enter");
38     napi_value result;
39     napi_value constructor = nullptr;
40     napi_get_reference_value(env, consRef_, &constructor);
41     napi_new_instance(env, constructor, 0, nullptr, &result);
42 
43     return result;
44 }
45 
DefineGattServerJSClass(napi_env env)46 void NapiGattServer::DefineGattServerJSClass(napi_env env)
47 {
48     napi_property_descriptor gattserverDesc[] = {
49 #ifdef BLUETOOTH_API_SINCE_10
50         DECLARE_NAPI_FUNCTION("notifyCharacteristicChanged", NotifyCharacteristicChangedEx),
51 #else
52         DECLARE_NAPI_FUNCTION("startAdvertising", StartAdvertising),
53         DECLARE_NAPI_FUNCTION("stopAdvertising", StopAdvertising),
54         DECLARE_NAPI_FUNCTION("notifyCharacteristicChanged", NotifyCharacteristicChanged),
55 #endif
56         DECLARE_NAPI_FUNCTION("addService", AddService),
57         DECLARE_NAPI_FUNCTION("removeService", RemoveGattService),
58         DECLARE_NAPI_FUNCTION("close", Close),
59         DECLARE_NAPI_FUNCTION("sendResponse", SendResponse),
60         DECLARE_NAPI_FUNCTION("on", On),
61         DECLARE_NAPI_FUNCTION("off", Off),
62     };
63 
64     napi_value constructor = nullptr;
65     napi_define_class(env, "GattServer", NAPI_AUTO_LENGTH, GattServerConstructor, nullptr,
66         sizeof(gattserverDesc) / sizeof(gattserverDesc[0]), gattserverDesc, &constructor);
67     napi_create_reference(env, constructor, 1, &consRef_);
68 }
69 
GattServerConstructor(napi_env env,napi_callback_info info)70 napi_value NapiGattServer::GattServerConstructor(napi_env env, napi_callback_info info)
71 {
72     napi_value thisVar = nullptr;
73     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
74     NapiGattServer* gattServer = new NapiGattServer();
75 
76     napi_wrap(
77         env, thisVar, gattServer,
78         [](napi_env env, void* data, void* hint) {
79             NapiGattServer* server = static_cast<NapiGattServer*>(data);
80             if (server) {
81                 delete server;
82                 server = nullptr;
83             }
84         },
85         nullptr,
86         nullptr);
87 
88     return thisVar;
89 }
90 
NapiGetGattServer(napi_env env,napi_value thisVar)91 static NapiGattServer *NapiGetGattServer(napi_env env, napi_value thisVar)
92 {
93     NapiGattServer *gattServer = nullptr;
94     auto status = napi_unwrap(env, thisVar, (void **)&gattServer);
95     if (status != napi_ok) {
96         return nullptr;
97     }
98     return gattServer;
99 }
100 
NapiGetGattServer(napi_env env,napi_callback_info info)101 static NapiGattServer *NapiGetGattServer(napi_env env, napi_callback_info info)
102 {
103     size_t argc = 0;
104     napi_value thisVar = nullptr;
105     if (napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr) != napi_ok) {
106         return nullptr;
107     }
108     return NapiGetGattServer(env, thisVar);
109 }
110 
On(napi_env env,napi_callback_info info)111 napi_value NapiGattServer::On(napi_env env, napi_callback_info info)
112 {
113     NapiGattServer *napiGattServer = NapiGetGattServer(env, info);
114     if (napiGattServer && napiGattServer->GetCallback()) {
115         auto status = napiGattServer->GetCallback()->eventSubscribe_.Register(env, info);
116         NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
117     }
118     return NapiGetUndefinedRet(env);
119 }
120 
Off(napi_env env,napi_callback_info info)121 napi_value NapiGattServer::Off(napi_env env, napi_callback_info info)
122 {
123     NapiGattServer *napiGattServer = NapiGetGattServer(env, info);
124     if (napiGattServer && napiGattServer->GetCallback()) {
125         auto status = napiGattServer->GetCallback()->eventSubscribe_.Deregister(env, info);
126         NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
127     }
128     return NapiGetUndefinedRet(env);
129 }
130 
CheckGattsAddService(napi_env env,napi_callback_info info,std::shared_ptr<GattServer> & outServer,std::unique_ptr<GattService> & outService)131 static napi_status CheckGattsAddService(napi_env env, napi_callback_info info, std::shared_ptr<GattServer> &outServer,
132     std::unique_ptr<GattService> &outService)
133 {
134     size_t argc = ARGS_SIZE_ONE;
135     napi_value argv[ARGS_SIZE_ONE] = {nullptr};
136     napi_value thisVar = nullptr;
137     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
138     NAPI_BT_RETURN_IF(argc != ARGS_SIZE_ONE, "Requires 1 arguments.", napi_invalid_arg);
139 
140     // std::unique_ptr<GattService> service {nullptr};
141     NapiGattService napiGattService;
142     NAPI_BT_CALL_RETURN(NapiParseGattService(env, argv[PARAM0], napiGattService));
143 
144     NapiGattServer *gattServer = NapiGetGattServer(env, thisVar);
145     NAPI_BT_RETURN_IF(gattServer == nullptr, "gattServer is nullptr.", napi_invalid_arg);
146     outServer = gattServer->GetServer();
147 
148     GattServiceType type = napiGattService.isPrimary ? GattServiceType::PRIMARY : GattServiceType::SECONDARY;
149     outService = std::make_unique<GattService>(napiGattService.serviceUuid, type);
150     for (const auto &napiCharacter : napiGattService.characteristics) {
151         int charPermissions = napiCharacter.permissions;
152         int charProperties = napiCharacter.properties;
153         GattCharacteristic character(napiCharacter.characteristicUuid, charPermissions, charProperties);
154         character.SetValue(napiCharacter.characteristicValue.data(), napiCharacter.characteristicValue.size());
155 
156         for (const auto &napiDescriptor : napiCharacter.descriptors) {
157             GattDescriptor descriptor(napiDescriptor.descriptorUuid, napiDescriptor.permissions);
158             descriptor.SetValue(napiDescriptor.descriptorValue.data(), napiDescriptor.descriptorValue.size());
159             character.AddDescriptor(descriptor);
160         }
161         outService->AddCharacteristic(character);
162     }
163 
164     return napi_ok;
165 }
166 
AddService(napi_env env,napi_callback_info info)167 napi_value NapiGattServer::AddService(napi_env env, napi_callback_info info)
168 {
169     HILOGI("enter");
170     std::shared_ptr<GattServer> server {nullptr};
171     std::unique_ptr<GattService> gattService {nullptr};
172     auto status = CheckGattsAddService(env, info, server, gattService);
173     NAPI_BT_ASSERT_RETURN_FALSE(env, (status == napi_ok && server != nullptr), BT_ERR_INVALID_PARAM);
174 
175     int ret = server->AddService(*gattService);
176     NAPI_BT_ASSERT_RETURN_FALSE(env, ret == BT_NO_ERROR, ret);
177     return NapiGetBooleanTrue(env);
178 }
179 
CheckGattsClose(napi_env env,napi_callback_info info,std::shared_ptr<GattServer> & outServer)180 static napi_status CheckGattsClose(napi_env env, napi_callback_info info, std::shared_ptr<GattServer> &outServer)
181 {
182     size_t argc = 0;
183     napi_value thisVar = nullptr;
184     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, nullptr, &thisVar, NULL));
185     NAPI_BT_RETURN_IF(argc > 0, "no needed arguments.", napi_invalid_arg);
186     NapiGattServer *gattServer = NapiGetGattServer(env, thisVar);
187     NAPI_BT_RETURN_IF(gattServer == nullptr, "gattServer is nullptr.", napi_invalid_arg);
188 
189     outServer = gattServer->GetServer();
190     return napi_ok;
191 }
192 
Close(napi_env env,napi_callback_info info)193 napi_value NapiGattServer::Close(napi_env env, napi_callback_info info)
194 {
195     HILOGI("enter");
196     std::shared_ptr<GattServer> server {nullptr};
197     auto status = CheckGattsClose(env, info, server);
198     NAPI_BT_ASSERT_RETURN_UNDEF(env, (status == napi_ok && server != nullptr), BT_ERR_INVALID_PARAM);
199 
200     int ret = server->Close();
201     NAPI_BT_ASSERT_RETURN_UNDEF(env, ret == BT_NO_ERROR, ret);
202     return NapiGetUndefinedRet(env);
203 }
204 
CheckGattsRemoveService(napi_env env,napi_callback_info info,std::shared_ptr<GattServer> & outServer,UUID & outUuid)205 static napi_status CheckGattsRemoveService(napi_env env, napi_callback_info info,
206     std::shared_ptr<GattServer> &outServer, UUID &outUuid)
207 {
208     size_t argc = 1;
209     napi_value argv[1] = {nullptr};
210     napi_value thisVar = nullptr;
211     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
212     NAPI_BT_RETURN_IF(argc != 1, "Requires 1 arguments.", napi_invalid_arg);
213 
214     std::string uuid {};
215     NAPI_BT_CALL_RETURN(NapiParseUuid(env, argv[0], uuid));
216 
217     NapiGattServer *gattServer = NapiGetGattServer(env, thisVar);
218     NAPI_BT_RETURN_IF(gattServer == nullptr, "gattServer is nullptr.", napi_invalid_arg);
219     outServer = gattServer->GetServer();
220     outUuid = UUID::FromString(uuid);
221     return napi_ok;
222 }
223 
RemoveGattService(napi_env env,napi_callback_info info)224 napi_value NapiGattServer::RemoveGattService(napi_env env, napi_callback_info info)
225 {
226     HILOGI("enter");
227     std::shared_ptr<GattServer> server {nullptr};
228     UUID serviceUuid;
229     auto status = CheckGattsRemoveService(env, info, server, serviceUuid);
230     NAPI_BT_ASSERT_RETURN_FALSE(env, (status == napi_ok && server != nullptr), BT_ERR_INVALID_PARAM);
231 
232     int ret = BT_ERR_INTERNAL_ERROR;
233     auto primaryService = server->GetService(serviceUuid, true);
234     if (primaryService.has_value()) {
235         ret = server->RemoveGattService(*primaryService);
236         NAPI_BT_ASSERT_RETURN_FALSE(env, ret == BT_NO_ERROR, ret);
237     }
238     auto secondService = server->GetService(serviceUuid, false);
239     if (secondService.has_value()) {
240         ret = server->RemoveGattService(*secondService);
241         NAPI_BT_ASSERT_RETURN_FALSE(env, ret == BT_NO_ERROR, ret);
242     }
243     NAPI_BT_ASSERT_RETURN_FALSE(env, (primaryService.has_value() || secondService.has_value()), BT_ERR_INVALID_PARAM);
244     return NapiGetBooleanRet(env, ret == BT_NO_ERROR);
245 }
246 
CheckGattsSendRsp(napi_env env,napi_callback_info info,std::shared_ptr<GattServer> & outServer,NapiGattsServerResponse & outRsp)247 static napi_status CheckGattsSendRsp(napi_env env, napi_callback_info info, std::shared_ptr<GattServer> &outServer,
248     NapiGattsServerResponse &outRsp)
249 {
250     size_t argc = 1;
251     napi_value argv[1] = {nullptr};
252     napi_value thisVar = nullptr;
253     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
254     NAPI_BT_RETURN_IF(argc != 1, "Requires 1 arguments.", napi_invalid_arg);
255 
256     NapiGattsServerResponse rsp;
257     NAPI_BT_CALL_RETURN(NapiParseGattsServerResponse(env, argv[0], rsp));
258 
259     NapiGattServer *gattServer = NapiGetGattServer(env, thisVar);
260     NAPI_BT_RETURN_IF(gattServer == nullptr, "gattServer is nullptr.", napi_invalid_arg);
261     outServer = gattServer->GetServer();
262     outRsp = std::move(rsp);
263     return napi_ok;
264 }
265 
SendResponse(napi_env env,napi_callback_info info)266 napi_value NapiGattServer::SendResponse(napi_env env, napi_callback_info info)
267 {
268     HILOGI("enter");
269     std::shared_ptr<GattServer> server {nullptr};
270     NapiGattsServerResponse rsp;
271     auto status = CheckGattsSendRsp(env, info, server, rsp);
272     NAPI_BT_ASSERT_RETURN_FALSE(env, (status == napi_ok && server != nullptr), BT_ERR_INVALID_PARAM);
273 
274     BluetoothRemoteDevice remoteDevice(rsp.deviceId, BTTransport::ADAPTER_BLE);
275     HILOGI("Remote device address: %{public}s", GET_ENCRYPT_ADDR(remoteDevice));
276     int ret = server->SendResponse(remoteDevice, rsp.transId, rsp.status, rsp.offset, rsp.value.data(),
277         static_cast<int>(rsp.value.size()));
278     NAPI_BT_ASSERT_RETURN_FALSE(env, ret == BT_NO_ERROR, ret);
279     return NapiGetBooleanTrue(env);
280 }
281 
GetGattCharacteristic(const std::shared_ptr<GattServer> & server,const UUID & serviceUuid,const UUID & characterUuid)282 static GattCharacteristic *GetGattCharacteristic(const std::shared_ptr<GattServer> &server, const UUID &serviceUuid,
283     const UUID &characterUuid)
284 {
285     auto service = server->GetService(serviceUuid, true);
286     if (!service.has_value()) {
287         service = server->GetService(serviceUuid, false);
288     }
289     if (!service.has_value()) {
290         HILOGE("not found service uuid: %{public}s", serviceUuid.ToString().c_str());
291         return nullptr;
292     }
293     GattCharacteristic *character = service.value().get().GetCharacteristic(characterUuid);
294     return character;
295 }
296 
297 #ifdef BLUETOOTH_API_SINCE_10
CheckNotifyCharacteristicChangedEx(napi_env env,napi_callback_info info,NapiGattServer ** outServer,std::string & outDeviceId,NapiNotifyCharacteristic & outCharacter)298 static napi_status CheckNotifyCharacteristicChangedEx(napi_env env, napi_callback_info info,
299     NapiGattServer **outServer, std::string &outDeviceId, NapiNotifyCharacteristic &outCharacter)
300 {
301     size_t argc = ARGS_SIZE_THREE;
302     napi_value argv[ARGS_SIZE_THREE] = {0};
303     napi_value thisVar = nullptr;
304     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
305     NAPI_BT_RETURN_IF(argc != ARGS_SIZE_TWO && argc != ARGS_SIZE_THREE, "Requires 2 or 3 arguments.", napi_invalid_arg);
306 
307     std::string deviceId {};
308     NapiNotifyCharacteristic character;
309     NAPI_BT_CALL_RETURN(NapiParseBdAddr(env, argv[PARAM0], deviceId));
310     NAPI_BT_CALL_RETURN(NapiParseNotifyCharacteristic(env, argv[PARAM1], character));
311 
312     NapiGattServer *gattServer = NapiGetGattServer(env, thisVar);
313     NAPI_BT_RETURN_IF(gattServer == nullptr || outServer ==nullptr, "gattServer is nullptr.", napi_invalid_arg);
314     *outServer = gattServer;
315     outDeviceId = std::move(deviceId);
316     outCharacter = std::move(character);
317     return napi_ok;
318 }
319 
NotifyCharacteristicChangedEx(napi_env env,napi_callback_info info)320 napi_value NapiGattServer::NotifyCharacteristicChangedEx(napi_env env, napi_callback_info info)
321 {
322     HILOGI("enter");
323     NapiGattServer* napiServer = nullptr;
324     std::string deviceId {};
325     NapiNotifyCharacteristic notifyCharacter;
326     auto status = CheckNotifyCharacteristicChangedEx(env, info, &napiServer, deviceId, notifyCharacter);
327     NAPI_BT_ASSERT_RETURN_FALSE(env, (status == napi_ok && napiServer && napiServer->GetServer()),
328         BT_ERR_INVALID_PARAM);
329 
330     auto func = [server = napiServer->GetServer(), notifyCharacter, deviceId]() {
331         int ret = BT_ERR_INTERNAL_ERROR;
332         auto character = GetGattCharacteristic(server, notifyCharacter.serviceUuid, notifyCharacter.characterUuid);
333         if (character == nullptr) {
334             HILOGI("character is null!");
335             return NapiAsyncWorkRet(ret);
336         }
337         character->SetValue(notifyCharacter.characterValue.data(), notifyCharacter.characterValue.size());
338         BluetoothRemoteDevice remoteDevice(deviceId, BTTransport::ADAPTER_BLE);
339         ret = server->NotifyCharacteristicChanged(remoteDevice, *character, notifyCharacter.confirm);
340         return NapiAsyncWorkRet(ret);
341     };
342     auto asyncWork = NapiAsyncWorkFactory::CreateAsyncWork(env, info, func, ASYNC_WORK_NEED_CALLBACK);
343     NAPI_BT_ASSERT_RETURN_UNDEF(env, asyncWork, BT_ERR_INTERNAL_ERROR);
344 
345     bool success = napiServer->GetCallback()->asyncWorkMap_.TryPush(NapiAsyncType::GATT_SERVER_NOTIFY_CHARACTERISTIC,
346         asyncWork);
347     NAPI_BT_ASSERT_RETURN_UNDEF(env, success, BT_ERR_INTERNAL_ERROR);
348 
349     asyncWork->Run();
350     return asyncWork->GetRet();
351 }
352 #else
CheckGattsNotify(napi_env env,napi_callback_info info,std::shared_ptr<GattServer> & outServer,std::string & outDeviceId,NapiNotifyCharacteristic & outCharacter)353 static napi_status CheckGattsNotify(napi_env env, napi_callback_info info, std::shared_ptr<GattServer> &outServer,
354     std::string &outDeviceId, NapiNotifyCharacteristic &outCharacter)
355 {
356     size_t argc = ARGS_SIZE_TWO;
357     napi_value argv[ARGS_SIZE_TWO] = {nullptr};
358     napi_value thisVar = nullptr;
359     NAPI_BT_CALL_RETURN(napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
360     NAPI_BT_RETURN_IF(argc != ARGS_SIZE_TWO, "Requires 2 arguments.", napi_invalid_arg);
361 
362     std::string deviceId {};
363     NapiNotifyCharacteristic character;
364     NAPI_BT_CALL_RETURN(NapiParseBdAddr(env, argv[PARAM0], deviceId));
365     NAPI_BT_CALL_RETURN(NapiParseNotifyCharacteristic(env, argv[PARAM1], character));
366 
367     NapiGattServer *gattServer = NapiGetGattServer(env, thisVar);
368     NAPI_BT_RETURN_IF(gattServer == nullptr, "gattServer is nullptr.", napi_invalid_arg);
369     outServer = gattServer->GetServer();
370     outDeviceId = std::move(deviceId);
371     outCharacter = std::move(character);
372     return napi_ok;
373 }
374 
NotifyCharacteristicChanged(napi_env env,napi_callback_info info)375 napi_value NapiGattServer::NotifyCharacteristicChanged(napi_env env, napi_callback_info info)
376 {
377     HILOGI("enter");
378     std::shared_ptr<GattServer> server {nullptr};
379     std::string deviceId {};
380     NapiNotifyCharacteristic notifyCharacter;
381     auto status = CheckGattsNotify(env, info, server, deviceId, notifyCharacter);
382     NAPI_BT_ASSERT_RETURN_FALSE(env, (status == napi_ok && server != nullptr), BT_ERR_INVALID_PARAM);
383 
384     auto character = GetGattCharacteristic(server, notifyCharacter.serviceUuid, notifyCharacter.characterUuid);
385     NAPI_BT_ASSERT_RETURN_FALSE(env, character != nullptr, BT_ERR_INVALID_PARAM);
386     character->SetValue(notifyCharacter.characterValue.data(), notifyCharacter.characterValue.size());
387 
388     BluetoothRemoteDevice remoteDevice(deviceId, BTTransport::ADAPTER_BLE);
389     int ret = server->NotifyCharacteristicChanged(remoteDevice, *character, notifyCharacter.confirm);
390     NAPI_BT_ASSERT_RETURN_FALSE(env, ret == BT_NO_ERROR, ret);
391     return NapiGetBooleanTrue(env);
392 }
393 #endif
394 } // namespace Bluetooth
395 } // namespace OHOS
396