[Bluetooth] Stop server after unregistering last service
[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 kValue = "value";
64 const std::string kOffset = "offset";
65 const std::string kReplyRequired = "replyRequired";
66 const std::string kRequestType = "requestType";
67 const std::string kReadRequestType = "readRequestType";
68 const std::string kWriteRequestType = "writeRequestType";
69 const std::string kStatusCode = "statusCode";
70 const std::string kData = "data";
71 const std::string kReadCallback = "readCallback";
72 const std::string kWriteCallback = "writeCallback";
73 const std::string kNotifyId = "notifyId";
74 const std::string kOnNotificationFail = "onnotificationfail";
75 const std::string kOnNotificationFinish = "onnotificationfinish";
76 const std::string kOnNotificationSuccess = "onnotificationsuccess";
77 const std::string kType = "type";
78 const std::string kClient = "client";
79
80 int GetPermissionsInt(const picojson::value& permissions) {
81   ScopeLogger("permissions: %s", permissions.serialize().c_str());
82
83   int ret = 0;
84   if (permissions.get(kReadPermission).get<bool>()) {
85     ret |= BT_GATT_PERMISSION_READ;
86   }
87   if (permissions.get(kWritePermission).get<bool>()) {
88     ret |= BT_GATT_PERMISSION_WRITE;
89   }
90   if (permissions.get(kEncryptedReadPermission).get<bool>()) {
91     ret |= BT_GATT_PERMISSION_ENCRYPT_READ;
92   }
93   if (permissions.get(kEncryptedWritePermission).get<bool>()) {
94     ret |= BT_GATT_PERMISSION_ENCRYPT_WRITE;
95   }
96   if (permissions.get(kEncryptedSignedReadPermission).get<bool>()) {
97     ret |= BT_GATT_PERMISSION_ENCRYPT_AUTHENTICATED_READ;
98   }
99   if (permissions.get(kEncryptedSignedWritePermission).get<bool>()) {
100     ret |= BT_GATT_PERMISSION_ENCRYPT_AUTHENTICATED_WRITE;
101   }
102
103   LoggerD("Permissions: %x", static_cast<unsigned int>(ret));
104   return ret;
105 }
106
107 int GetPropertiesInt(const picojson::value& properties) {
108   ScopeLogger("properties: %s", properties.serialize().c_str());
109
110   int ret = 0;
111   if (properties.get(kIsBroadcast).get<bool>()) {
112     ret |= BT_GATT_PROPERTY_BROADCAST;
113   }
114   if (properties.get(kIsReadable).get<bool>()) {
115     ret |= BT_GATT_PROPERTY_READ;
116   }
117   if (properties.get(kIsWriteNoResponse).get<bool>()) {
118     ret |= BT_GATT_PROPERTY_WRITE_WITHOUT_RESPONSE;
119   }
120   if (properties.get(kIsWritable).get<bool>()) {
121     ret |= BT_GATT_PROPERTY_WRITE;
122   }
123   if (properties.get(kIsNotify).get<bool>()) {
124     ret |= BT_GATT_PROPERTY_NOTIFY;
125   }
126   if (properties.get(kIsIndication).get<bool>()) {
127     ret |= BT_GATT_PROPERTY_INDICATE;
128   }
129   if (properties.get(kIsSignedWrite).get<bool>()) {
130     ret |= BT_GATT_PROPERTY_AUTHENTICATED_SIGNED_WRITES;
131   }
132   if (properties.get(kHasExtendedProperties).get<bool>()) {
133     ret |= BT_GATT_PROPERTY_EXTENDED_PROPERTIES;
134   }
135
136   LoggerD("Properties: %x", static_cast<unsigned int>(ret));
137   return ret;
138 }
139
140 }  // namespace
141
142 bool BluetoothGATTServerService::DestroyService(int total, int index, bt_gatt_h handle,
143                                                 void* user_data) {
144   ScopeLogger("total: %d, index: %d, handle: %p", total, index, handle);
145
146   /*
147    * Undocumented behavior of native Bluetooth API:
148    * bt_gatt_service_destroy() destroys not only the service, but also all
149    * its components (included services, characteristics, descriptors)
150    * recursively.
151    */
152   auto ret = bt_gatt_service_destroy(handle);
153   if (BT_ERROR_NONE != ret) {
154     LoggerE("bt_gatt_service_destroy(): %d (%s)", ret, get_error_message(ret));
155   }
156   LoggerD("bt_gatt_service_destroy(): success");
157
158   return true;
159 }
160
161 bool BluetoothGATTServerService::DestroyCharacteristic(int total, int index, bt_gatt_h handle,
162                                                        void* user_data) {
163   ScopeLogger("total: %d, index: %d, handle: %p", total, index, handle);
164
165   auto ret = bt_gatt_characteristic_destroy(handle);
166   if (BT_ERROR_NONE != ret) {
167     LoggerE("bt_gatt_characteristic_destroy(): %d (%s)", ret, get_error_message(ret));
168   }
169   LoggerD("bt_gatt_characteristic_destroy(): success");
170
171   return true;
172 }
173
174 bool BluetoothGATTServerService::DestroyDescriptor(int total, int index, bt_gatt_h handle,
175                                                    void* user_data) {
176   ScopeLogger("total: %d, index: %d, handle: %p", total, index, handle);
177
178   auto ret = bt_gatt_descriptor_destroy(handle);
179   if (BT_ERROR_NONE != ret) {
180     LoggerE("bt_gatt_descriptor_destroy(): %d (%s)", ret, get_error_message(ret));
181   }
182   LoggerD("bt_gatt_descriptor_destroy(): success");
183
184   return true;
185 }
186
187 BluetoothGATTServerService::BluetoothGATTServerService(BluetoothInstance& instance)
188     : instance_{instance}, rw_request_callback_data_{instance, callback_names_} {
189   ScopeLogger();
190 }
191
192 BluetoothGATTServerService::~BluetoothGATTServerService() {
193   ScopeLogger();
194 }
195
196 common::PlatformResult BluetoothGATTServerService::AddDescriptors(
197     const picojson::array& descriptors_init, bt_gatt_h characteristic_handle,
198     std::vector<std::pair<int, bt_gatt_h>>& new_gatt_objects) {
199   ScopeLogger("descriptors_init length: %zu", descriptors_init.size());
200
201   /*
202    * This function expects valid input.
203    * If it gets descriptors missing any: uuid, permission,
204    * or with one of these with a wrong type, the application will crash.
205    */
206
207   for (const auto& descriptor_init_data : descriptors_init) {
208     const auto& uuid_str = descriptor_init_data.get(kUuid).get<std::string>();
209     /*
210      * Native APIs don't support 32-bit UUIDs. We convert any UUID to its 128-bit
211      * form to assure, it will be accepted by the native API.
212      *
213      * We assume, UUID::create() returns a valid object, because the input is valid.
214      */
215     auto uuid = UUID::create(uuid_str);
216     int permissions = GetPermissionsInt(descriptor_init_data);
217     bt_gatt_h descriptor_handle = nullptr;
218
219     int ret = bt_gatt_descriptor_create(uuid->uuid_128_bit.c_str(), permissions, nullptr, 0,
220                                         &descriptor_handle);
221     if (BT_ERROR_NONE != ret) {
222       LoggerE("bt_gatt_descriptor_create() failed: %d (%s)", ret, get_error_message(ret));
223       return BluetoothErrorToPlatformResult(ret, "Failed to create a descriptor");
224     }
225     LoggerD("bt_gatt_descriptor_create(): success");
226
227     ret = bt_gatt_characteristic_add_descriptor(characteristic_handle, descriptor_handle);
228     if (BT_ERROR_NONE != ret) {
229       LoggerE("bt_gatt_characteristic_add_descriptor() failed: %d (%s)", ret,
230               get_error_message(ret));
231       DestroyDescriptor(0, 0, descriptor_handle, nullptr);
232       return BluetoothErrorToPlatformResult(ret, "Failed to add descriptor to characteristic");
233     }
234     LoggerD("bt_gatt_characteristic_add_descriptor(): success");
235
236     const auto _id = static_cast<int>(descriptor_init_data.get(kId).get<double>());
237     new_gatt_objects.push_back({_id, descriptor_handle});
238   }
239
240   return common::PlatformResult();
241 }
242
243 common::PlatformResult BluetoothGATTServerService::AddCharacteristics(
244     const picojson::array& characteristics_init, bt_gatt_h service_handle,
245     std::vector<std::pair<int, bt_gatt_h>>& new_gatt_objects) {
246   ScopeLogger("characteristics_init length: %zu", characteristics_init.size());
247
248   /*
249    * This function expects valid input.
250    * If it gets characteristics missing any: uuid, permission, property,
251    * or with any of these with a wrong type, the application will crash.
252    */
253
254   for (const auto& characteristic_init_data : characteristics_init) {
255     const auto& uuid_str = characteristic_init_data.get(kUuid).get<std::string>();
256     /*
257      * Native APIs don't support 32-bit UUIDs. We convert any UUID to its 128-bit
258      * form to assure, it will be accepted by the native API.
259      *
260      * We assume, UUID::create() returns a valid object, because the input is valid.
261      */
262     auto uuid = UUID::create(uuid_str);
263
264     int permissions = GetPermissionsInt(characteristic_init_data);
265     int properties = GetPropertiesInt(characteristic_init_data);
266     bt_gatt_h characteristic_handle = nullptr;
267
268     int ret = bt_gatt_characteristic_create(uuid->uuid_128_bit.c_str(), permissions, properties,
269                                             nullptr, 0, &characteristic_handle);
270     if (BT_ERROR_NONE != ret) {
271       LoggerE("bt_gatt_characteristic_create() failed: %d (%s)", ret, get_error_message(ret));
272       return BluetoothErrorToPlatformResult(ret, "Failed to create a characteristic");
273     }
274     LoggerD("bt_gatt_characteristic_create(): success");
275
276     if (characteristic_init_data.get(kDescriptors).is<picojson::array>()) {
277       const auto& descriptors = characteristic_init_data.get(kDescriptors).get<picojson::array>();
278       auto result = AddDescriptors(descriptors, characteristic_handle, new_gatt_objects);
279       if (!result) {
280         DestroyCharacteristic(0, 0, characteristic_handle, nullptr);
281         return result;
282       }
283     }
284
285     ret = bt_gatt_service_add_characteristic(service_handle, characteristic_handle);
286     if (BT_ERROR_NONE != ret) {
287       LoggerE("bt_gatt_service_add_characteristic() failed: %d (%s)", ret, get_error_message(ret));
288       DestroyCharacteristic(0, 0, characteristic_handle, nullptr);
289       return BluetoothErrorToPlatformResult(ret, "Failed to add a characteristic to a service");
290     }
291     LoggerD("bt_gatt_service_add_characteristic(): success");
292
293     const auto _id = static_cast<int>(characteristic_init_data.get(kId).get<double>());
294     new_gatt_objects.push_back({_id, characteristic_handle});
295   }
296
297   return common::PlatformResult();
298 }
299
300 common::PlatformResult BluetoothGATTServerService::AddIncludedServices(
301     const picojson::array& included_services_init, bt_gatt_h parent_service_handle,
302     std::vector<std::pair<int, bt_gatt_h>>& new_gatt_objects) {
303   ScopeLogger("included_services_init length: %zu", included_services_init.size());
304
305   /*
306    * This function expects valid input.
307    * If it gets included_services missing a uuid
308    * or with any of these with a wrong type, the application will crash.
309    */
310
311   for (const auto& service_init_data : included_services_init) {
312     bt_gatt_h included_service_handle = nullptr;
313     auto result = CreateService(service_init_data, &included_service_handle, new_gatt_objects);
314     if (!result) {
315       LoggerE("Failed to create included service");
316       return result;
317     }
318
319     int ret = bt_gatt_service_add_included_service(parent_service_handle, included_service_handle);
320     if (BT_ERROR_NONE != ret) {
321       LoggerE("bt_gatt_service_add_included_service() failed: %d (%s)", ret,
322               get_error_message(ret));
323       DestroyService(0, 0, included_service_handle, nullptr);
324       return BluetoothErrorToPlatformResult(ret, "Failed to add included service");
325     }
326     LoggerD("bt_gatt_service_add_included_service(): success");
327
328     const auto _id = static_cast<int>(service_init_data.get(kId).get<double>());
329     new_gatt_objects.push_back({_id, parent_service_handle});
330   }
331
332   return common::PlatformResult();
333 }
334
335 common::PlatformResult BluetoothGATTServerService::CreateService(
336     const picojson::value& service_init, bt_gatt_h* new_service_handle,
337     std::vector<std::pair<int, bt_gatt_h>>& new_gatt_objects) {
338   ScopeLogger("service_init: %s", service_init.serialize().c_str());
339   /*
340    * This function expects valid input.
341    * If it gets service_init without any of the expected members or with a member of
342    * a wrong type, the application will crash.
343    */
344
345   const auto& uuid_str = service_init.get(kServiceUuid).get<std::string>();
346   /*
347    * Native APIs don't support 32-bit UUIDs. We convert any UUID to its 128-bit
348    * form to assure, it will be accepted by the native API.
349    *
350    * We assume, UUID::create() returns a valid object, because the input is valid.
351    */
352   auto uuid = UUID::create(uuid_str);
353   bool primary = service_init.get(kIsPrimary).get<bool>();
354   bt_gatt_service_type_e type =
355       primary ? BT_GATT_SERVICE_TYPE_PRIMARY : BT_GATT_SERVICE_TYPE_SECONDARY;
356   bt_gatt_h service_handle = nullptr;
357
358   int err = bt_gatt_service_create(uuid->uuid_128_bit.c_str(), type, &service_handle);
359   if (BT_ERROR_NONE != err) {
360     LoggerE("bt_gatt_service_create error: %d (%s)", err, get_error_message(err));
361     return BluetoothErrorToPlatformResult(err, "Failed to create GATT service");
362   }
363   LoggerD("bt_gatt_service_create(): success");
364
365   if (service_init.get(kServices).is<picojson::array>()) {
366     const auto& services = service_init.get(kServices).get<picojson::array>();
367     auto result = AddIncludedServices(services, service_handle, new_gatt_objects);
368     if (!result) {
369       DestroyService(0, 0, service_handle, nullptr);
370       return result;
371     }
372   }
373
374   if (service_init.get(kCharacteristics).is<picojson::array>()) {
375     const auto& characteristics = service_init.get(kCharacteristics).get<picojson::array>();
376     auto result = AddCharacteristics(characteristics, service_handle, new_gatt_objects);
377     if (!result) {
378       DestroyService(0, 0, service_handle, nullptr);
379       return result;
380     }
381   }
382
383   const auto _id = static_cast<int>(service_init.get(kId).get<double>());
384   new_gatt_objects.push_back({_id, service_handle});
385
386   *new_service_handle = service_handle;
387
388   return common::PlatformResult();
389 }
390
391 common::PlatformResult BluetoothGATTServerService::RegisterService(
392     bt_gatt_h service_handle, bt_gatt_server_h server,
393     const std::vector<std::pair<int, bt_gatt_h>>& new_gatt_objects) {
394   ScopeLogger();
395
396   int ret = bt_gatt_server_register_service(server, service_handle);
397   if (BT_ERROR_NONE != ret) {
398     LoggerE("bt_gatt_server_register_service() failed: %d (%s)", ret, get_error_message(ret));
399     return BluetoothErrorToPlatformResult(ret, "Failed to register GATT service");
400   }
401
402   gatt_objects_.insert(new_gatt_objects.begin(), new_gatt_objects.end());
403
404   return common::PlatformResult();
405 }
406
407 common::PlatformResult BluetoothGATTServerService::UnregisterService(const picojson::value& args,
408                                                                      bt_gatt_server_h server) {
409   ScopeLogger();
410
411   auto _id = static_cast<int>(args.get(kId).get<double>());
412   LoggerD("Unregistering service with _id: %d", _id);
413
414   auto service_handle = gatt_objects_[_id];
415
416   /*
417    * Undocumented behavior of native Bluetooth API:
418    * bt_gatt_server_unregister_service() not only unregisters the service,
419    * but also calls bt_gatt_destroy_service() on its handle, destroying
420    * the corresponding service object and all its components (included services,
421    * characteristics, descriptors).
422    */
423   auto ret = bt_gatt_server_unregister_service(server, service_handle);
424   if (BT_ERROR_NONE != ret) {
425     LoggerE("bt_gatt_server_unregister_service() failed: %d (%s)", ret, get_error_message(ret));
426     return BluetoothErrorToPlatformResult(ret, "Failed to unregister GATT service");
427   }
428   LoggerD("bt_gatt_server_unregister_service(): SUCCESS");
429
430   gatt_objects_.erase(_id);
431
432   auto ids_to_remove = args.get(kIdsToRemoveFromNativeLayer).get<picojson::array>();
433   for (const auto& to_remove : ids_to_remove) {
434     const auto id_to_remove = static_cast<int>(to_remove.get<double>());
435
436     auto handle_to_remove = gatt_objects_[id_to_remove];
437     LoggerD("Erasing gatt object with _id: %d", id_to_remove);
438     callback_names_.erase(std::make_pair(handle_to_remove, kReadCallback));
439     callback_names_.erase(std::make_pair(handle_to_remove, kWriteCallback));
440     gatt_objects_.erase(id_to_remove);
441   }
442
443   return common::PlatformResult{};
444 }
445
446 PlatformResult BluetoothGATTServerService::SetReadValueRequestCallback(
447     const picojson::value& args) {
448   ScopeLogger();
449
450   auto _id = static_cast<int>(args.get(kId).get<double>());
451   LoggerD("Setting read value request callback for a GATT entity with _id: %d", _id);
452
453   if (gatt_objects_.find(_id) == gatt_objects_.end()) {
454     LoggerE("No GATT handle for entity with _id [%d]", _id);
455     return common::PlatformResult{ErrorCode::ABORT_ERR, "Failed to set read value request callback"};
456   }
457
458   auto gatt_handle = gatt_objects_[_id];
459   callback_names_[std::make_pair(gatt_handle, kReadCallback)] =
460       "ReadValueRequestCallback_" + std::to_string(_id);
461
462   auto read_value_request_callback = [](const char* remote_address, int request_id,
463                                         bt_gatt_server_h server, bt_gatt_h gatt_handle, int offset,
464                                         void* user_data) -> void {
465     ScopeLogger("ReadValueRequestCallback called. remote_address: %s, request_id: %d, offset: %d",
466                 remote_address, request_id, offset);
467     auto rw_callback_data = static_cast<ReadWriteRequestCallbackData*>(user_data);
468
469     // We create a copy of this value, because remote_address pointer will be invalid
470     // when the job will be executed in the worker
471     auto remote_address_copy = std::string{remote_address};
472
473     rw_callback_data->instance_.GetWorker().add_job(
474         [remote_address_copy, request_id, server, gatt_handle, offset, rw_callback_data] {
475           ScopeLogger("Async call: SetReadValueRequestCallback");
476
477           auto read_value_request = picojson::value{picojson::object{}};
478           auto& read_value_request_obj = read_value_request.get<picojson::object>();
479           read_value_request_obj[kClientAddress] = picojson::value{remote_address_copy};
480           read_value_request_obj[kRequestId] = picojson::value{static_cast<double>(request_id)};
481           read_value_request_obj[kRequestType] = picojson::value{kReadRequestType};
482           read_value_request_obj[kOffset] = picojson::value{static_cast<double>(offset)};
483           const auto callback_name =
484               rw_callback_data->callback_names_map_[std::make_pair(gatt_handle, kReadCallback)];
485           LoggerD("Firing read value request event: %s: %s", callback_name.c_str(),
486                   read_value_request.serialize().c_str());
487           rw_callback_data->instance_.FireEvent(callback_name, read_value_request);
488         });
489   };
490
491   auto ret = bt_gatt_server_set_read_value_requested_cb(gatt_handle, read_value_request_callback,
492                                                         &rw_request_callback_data_);
493   if (BT_ERROR_NONE != ret) {
494     LoggerE("bt_gatt_server_set_read_value_requested_cb() failed: %d (%s)", ret,
495             get_error_message(ret));
496     return BluetoothErrorToPlatformResult(ret, "Failed to set read value request callback");
497   }
498
499   LoggerD("bt_gatt_server_set_read_value_requested_cb(): SUCCESS");
500   return common::PlatformResult{};
501 }
502
503 PlatformResult BluetoothGATTServerService::SetWriteValueRequestCallback(
504     const picojson::value& args) {
505   ScopeLogger();
506
507   auto _id = static_cast<int>(args.get(kId).get<double>());
508   LoggerD("Setting write value request callback for a GATT entity with _id: %d", _id);
509
510   if (gatt_objects_.find(_id) == gatt_objects_.end()) {
511     LoggerE("No GATT handle for entity with _id [%d]", _id);
512     return common::PlatformResult{ErrorCode::ABORT_ERR, "Failed to set write value request callback"};
513   }
514
515   auto gatt_handle = gatt_objects_[_id];
516   callback_names_[std::make_pair(gatt_handle, kWriteCallback)] =
517       "WriteValueRequestCallback_" + std::to_string(_id);
518
519   auto write_value_request_callback = [](
520       const char* remote_address, int request_id, bt_gatt_server_h server, bt_gatt_h gatt_handle,
521       bool response_needed, int offset, const char* value, int len, void* user_data) -> void {
522     ScopeLogger(
523         "WriteValueRequestCallback called. remote_address: %s, request_id: %d, response_needed: "
524         "%d, offset: %d, value: %s, len: %d",
525         remote_address, request_id, response_needed, offset, value, len);
526     auto rw_callback_data = static_cast<ReadWriteRequestCallbackData*>(user_data);
527
528     // We create a copy of value and remote_address
529     auto remote_address_copy = std::string{remote_address};
530     auto value_copy = std::string{value};
531     rw_callback_data->instance_.GetWorker().add_job([remote_address_copy, request_id, server,
532                                                      gatt_handle, response_needed, offset,
533                                                      value_copy, rw_callback_data] {
534       ScopeLogger("Async call: SetWriteValueRequestCallback");
535
536       auto write_value_request = picojson::value{picojson::object{}};
537       auto& write_value_request_obj = write_value_request.get<picojson::object>();
538       write_value_request_obj[kClientAddress] = picojson::value{remote_address_copy};
539       write_value_request_obj[kRequestId] = picojson::value{static_cast<double>(request_id)};
540       write_value_request_obj[kRequestType] = picojson::value{kWriteRequestType};
541       write_value_request_obj[kReplyRequired] = picojson::value{response_needed};
542       write_value_request_obj[kOffset] = picojson::value{static_cast<double>(offset)};
543
544       write_value_request_obj[kValue] = picojson::value{picojson::array{}};
545       auto& value_byte_array = write_value_request_obj[kValue].get<picojson::array>();
546       for (auto c : value_copy) {
547         value_byte_array.push_back(picojson::value{static_cast<double>(c)});
548       }
549       const auto callback_name =
550           rw_callback_data->callback_names_map_[std::make_pair(gatt_handle, kWriteCallback)];
551       LoggerD("Firing write value request event: %s: %s", callback_name.c_str(),
552               write_value_request.serialize().c_str());
553       rw_callback_data->instance_.FireEvent(callback_name, write_value_request);
554     });
555   };
556
557   auto ret = bt_gatt_server_set_write_value_requested_cb(gatt_handle, write_value_request_callback,
558                                                          &rw_request_callback_data_);
559   if (BT_ERROR_NONE != ret) {
560     LoggerE("bt_gatt_server_set_write_value_requested_cb() failed: %d (%s)", ret,
561             get_error_message(ret));
562     return BluetoothErrorToPlatformResult(ret, "Failed to set write value request callback");
563   }
564
565   LoggerD("bt_gatt_server_set_write_value_requested_cb(): SUCCESS");
566   return common::PlatformResult{};
567 }
568
569 PlatformResult BluetoothGATTServerService::SendResponse(const picojson::value& args) {
570   ScopeLogger("Response: %s", args.serialize().c_str());
571
572   auto _id = static_cast<int>(args.get(kId).get<double>());
573   auto request_id = static_cast<int>(args.get(kRequestId).get<double>());
574   auto request_type_str = args.get(kRequestType).get<std::string>();
575   auto request_type = (request_type_str == kReadRequestType) ? BT_GATT_REQUEST_TYPE_READ
576                                                              : BT_GATT_REQUEST_TYPE_WRITE;
577   auto offset = static_cast<int>(args.get(kOffset).get<double>());
578   auto status_code = static_cast<int>(args.get(kStatusCode).get<double>());
579
580   std::unique_ptr<char[]> value{nullptr};
581   int value_size = 0;
582   if (args.get(kData).is<picojson::array>()) {
583     auto value_octets = args.get(kData).get<picojson::array>();
584     value_size = value_octets.size();
585     value = std::make_unique<char[]>(value_size);
586     for (int i = 0; i < value_size; ++i) {
587       value[i] += static_cast<int>(value_octets[i].get<double>());
588     }
589   } else {
590     LoggerD("No data!");
591   }
592
593   LoggerD(
594       "Sending response: _id: %d, requestId: %d, requestType: %s, offset: %d, statusCode: %d, "
595       "value: [%p], value size: %d",
596       _id, request_id, request_type_str.c_str(), offset, status_code, value.get(), value_size);
597
598   auto ret = bt_gatt_server_send_response(request_id, request_type, offset, status_code,
599                                           value.get(), value_size);
600   if (BT_ERROR_NONE != ret) {
601     LoggerE("bt_gatt_server_send_response() failed: %d (%s)", ret, get_error_message(ret));
602     return BluetoothErrorToPlatformResult(ret, "Failed to send response");
603   }
604   LoggerD("bt_gatt_server_send_response(): SUCCESS");
605
606   return common::PlatformResult{};
607 }
608
609 struct NotificationUserData {
610   int notify_id;
611   BluetoothGATTServerService* service;
612 };
613
614 void BluetoothGATTServerService::NotifyCallback(int result, const char* remote_address,
615                                                 bt_gatt_server_h server, bt_gatt_h characteristic,
616                                                 bool completed, void* user_data) {
617   ScopeLogger("Async callback of bt_gatt_server_notify_characteristic_changed_value()");
618   LoggerD("result: %d, remote_address: %s, completed: %d", result, remote_address, completed);
619
620   NotificationUserData* data = static_cast<NotificationUserData*>(user_data);
621   BluetoothGATTServerService* bt_service = data->service;
622   int notify_id = data->notify_id;
623   LoggerD("notify_id: %d", notify_id);
624
625   picojson::value response = picojson::value(picojson::object());
626   picojson::object& obj = response.get<picojson::object>();
627
628   if (remote_address != nullptr) {
629     obj.insert(std::make_pair(kClientAddress, remote_address));
630   } else {
631     obj.insert(std::make_pair(kClientAddress, picojson::value()));
632   }
633   obj.insert(std::make_pair(kNotifyId, static_cast<double>(notify_id)));
634
635   std::string type;
636   if (BT_ERROR_NONE != result) {
637     auto ret = util::GetBluetoothError(result, "Failed to notify client about change");
638     type = kOnNotificationFail;
639     common::tools::ReportError(ret, &obj);
640   } else {
641     type = kOnNotificationSuccess;
642   }
643
644   obj.insert(std::make_pair(kType, type));
645
646   LoggerD("Sending event: type: %s, notifyId: %d", type.c_str(), notify_id);
647   std::string event =
648       "BluetoothGATTServerCharacteristicNotifyCallback_" + std::to_string(notify_id);
649   bt_service->instance_.FireEvent(event, response);
650
651   if (completed) {
652     obj[kType] = picojson::value(kOnNotificationFinish);
653     bt_service->instance_.FireEvent(event, response);
654     delete data;
655   }
656 };
657
658 common::PlatformResult BluetoothGATTServerService::NotifyAboutValueChange(
659     const picojson::value& args) {
660   ScopeLogger();
661
662   auto gatt_id = static_cast<int>(args.get(kId).get<double>());
663   auto gatt_iter = gatt_objects_.find(gatt_id);
664   if (gatt_iter == gatt_objects_.end()) {
665     LoggerE("Can't find gatt object with id: %d", gatt_id);
666     return common::PlatformResult{common::ErrorCode::ABORT_ERR, "Unknown error occurred"};
667   }
668   bt_gatt_h gatt_handle = gatt_iter->second;
669   LoggerD("Found proper gatt object");
670
671   const picojson::array& value_array = args.get(kValue).get<picojson::array>();
672   int value_size = value_array.size();
673   std::unique_ptr<char[]> value_data(new char[value_size]);
674   for (int i = 0; i < value_size; ++i) {
675     value_data[i] = static_cast<int>(value_array[i].get<double>());
676   }
677   int ret = bt_gatt_set_value(gatt_handle, value_data.get(), value_size);
678   if (BT_ERROR_NONE != ret) {
679     LoggerE("Failed to set value, error: %d, message: %s", ret, get_error_message(ret));
680     return common::PlatformResult{common::ErrorCode::ABORT_ERR, "Unknown error occurred"};
681   }
682   LoggerD("New value set in characteristic");
683
684   const char* address = args.get(kClient).is<picojson::null>()
685                             ? nullptr
686                             : args.get(kClient).get<std::string>().c_str();
687
688   LoggerD("Client address to notify: [%s]", address);
689
690   auto notify_id = static_cast<int>(args.get(kNotifyId).get<double>());
691   NotificationUserData* user_data = new NotificationUserData{notify_id, this};
692   ret = bt_gatt_server_notify_characteristic_changed_value(gatt_handle, NotifyCallback, address,
693                                                            user_data);
694   if (BT_ERROR_NONE != ret) {
695     LoggerE("bt_gatt_server_notify_characteristic_changed_value() failed: %d", ret);
696     delete user_data;
697     return common::PlatformResult{common::ErrorCode::ABORT_ERR, "Failed to notify"};
698   }
699   LoggerD("Sent notification about value changed");
700   return common::PlatformResult{};
701 }
702
703 void BluetoothGATTServerService::ClearGATTData() {
704   ScopeLogger();
705
706   LoggerD("Removing %zu old GATT handles and %zu callback names",
707           gatt_objects_.size(), callback_names_.size());
708   gatt_objects_.clear();
709   callback_names_.clear();
710 }
711
712 bool BluetoothGATTServerService::IsAnyServiceRegistered() {
713   ScopeLogger();
714   return 0 != gatt_objects_.size();
715 }
716
717 }  // namespace bluetooth
718 }  // namespace extension