2 * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include "bluetooth/bluetooth_gatt_server.h"
20 #include "bluetooth/bluetooth_gatt_server_service.h"
21 #include "bluetooth/bluetooth_instance.h"
22 #include "bluetooth/bluetooth_util.h"
23 #include "bluetooth/uuid.h"
25 #include "common/logger.h"
26 #include "common/platform_result.h"
27 #include "common/tools.h"
29 using namespace extension::bluetooth::util;
30 using common::PlatformResult;
31 using common::ErrorCode;
37 const std::string kUuid = "uuid";
38 const std::string kServiceUuid = "serviceUuid";
39 const std::string kIsPrimary = "isPrimary";
40 const std::string kCharacteristics = "characteristics";
42 const std::string kServices = "services";
43 const std::string kDescriptors = "descriptors";
44 const std::string kIsBroadcast = "isBroadcast";
45 const std::string kHasExtendedProperties = "hasExtendedProperties";
46 const std::string kIsNotify = "isNotify";
47 const std::string kIsIndication = "isIndication";
48 const std::string kIsReadable = "isReadable";
49 const std::string kIsSignedWrite = "isSignedWrite";
50 const std::string kIsWritable = "isWritable";
51 const std::string kIsWriteNoResponse = "isWriteNoResponse";
52 const std::string kReadPermission = "readPermission";
53 const std::string kWritePermission = "writePermission";
54 const std::string kEncryptedReadPermission = "encryptedReadPermission";
55 const std::string kEncryptedWritePermission = "encryptedWritePermission";
56 const std::string kEncryptedSignedReadPermission = "encryptedSignedReadPermission";
57 const std::string kEncryptedSignedWritePermission = "encryptedSignedWritePermission";
59 const std::string kId = "_id";
60 const std::string kIdsToRemoveFromNativeLayer = "idsToRemoveFromNativeLayer";
61 const std::string kClientAddress = "clientAddress";
62 const std::string kRequestId = "requestId";
63 const std::string kOffset = "offset";
64 const std::string kRequestType = "requestType";
65 const std::string kReadRequestType = "readRequestType";
66 const std::string kWriteRequestType = "writeRequestType";
67 const std::string kStatusCode = "statusCode";
68 const std::string kData = "data";
70 int GetPermissionsInt(const picojson::value& permissions) {
71 ScopeLogger("permissions: %s", permissions.serialize().c_str());
74 if (permissions.get(kReadPermission).get<bool>()) {
75 ret |= BT_GATT_PERMISSION_READ;
77 if (permissions.get(kWritePermission).get<bool>()) {
78 ret |= BT_GATT_PERMISSION_WRITE;
80 if (permissions.get(kEncryptedReadPermission).get<bool>()) {
81 ret |= BT_GATT_PERMISSION_ENCRYPT_READ;
83 if (permissions.get(kEncryptedWritePermission).get<bool>()) {
84 ret |= BT_GATT_PERMISSION_ENCRYPT_WRITE;
86 if (permissions.get(kEncryptedSignedReadPermission).get<bool>()) {
87 ret |= BT_GATT_PERMISSION_ENCRYPT_AUTHENTICATED_READ;
89 if (permissions.get(kEncryptedSignedWritePermission).get<bool>()) {
90 ret |= BT_GATT_PERMISSION_ENCRYPT_AUTHENTICATED_WRITE;
93 LoggerD("Permissions: %x", static_cast<unsigned int>(ret));
97 int GetPropertiesInt(const picojson::value& properties) {
98 ScopeLogger("properties: %s", properties.serialize().c_str());
101 if (properties.get(kIsBroadcast).get<bool>()) {
102 ret |= BT_GATT_PROPERTY_BROADCAST;
104 if (properties.get(kIsReadable).get<bool>()) {
105 ret |= BT_GATT_PROPERTY_READ;
107 if (properties.get(kIsWriteNoResponse).get<bool>()) {
108 ret |= BT_GATT_PROPERTY_WRITE_WITHOUT_RESPONSE;
110 if (properties.get(kIsWritable).get<bool>()) {
111 ret |= BT_GATT_PROPERTY_WRITE;
113 if (properties.get(kIsNotify).get<bool>()) {
114 ret |= BT_GATT_PROPERTY_NOTIFY;
116 if (properties.get(kIsIndication).get<bool>()) {
117 ret |= BT_GATT_PROPERTY_INDICATE;
119 if (properties.get(kIsSignedWrite).get<bool>()) {
120 ret |= BT_GATT_PROPERTY_AUTHENTICATED_SIGNED_WRITES;
122 if (properties.get(kHasExtendedProperties).get<bool>()) {
123 ret |= BT_GATT_PROPERTY_EXTENDED_PROPERTIES;
126 LoggerD("Properties: %x", static_cast<unsigned int>(ret));
132 bool BluetoothGATTServerService::DestroyService(int total, int index, bt_gatt_h handle,
134 ScopeLogger("total: %d, index: %d, handle: %p", total, index, handle);
137 * Undocumented behavior of native Bluetooth API:
138 * bt_gatt_service_destroy() destroys not only the service, but also all
139 * its components (included services, characteristics, descriptors)
142 auto ret = bt_gatt_service_destroy(handle);
143 if (BT_ERROR_NONE != ret) {
144 LoggerE("bt_gatt_service_destroy(): %d (%s)", ret, get_error_message(ret));
146 LoggerD("bt_gatt_service_destroy(): success");
151 bool BluetoothGATTServerService::DestroyCharacteristic(int total, int index, bt_gatt_h handle,
153 ScopeLogger("total: %d, index: %d, handle: %p", total, index, handle);
155 auto ret = bt_gatt_characteristic_destroy(handle);
156 if (BT_ERROR_NONE != ret) {
157 LoggerE("bt_gatt_characteristic_destroy(): %d (%s)", ret, get_error_message(ret));
159 LoggerD("bt_gatt_characteristic_destroy(): success");
164 bool BluetoothGATTServerService::DestroyDescriptor(int total, int index, bt_gatt_h handle,
166 ScopeLogger("total: %d, index: %d, handle: %p", total, index, handle);
168 auto ret = bt_gatt_descriptor_destroy(handle);
169 if (BT_ERROR_NONE != ret) {
170 LoggerE("bt_gatt_descriptor_destroy(): %d (%s)", ret, get_error_message(ret));
172 LoggerD("bt_gatt_descriptor_destroy(): success");
177 BluetoothGATTServerService::BluetoothGATTServerService(BluetoothInstance& instance)
178 : instance_{instance}, rw_request_callback_data_{instance, callback_names_} {
182 BluetoothGATTServerService::~BluetoothGATTServerService() {
186 common::PlatformResult BluetoothGATTServerService::AddDescriptors(
187 const picojson::array& descriptors_init, bt_gatt_h characteristic_handle,
188 std::vector<std::pair<int, bt_gatt_h>>& new_gatt_objects) {
189 ScopeLogger("descriptors_init length: %zu", descriptors_init.size());
192 * This function expects valid input.
193 * If it gets descriptors missing any: uuid, permission,
194 * or with one of these with a wrong type, the application will crash.
197 for (const auto& descriptor_init_data : descriptors_init) {
198 const auto& uuid_str = descriptor_init_data.get(kUuid).get<std::string>();
200 * Native APIs don't support 32-bit UUIDs. We convert any UUID to its 128-bit
201 * form to assure, it will be accepted by the native API.
203 * We assume, UUID::create() returns a valid object, because the input is valid.
205 auto uuid = UUID::create(uuid_str);
206 int permissions = GetPermissionsInt(descriptor_init_data);
207 bt_gatt_h descriptor_handle = nullptr;
209 int ret = bt_gatt_descriptor_create(uuid->uuid_128_bit.c_str(), permissions, nullptr, 0,
211 if (BT_ERROR_NONE != ret) {
212 LoggerE("bt_gatt_descriptor_create() failed: %d (%s)", ret, get_error_message(ret));
213 return BluetoothErrorToPlatformResult(ret, "Failed to create a descriptor");
215 LoggerD("bt_gatt_descriptor_create(): success");
217 ret = bt_gatt_characteristic_add_descriptor(characteristic_handle, descriptor_handle);
218 if (BT_ERROR_NONE != ret) {
219 LoggerE("bt_gatt_characteristic_add_descriptor() failed: %d (%s)", ret,
220 get_error_message(ret));
221 DestroyDescriptor(0, 0, descriptor_handle, nullptr);
222 return BluetoothErrorToPlatformResult(ret, "Failed to add descriptor to characteristic");
224 LoggerD("bt_gatt_characteristic_add_descriptor(): success");
226 const auto _id = static_cast<int>(descriptor_init_data.get(kId).get<double>());
227 new_gatt_objects.push_back({_id, descriptor_handle});
230 return common::PlatformResult();
233 common::PlatformResult BluetoothGATTServerService::AddCharacteristics(
234 const picojson::array& characteristics_init, bt_gatt_h service_handle,
235 std::vector<std::pair<int, bt_gatt_h>>& new_gatt_objects) {
236 ScopeLogger("characteristics_init length: %zu", characteristics_init.size());
239 * This function expects valid input.
240 * If it gets characteristics missing any: uuid, permission, property,
241 * or with any of these with a wrong type, the application will crash.
244 for (const auto& characteristic_init_data : characteristics_init) {
245 const auto& uuid_str = characteristic_init_data.get(kUuid).get<std::string>();
247 * Native APIs don't support 32-bit UUIDs. We convert any UUID to its 128-bit
248 * form to assure, it will be accepted by the native API.
250 * We assume, UUID::create() returns a valid object, because the input is valid.
252 auto uuid = UUID::create(uuid_str);
254 int permissions = GetPermissionsInt(characteristic_init_data);
255 int properties = GetPropertiesInt(characteristic_init_data);
256 bt_gatt_h characteristic_handle = nullptr;
258 int ret = bt_gatt_characteristic_create(uuid->uuid_128_bit.c_str(), permissions, properties,
259 nullptr, 0, &characteristic_handle);
260 if (BT_ERROR_NONE != ret) {
261 LoggerE("bt_gatt_characteristic_create() failed: %d (%s)", ret, get_error_message(ret));
262 return BluetoothErrorToPlatformResult(ret, "Failed to create a characteristic");
264 LoggerD("bt_gatt_characteristic_create(): success");
266 if (characteristic_init_data.get(kDescriptors).is<picojson::array>()) {
267 const auto& descriptors = characteristic_init_data.get(kDescriptors).get<picojson::array>();
268 auto result = AddDescriptors(descriptors, characteristic_handle, new_gatt_objects);
270 DestroyCharacteristic(0, 0, characteristic_handle, nullptr);
275 ret = bt_gatt_service_add_characteristic(service_handle, characteristic_handle);
276 if (BT_ERROR_NONE != ret) {
277 LoggerE("bt_gatt_service_add_characteristic() failed: %d (%s)", ret, get_error_message(ret));
278 DestroyCharacteristic(0, 0, characteristic_handle, nullptr);
279 return BluetoothErrorToPlatformResult(ret, "Failed to add a characteristic to a service");
281 LoggerD("bt_gatt_service_add_characteristic(): success");
283 const auto _id = static_cast<int>(characteristic_init_data.get(kId).get<double>());
284 new_gatt_objects.push_back({_id, characteristic_handle});
287 return common::PlatformResult();
290 common::PlatformResult BluetoothGATTServerService::AddIncludedServices(
291 const picojson::array& included_services_init, bt_gatt_h parent_service_handle,
292 std::vector<std::pair<int, bt_gatt_h>>& new_gatt_objects) {
293 ScopeLogger("included_services_init length: %zu", included_services_init.size());
296 * This function expects valid input.
297 * If it gets included_services missing a uuid
298 * or with any of these with a wrong type, the application will crash.
301 for (const auto& service_init_data : included_services_init) {
302 bt_gatt_h included_service_handle = nullptr;
303 auto result = CreateService(service_init_data, &included_service_handle, new_gatt_objects);
305 LoggerE("Failed to create included service");
309 int ret = bt_gatt_service_add_included_service(parent_service_handle, included_service_handle);
310 if (BT_ERROR_NONE != ret) {
311 LoggerE("bt_gatt_service_add_included_service() failed: %d (%s)", ret,
312 get_error_message(ret));
313 DestroyService(0, 0, included_service_handle, nullptr);
314 return BluetoothErrorToPlatformResult(ret, "Failed to add included service");
316 LoggerD("bt_gatt_service_add_included_service(): success");
318 const auto _id = static_cast<int>(service_init_data.get(kId).get<double>());
319 new_gatt_objects.push_back({_id, parent_service_handle});
322 return common::PlatformResult();
325 common::PlatformResult BluetoothGATTServerService::CreateService(
326 const picojson::value& service_init, bt_gatt_h* new_service_handle,
327 std::vector<std::pair<int, bt_gatt_h>>& new_gatt_objects) {
328 ScopeLogger("service_init: %s", service_init.serialize().c_str());
330 * This function expects valid input.
331 * If it gets service_init without any of the expected members or with a member of
332 * a wrong type, the application will crash.
335 const auto& uuid_str = service_init.get(kServiceUuid).get<std::string>();
337 * Native APIs don't support 32-bit UUIDs. We convert any UUID to its 128-bit
338 * form to assure, it will be accepted by the native API.
340 * We assume, UUID::create() returns a valid object, because the input is valid.
342 auto uuid = UUID::create(uuid_str);
343 bool primary = service_init.get(kIsPrimary).get<bool>();
344 bt_gatt_service_type_e type =
345 primary ? BT_GATT_SERVICE_TYPE_PRIMARY : BT_GATT_SERVICE_TYPE_SECONDARY;
346 bt_gatt_h service_handle = nullptr;
348 int err = bt_gatt_service_create(uuid->uuid_128_bit.c_str(), type, &service_handle);
349 if (BT_ERROR_NONE != err) {
350 LoggerE("bt_gatt_service_create error: %d (%s)", err, get_error_message(err));
351 return BluetoothErrorToPlatformResult(err, "Failed to create GATT service");
353 LoggerD("bt_gatt_service_create(): success");
355 if (service_init.get(kServices).is<picojson::array>()) {
356 const auto& services = service_init.get(kServices).get<picojson::array>();
357 auto result = AddIncludedServices(services, service_handle, new_gatt_objects);
359 DestroyService(0, 0, service_handle, nullptr);
364 if (service_init.get(kCharacteristics).is<picojson::array>()) {
365 const auto& characteristics = service_init.get(kCharacteristics).get<picojson::array>();
366 auto result = AddCharacteristics(characteristics, service_handle, new_gatt_objects);
368 DestroyService(0, 0, service_handle, nullptr);
373 const auto _id = static_cast<int>(service_init.get(kId).get<double>());
374 new_gatt_objects.push_back({_id, service_handle});
376 *new_service_handle = service_handle;
378 return common::PlatformResult();
381 common::PlatformResult BluetoothGATTServerService::RegisterService(
382 bt_gatt_h service_handle, bt_gatt_server_h server,
383 const std::vector<std::pair<int, bt_gatt_h>>& new_gatt_objects) {
386 int ret = bt_gatt_server_register_service(server, service_handle);
387 if (BT_ERROR_NONE != ret) {
388 LoggerE("bt_gatt_server_register_service() failed: %d (%s)", ret, get_error_message(ret));
389 return BluetoothErrorToPlatformResult(ret, "Failed to register GATT service");
392 gatt_objects_.insert(new_gatt_objects.begin(), new_gatt_objects.end());
394 return common::PlatformResult();
397 common::PlatformResult BluetoothGATTServerService::UnregisterService(const picojson::value& args,
398 bt_gatt_server_h server) {
401 auto _id = static_cast<int>(args.get(kId).get<double>());
402 LoggerD("Unregistering service with _id: %d", _id);
404 auto service_handle = gatt_objects_[_id];
407 * Undocumented behavior of native Bluetooth API:
408 * bt_gatt_server_unregister_service() not only unregisters the service,
409 * but also calls bt_gatt_destroy_service() on its handle, destroying
410 * the corresponding service object and all its components (included services,
411 * characteristics, descriptors).
413 auto ret = bt_gatt_server_unregister_service(server, service_handle);
414 if (BT_ERROR_NONE != ret) {
415 LoggerE("bt_gatt_server_unregister_service() failed: %d (%s)", ret, get_error_message(ret));
416 return BluetoothErrorToPlatformResult(ret, "Failed to unregister GATT service");
418 LoggerD("bt_gatt_server_unregister_service(): SUCCESS");
420 gatt_objects_.erase(_id);
422 auto ids_to_remove = args.get(kIdsToRemoveFromNativeLayer).get<picojson::array>();
423 for (const auto& to_remove : ids_to_remove) {
424 const auto id_to_remove = static_cast<int>(to_remove.get<double>());
426 auto handle_to_remove = gatt_objects_[id_to_remove];
427 LoggerD("Erasing gatt object with _id: %d", id_to_remove);
428 callback_names_.erase(handle_to_remove);
429 gatt_objects_.erase(id_to_remove);
432 return common::PlatformResult{};
435 PlatformResult BluetoothGATTServerService::SetReadValueRequestCallback(
436 const picojson::value& args) {
439 auto _id = static_cast<int>(args.get(kId).get<double>());
440 LoggerD("Setting read value request callback for a GATT entity with _id: %d", _id);
442 auto gatt_handle = gatt_objects_[_id];
443 callback_names_[gatt_handle] = "ReadValueRequestCallback_" + std::to_string(_id);
445 auto read_value_request_callback = [](const char* remote_address, int request_id,
446 bt_gatt_server_h server, bt_gatt_h gatt_handle, int offset,
447 void* user_data) -> void {
448 ScopeLogger("ReadValueRequestCallback called. remote_address: %s, request_id: %d, offset: %d",
449 remote_address, request_id, offset);
450 auto rw_callback_data = static_cast<ReadWriteRequestCallbackData*>(user_data);
452 rw_callback_data->instance_.GetWorker().add_job(
453 [remote_address, request_id, server, gatt_handle, offset, rw_callback_data] {
454 ScopeLogger("Async call: SetReadValueRequestCallback");
456 auto read_value_request = picojson::value{picojson::object{}};
457 auto& read_value_request_obj = read_value_request.get<picojson::object>();
458 read_value_request_obj[kClientAddress] = picojson::value{remote_address};
459 read_value_request_obj[kRequestId] = picojson::value{static_cast<double>(request_id)};
460 read_value_request_obj[kRequestType] = picojson::value{kReadRequestType};
461 read_value_request_obj[kOffset] = picojson::value{static_cast<double>(offset)};
462 const auto callback_name = rw_callback_data->callback_names_map_[gatt_handle];
463 LoggerD("Firing read value request event: %s: %s", callback_name.c_str(),
464 read_value_request.serialize().c_str());
465 rw_callback_data->instance_.FireEvent(callback_name, read_value_request);
469 auto ret = bt_gatt_server_set_read_value_requested_cb(gatt_handle, read_value_request_callback,
470 &rw_request_callback_data_);
471 if (BT_ERROR_NONE != ret) {
472 LoggerE("bt_gatt_server_set_read_value_requested_cb() failed: %d (%s)", ret,
473 get_error_message(ret));
474 return BluetoothErrorToPlatformResult(ret, "Failed to set read value request callback");
477 LoggerD("bt_gatt_server_set_read_value_requested_cb(): SUCCESS");
478 return common::PlatformResult{};
481 PlatformResult BluetoothGATTServerService::SendResponse(const picojson::value& args) {
484 auto _id = static_cast<int>(args.get(kId).get<double>());
485 auto request_id = static_cast<int>(args.get(kRequestId).get<double>());
486 auto request_type_str = args.get(kRequestType).get<std::string>();
487 auto request_type = (request_type_str == kReadRequestType) ? BT_GATT_REQUEST_TYPE_READ
488 : BT_GATT_REQUEST_TYPE_WRITE;
489 auto offset = static_cast<int>(args.get(kOffset).get<double>());
490 auto status_code = static_cast<int>(args.get(kStatusCode).get<double>());
492 std::unique_ptr<char[]> value{nullptr};
494 if (args.get(kData).is<picojson::array>()) {
495 auto value_octets = args.get(kData).get<picojson::array>();
496 value_size = value_octets.size();
497 value = std::make_unique<char[]>(value_size);
498 for (int i = 0; i < value_size; ++i) {
499 value[i] += static_cast<int>(value_octets[i].get<double>());
506 "Sending response: _id: %d, requestId: %d, requestType: %s, offset: %d, statusCode: %d, "
507 "value: [%s], value size: %d",
508 _id, request_id, request_type_str.c_str(), offset, status_code, value.get(), value_size);
510 auto ret = bt_gatt_server_send_response(request_id, request_type, offset, status_code,
511 value.get(), value_size);
512 if (BT_ERROR_NONE != ret) {
513 LoggerE("bt_gatt_server_send_response() failed: %d (%s)", ret, get_error_message(ret));
514 return BluetoothErrorToPlatformResult(ret, "Failed to send response");
516 LoggerD("bt_gatt_server_send_response(): SUCCESS");
518 return common::PlatformResult{};
521 } // namespace bluetooth
522 } // namespace extension