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