8d0bc02a7d908046682e06647a53990cf9a3d193
[platform/core/api/webapi-plugins.git] / src / bluetooth / bluetooth_gatt_server_service.cc
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include <string>
18
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"
24
25 #include "common/logger.h"
26 #include "common/platform_result.h"
27 #include "common/tools.h"
28
29 using namespace extension::bluetooth::util;
30 using common::PlatformResult;
31 using common::ErrorCode;
32
33 namespace extension {
34 namespace bluetooth {
35
36 namespace {
37 const std::string kUuid = "uuid";
38 const std::string kServiceUuid = "serviceUuid";
39 const std::string kIsPrimary = "isPrimary";
40 const std::string kCharacteristics = "characteristics";
41
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";
58
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";
69
70 int GetPermissionsInt(const picojson::value& permissions) {
71   ScopeLogger("permissions: %s", permissions.serialize().c_str());
72
73   int ret = 0;
74   if (permissions.get(kReadPermission).get<bool>()) {
75     ret |= BT_GATT_PERMISSION_READ;
76   }
77   if (permissions.get(kWritePermission).get<bool>()) {
78     ret |= BT_GATT_PERMISSION_WRITE;
79   }
80   if (permissions.get(kEncryptedReadPermission).get<bool>()) {
81     ret |= BT_GATT_PERMISSION_ENCRYPT_READ;
82   }
83   if (permissions.get(kEncryptedWritePermission).get<bool>()) {
84     ret |= BT_GATT_PERMISSION_ENCRYPT_WRITE;
85   }
86   if (permissions.get(kEncryptedSignedReadPermission).get<bool>()) {
87     ret |= BT_GATT_PERMISSION_ENCRYPT_AUTHENTICATED_READ;
88   }
89   if (permissions.get(kEncryptedSignedWritePermission).get<bool>()) {
90     ret |= BT_GATT_PERMISSION_ENCRYPT_AUTHENTICATED_WRITE;
91   }
92
93   LoggerD("Permissions: %x", static_cast<unsigned int>(ret));
94   return ret;
95 }
96
97 int GetPropertiesInt(const picojson::value& properties) {
98   ScopeLogger("properties: %s", properties.serialize().c_str());
99
100   int ret = 0;
101   if (properties.get(kIsBroadcast).get<bool>()) {
102     ret |= BT_GATT_PROPERTY_BROADCAST;
103   }
104   if (properties.get(kIsReadable).get<bool>()) {
105     ret |= BT_GATT_PROPERTY_READ;
106   }
107   if (properties.get(kIsWriteNoResponse).get<bool>()) {
108     ret |= BT_GATT_PROPERTY_WRITE_WITHOUT_RESPONSE;
109   }
110   if (properties.get(kIsWritable).get<bool>()) {
111     ret |= BT_GATT_PROPERTY_WRITE;
112   }
113   if (properties.get(kIsNotify).get<bool>()) {
114     ret |= BT_GATT_PROPERTY_NOTIFY;
115   }
116   if (properties.get(kIsIndication).get<bool>()) {
117     ret |= BT_GATT_PROPERTY_INDICATE;
118   }
119   if (properties.get(kIsSignedWrite).get<bool>()) {
120     ret |= BT_GATT_PROPERTY_AUTHENTICATED_SIGNED_WRITES;
121   }
122   if (properties.get(kHasExtendedProperties).get<bool>()) {
123     ret |= BT_GATT_PROPERTY_EXTENDED_PROPERTIES;
124   }
125
126   LoggerD("Properties: %x", static_cast<unsigned int>(ret));
127   return ret;
128 }
129
130 }  // namespace
131
132 bool BluetoothGATTServerService::DestroyService(int total, int index, bt_gatt_h handle,
133                                                 void* user_data) {
134   ScopeLogger("total: %d, index: %d, handle: %p", total, index, handle);
135
136   /*
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)
140    * recursively.
141    */
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));
145   }
146   LoggerD("bt_gatt_service_destroy(): success");
147
148   return true;
149 }
150
151 bool BluetoothGATTServerService::DestroyCharacteristic(int total, int index, bt_gatt_h handle,
152                                                        void* user_data) {
153   ScopeLogger("total: %d, index: %d, handle: %p", total, index, handle);
154
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));
158   }
159   LoggerD("bt_gatt_characteristic_destroy(): success");
160
161   return true;
162 }
163
164 bool BluetoothGATTServerService::DestroyDescriptor(int total, int index, bt_gatt_h handle,
165                                                    void* user_data) {
166   ScopeLogger("total: %d, index: %d, handle: %p", total, index, handle);
167
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));
171   }
172   LoggerD("bt_gatt_descriptor_destroy(): success");
173
174   return true;
175 }
176
177 BluetoothGATTServerService::BluetoothGATTServerService(BluetoothInstance& instance)
178     : instance_{instance}, rw_request_callback_data_{instance, callback_names_} {
179   ScopeLogger();
180 }
181
182 BluetoothGATTServerService::~BluetoothGATTServerService() {
183   ScopeLogger();
184 }
185
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());
190
191   /*
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.
195    */
196
197   for (const auto& descriptor_init_data : descriptors_init) {
198     const auto& uuid_str = descriptor_init_data.get(kUuid).get<std::string>();
199     /*
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.
202      *
203      * We assume, UUID::create() returns a valid object, because the input is valid.
204      */
205     auto uuid = UUID::create(uuid_str);
206     int permissions = GetPermissionsInt(descriptor_init_data);
207     bt_gatt_h descriptor_handle = nullptr;
208
209     int ret = bt_gatt_descriptor_create(uuid->uuid_128_bit.c_str(), permissions, nullptr, 0,
210                                         &descriptor_handle);
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");
214     }
215     LoggerD("bt_gatt_descriptor_create(): success");
216
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");
223     }
224     LoggerD("bt_gatt_characteristic_add_descriptor(): success");
225
226     const auto _id = static_cast<int>(descriptor_init_data.get(kId).get<double>());
227     new_gatt_objects.push_back({_id, descriptor_handle});
228   }
229
230   return common::PlatformResult();
231 }
232
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());
237
238   /*
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.
242    */
243
244   for (const auto& characteristic_init_data : characteristics_init) {
245     const auto& uuid_str = characteristic_init_data.get(kUuid).get<std::string>();
246     /*
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.
249      *
250      * We assume, UUID::create() returns a valid object, because the input is valid.
251      */
252     auto uuid = UUID::create(uuid_str);
253
254     int permissions = GetPermissionsInt(characteristic_init_data);
255     int properties = GetPropertiesInt(characteristic_init_data);
256     bt_gatt_h characteristic_handle = nullptr;
257
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");
263     }
264     LoggerD("bt_gatt_characteristic_create(): success");
265
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);
269       if (!result) {
270         DestroyCharacteristic(0, 0, characteristic_handle, nullptr);
271         return result;
272       }
273     }
274
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");
280     }
281     LoggerD("bt_gatt_service_add_characteristic(): success");
282
283     const auto _id = static_cast<int>(characteristic_init_data.get(kId).get<double>());
284     new_gatt_objects.push_back({_id, characteristic_handle});
285   }
286
287   return common::PlatformResult();
288 }
289
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());
294
295   /*
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.
299    */
300
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);
304     if (!result) {
305       LoggerE("Failed to create included service");
306       return result;
307     }
308
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");
315     }
316     LoggerD("bt_gatt_service_add_included_service(): success");
317
318     const auto _id = static_cast<int>(service_init_data.get(kId).get<double>());
319     new_gatt_objects.push_back({_id, parent_service_handle});
320   }
321
322   return common::PlatformResult();
323 }
324
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());
329   /*
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.
333    */
334
335   const auto& uuid_str = service_init.get(kServiceUuid).get<std::string>();
336   /*
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.
339    *
340    * We assume, UUID::create() returns a valid object, because the input is valid.
341    */
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;
347
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");
352   }
353   LoggerD("bt_gatt_service_create(): success");
354
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);
358     if (!result) {
359       DestroyService(0, 0, service_handle, nullptr);
360       return result;
361     }
362   }
363
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);
367     if (!result) {
368       DestroyService(0, 0, service_handle, nullptr);
369       return result;
370     }
371   }
372
373   const auto _id = static_cast<int>(service_init.get(kId).get<double>());
374   new_gatt_objects.push_back({_id, service_handle});
375
376   *new_service_handle = service_handle;
377
378   return common::PlatformResult();
379 }
380
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) {
384   ScopeLogger();
385
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");
390   }
391
392   gatt_objects_.insert(new_gatt_objects.begin(), new_gatt_objects.end());
393
394   return common::PlatformResult();
395 }
396
397 common::PlatformResult BluetoothGATTServerService::UnregisterService(const picojson::value& args,
398                                                                      bt_gatt_server_h server) {
399   ScopeLogger();
400
401   auto _id = static_cast<int>(args.get(kId).get<double>());
402   LoggerD("Unregistering service with _id: %d", _id);
403
404   auto service_handle = gatt_objects_[_id];
405
406   /*
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).
412    */
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");
417   }
418   LoggerD("bt_gatt_server_unregister_service(): SUCCESS");
419
420   gatt_objects_.erase(_id);
421
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>());
425
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);
430   }
431
432   return common::PlatformResult{};
433 }
434
435 PlatformResult BluetoothGATTServerService::SetReadValueRequestCallback(
436     const picojson::value& args) {
437   ScopeLogger();
438
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);
441
442   auto gatt_handle = gatt_objects_[_id];
443   callback_names_[gatt_handle] = "ReadValueRequestCallback_" + std::to_string(_id);
444
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);
451
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");
455
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);
466         });
467   };
468
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");
475   }
476
477   LoggerD("bt_gatt_server_set_read_value_requested_cb(): SUCCESS");
478   return common::PlatformResult{};
479 }
480
481 PlatformResult BluetoothGATTServerService::SendResponse(const picojson::value& args) {
482   ScopeLogger();
483
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>());
491
492   std::unique_ptr<char[]> value{nullptr};
493   int value_size = 0;
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>());
500     }
501   } else {
502     LoggerD("No data!");
503   }
504
505   LoggerD(
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);
509
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");
515   }
516   LoggerD("bt_gatt_server_send_response(): SUCCESS");
517
518   return common::PlatformResult{};
519 }
520
521 }  // namespace bluetooth
522 }  // namespace extension