1 // 2 // Copyright 2015 Google, Inc. 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 #define LOG_TAG "bt_gatts" 18 19 #include "gatt_server_old.h" 20 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <unistd.h> 24 25 #include <base/bind.h> 26 #include <algorithm> 27 #include <array> 28 #include <condition_variable> 29 #include <map> 30 #include <memory> 31 #include <mutex> 32 #include <set> 33 #include <string> 34 #include <unordered_map> 35 #include <unordered_set> 36 #include <vector> 37 38 #include <hardware/bluetooth.h> 39 #include <hardware/bt_gatt.h> 40 41 #include "service/hal/bluetooth_interface.h" 42 #include "service/logging_helpers.h" 43 44 #include "osi/include/log.h" 45 #include "osi/include/osi.h" 46 47 namespace { 48 49 const size_t kMaxGattAttributeSize = 512; 50 std::vector<btgatt_db_element_t> pending_svc_decl; 51 std::unordered_set<int> blob_index; 52 53 // TODO(icoolidge): Support multiple instances 54 // TODO(armansito): Remove this variable. No point of having this if 55 // each bluetooth::gatt::Server instance already keeps a pointer to the 56 // ServerInternals that is associated with it (which is much cleaner). It looks 57 // like this variable exists because the btif callbacks don't allow the 58 // upper-layer to pass user data to them. We could: 59 // 60 // 1. Fix the btif callbacks so that some sort of continuation can be 61 // attached to a callback. This might be a long shot since the callback 62 // interface doesn't allow more than one caller to register its own callbacks 63 // (which might be what we want though, since this would make the API more 64 // flexible). 65 // 66 // 2. Allow creation of Server objects using a factory method that returns 67 // the result asynchronously in a base::Callback. The RegisterServerCallback 68 // provides an |app_uuid|, which can be used to store callback structures in 69 // a map and lazily instantiate the Server and invoke the correct callback. 70 // This is a general pattern that we should use throughout the daemon, since 71 // all operations can timeout or fail and this is best reported in an 72 // asynchronous base::Callback. 73 // 74 static bluetooth::gatt::ServerInternals* g_internal = nullptr; 75 76 enum { kPipeReadEnd = 0, kPipeWriteEnd = 1, kPipeNumEnds = 2 }; 77 78 } // namespace 79 80 void DoNothing(uint8_t p) {} 81 82 namespace bluetooth { 83 namespace gatt { 84 85 struct Characteristic { 86 Uuid uuid; 87 int blob_section; 88 std::vector<uint8_t> blob; 89 90 // Support synchronized blob updates by latching under mutex. 91 std::vector<uint8_t> next_blob; 92 bool next_blob_pending; 93 bool notify; 94 }; 95 96 struct ServerInternals { 97 ServerInternals(); 98 ~ServerInternals(); 99 int Initialize(); 100 bt_status_t AddCharacteristic(const Uuid& uuid, uint8_t properties, 101 uint16_t permissions); 102 103 // This maps API attribute Uuids to BlueDroid handles. 104 std::map<Uuid, int> uuid_to_attribute; 105 106 // The attribute cache, indexed by BlueDroid handles. 107 std::unordered_map<int, Characteristic> characteristics; 108 109 // Associate a control attribute with its value attribute. 110 std::unordered_map<int, int> controlled_blobs; 111 112 ScanResults scan_results; 113 114 Uuid last_write; 115 const btgatt_interface_t* gatt; 116 int server_if; 117 int client_if; 118 int service_handle; 119 std::set<int> connections; 120 121 std::mutex lock; 122 std::condition_variable api_synchronize; 123 int pipefd[kPipeNumEnds]; 124 }; 125 126 } // namespace gatt 127 } // namespace bluetooth 128 129 namespace { 130 131 /** Callback invoked in response to register_server */ 132 void RegisterServerCallback(int status, int server_if, 133 const bluetooth::Uuid& app_uuid) { 134 LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d app_uuid:%p", __func__, status, 135 server_if, &app_uuid); 136 137 g_internal->server_if = server_if; 138 139 pending_svc_decl.push_back( 140 {.type = BTGATT_DB_PRIMARY_SERVICE, .uuid = app_uuid}); 141 } 142 143 void ServiceAddedCallback(int status, int server_if, 144 std::vector<btgatt_db_element_t> service) { 145 LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d count:%zu svc_handle:%d", 146 __func__, status, server_if, service.size(), 147 service[0].attribute_handle); 148 149 std::lock_guard<std::mutex> lock(g_internal->lock); 150 g_internal->server_if = server_if; 151 152 g_internal->service_handle = service[0].attribute_handle; 153 154 uint16_t prev_char_handle = 0; 155 uint16_t prev_char_properties = 0; 156 for (size_t i = 1; i < service.size(); i++) { 157 const btgatt_db_element_t& el = service[i]; 158 if (el.type == BTGATT_DB_DESCRIPTOR) { 159 LOG_INFO(LOG_TAG, "%s: descr_handle:%d", __func__, el.attribute_handle); 160 } else if (el.type == BTGATT_DB_CHARACTERISTIC) { 161 bluetooth::Uuid id(el.uuid); 162 uint16_t char_handle = el.attribute_handle; 163 164 LOG_INFO(LOG_TAG, "%s: char_handle:%d", __func__, char_handle); 165 166 g_internal->uuid_to_attribute[id] = char_handle; 167 g_internal->characteristics[char_handle].uuid = id; 168 g_internal->characteristics[char_handle].blob_section = 0; 169 170 // If the added characteristic is blob 171 if (blob_index.find(i) != blob_index.end()) { 172 // Finally, associate the control attribute with the value attribute. 173 // Also, initialize the control attribute to a readable zero. 174 const uint16_t control_attribute = char_handle; 175 const uint16_t blob_attribute = prev_char_handle; 176 g_internal->controlled_blobs[control_attribute] = blob_attribute; 177 g_internal->characteristics[blob_attribute].notify = 178 prev_char_properties & bluetooth::gatt::kPropertyNotify; 179 180 bluetooth::gatt::Characteristic& ctrl = 181 g_internal->characteristics[control_attribute]; 182 ctrl.next_blob.clear(); 183 ctrl.next_blob.push_back(0); 184 ctrl.next_blob_pending = true; 185 ctrl.blob_section = 0; 186 ctrl.notify = false; 187 } 188 prev_char_handle = char_handle; 189 prev_char_properties = el.properties; 190 } 191 } 192 193 pending_svc_decl.clear(); 194 blob_index.clear(); 195 196 // The Uuid provided here is unimportant, and is only used to satisfy 197 // BlueDroid. 198 // It must be different than any other registered Uuid. 199 bluetooth::Uuid client_id = bluetooth::Uuid::GetRandom(); 200 201 bt_status_t btstat = g_internal->gatt->client->register_client(client_id); 202 if (btstat != BT_STATUS_SUCCESS) { 203 LOG_ERROR(LOG_TAG, "%s: Failed to register client", __func__); 204 } 205 } 206 207 void RequestReadCallback(int conn_id, int trans_id, const RawAddress& bda, 208 int attr_handle, int attribute_offset_octets, 209 bool is_long) { 210 std::lock_guard<std::mutex> lock(g_internal->lock); 211 212 bluetooth::gatt::Characteristic& ch = 213 g_internal->characteristics[attr_handle]; 214 215 // Latch next_blob to blob on a 'fresh' read. 216 if (ch.next_blob_pending && attribute_offset_octets == 0 && 217 ch.blob_section == 0) { 218 std::swap(ch.blob, ch.next_blob); 219 ch.next_blob_pending = false; 220 } 221 222 const size_t blob_offset_octets = 223 std::min(ch.blob.size(), ch.blob_section * kMaxGattAttributeSize); 224 const size_t blob_remaining = ch.blob.size() - blob_offset_octets; 225 const size_t attribute_size = std::min(kMaxGattAttributeSize, blob_remaining); 226 227 std::string addr(BtAddrString(&bda)); 228 LOG_INFO(LOG_TAG, 229 "%s: connection:%d (%s) reading attr:%d attribute_offset_octets:%d " 230 "blob_section:%u (is_long:%u)", 231 __func__, conn_id, addr.c_str(), attr_handle, 232 attribute_offset_octets, ch.blob_section, is_long); 233 234 btgatt_response_t response; 235 response.attr_value.len = 0; 236 237 if (attribute_offset_octets < static_cast<int>(attribute_size)) { 238 std::copy(ch.blob.begin() + blob_offset_octets + attribute_offset_octets, 239 ch.blob.begin() + blob_offset_octets + attribute_size, 240 response.attr_value.value); 241 response.attr_value.len = attribute_size - attribute_offset_octets; 242 } 243 244 response.attr_value.handle = attr_handle; 245 response.attr_value.offset = attribute_offset_octets; 246 response.attr_value.auth_req = 0; 247 g_internal->gatt->server->send_response(conn_id, trans_id, 0, response); 248 } 249 250 void RequestWriteCallback(int conn_id, int trans_id, const RawAddress& bda, 251 int attr_handle, int attribute_offset, bool need_rsp, 252 bool is_prep, std::vector<uint8_t> value) { 253 std::string addr(BtAddrString(&bda)); 254 LOG_INFO(LOG_TAG, 255 "%s: connection:%d (%s:trans:%d) write attr:%d attribute_offset:%d " 256 "length:%zu " 257 "need_resp:%u is_prep:%u", 258 __func__, conn_id, addr.c_str(), trans_id, attr_handle, 259 attribute_offset, value.size(), need_rsp, is_prep); 260 261 std::lock_guard<std::mutex> lock(g_internal->lock); 262 263 bluetooth::gatt::Characteristic& ch = 264 g_internal->characteristics[attr_handle]; 265 266 ch.blob.resize(attribute_offset + value.size()); 267 268 std::copy(value.begin(), value.end(), ch.blob.begin() + attribute_offset); 269 270 auto target_blob = g_internal->controlled_blobs.find(attr_handle); 271 // If this is a control attribute, adjust offset of the target blob. 272 if (target_blob != g_internal->controlled_blobs.end() && 273 ch.blob.size() == 1u) { 274 g_internal->characteristics[target_blob->second].blob_section = ch.blob[0]; 275 LOG_INFO(LOG_TAG, "%s: updating attribute %d blob_section to %u", __func__, 276 target_blob->second, ch.blob[0]); 277 } else if (!is_prep) { 278 // This is a single frame characteristic write. 279 // Notify upwards because we're done now. 280 const bluetooth::Uuid::UUID128Bit& attr_uuid = ch.uuid.To128BitBE(); 281 ssize_t status; 282 OSI_NO_INTR(status = write(g_internal->pipefd[kPipeWriteEnd], 283 attr_uuid.data(), attr_uuid.size())); 284 if (-1 == status) 285 LOG_ERROR(LOG_TAG, "%s: write failed: %s", __func__, strerror(errno)); 286 } else { 287 // This is a multi-frame characteristic write. 288 // Wait for an 'RequestExecWriteCallback' to notify completion. 289 g_internal->last_write = ch.uuid; 290 } 291 292 // Respond only if needed. 293 if (!need_rsp) return; 294 295 btgatt_response_t response; 296 response.attr_value.handle = attr_handle; 297 response.attr_value.offset = attribute_offset; 298 response.attr_value.len = value.size(); 299 response.attr_value.auth_req = 0; 300 // Provide written data back to sender for the response. 301 // Remote stacks use this to validate the success of the write. 302 std::copy(value.begin(), value.end(), response.attr_value.value); 303 g_internal->gatt->server->send_response(conn_id, trans_id, 0, response); 304 } 305 306 void RequestExecWriteCallback(int conn_id, int trans_id, const RawAddress& bda, 307 int exec_write) { 308 std::string addr(BtAddrString(&bda)); 309 LOG_INFO(LOG_TAG, "%s: connection:%d (%s:trans:%d) exec_write:%d", __func__, 310 conn_id, addr.c_str(), trans_id, exec_write); 311 312 // This 'response' data is unused for ExecWriteResponses. 313 // It is only used to pass BlueDroid argument validation. 314 btgatt_response_t response = {}; 315 g_internal->gatt->server->send_response(conn_id, trans_id, 0, response); 316 317 if (!exec_write) return; 318 319 std::lock_guard<std::mutex> lock(g_internal->lock); 320 // Communicate the attribute Uuid as notification of a write update. 321 const bluetooth::Uuid::UUID128Bit uuid = g_internal->last_write.To128BitBE(); 322 ssize_t status; 323 OSI_NO_INTR(status = write(g_internal->pipefd[kPipeWriteEnd], uuid.data(), 324 uuid.size())); 325 if (-1 == status) 326 LOG_ERROR(LOG_TAG, "%s: write failed: %s", __func__, strerror(errno)); 327 } 328 329 void ConnectionCallback(int conn_id, int server_if, int connected, 330 const RawAddress& bda) { 331 std::string addr(BtAddrString(&bda)); 332 LOG_INFO(LOG_TAG, "%s: connection:%d server_if:%d connected:%d addr:%s", 333 __func__, conn_id, server_if, connected, addr.c_str()); 334 if (connected == 1) { 335 g_internal->connections.insert(conn_id); 336 } else if (connected == 0) { 337 g_internal->connections.erase(conn_id); 338 } 339 } 340 341 void EnableAdvertisingCallback(uint8_t status) { 342 LOG_INFO(LOG_TAG, "%s: status:%d", __func__, status); 343 // This terminates a Start call. 344 std::lock_guard<std::mutex> lock(g_internal->lock); 345 g_internal->api_synchronize.notify_one(); 346 } 347 348 void RegisterClientCallback(int status, int client_if, 349 const bluetooth::Uuid& app_uuid) { 350 LOG_INFO(LOG_TAG, "%s: status:%d client_if:%d uuid[0]:%s", __func__, status, 351 client_if, app_uuid.ToString().c_str()); 352 g_internal->client_if = client_if; 353 354 // Setup our advertisement. This has no callback. 355 g_internal->gatt->advertiser->SetData(0 /* std_inst */, false, 356 {/*TODO: put inverval 2,2 here*/}, 357 base::Bind(&DoNothing)); 358 359 g_internal->gatt->advertiser->Enable( 360 0 /* std_inst */, true, base::Bind(&EnableAdvertisingCallback), 361 0 /* no duration */, 0 /* no maxExtAdvEvent*/, base::Bind(&DoNothing)); 362 } 363 364 void ServiceStoppedCallback(int status, int server_if, int srvc_handle) { 365 LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d srvc_handle:%d", __func__, 366 status, server_if, srvc_handle); 367 // This terminates a Stop call. 368 // TODO(icoolidge): make this symmetric with start 369 std::lock_guard<std::mutex> lock(g_internal->lock); 370 g_internal->api_synchronize.notify_one(); 371 } 372 373 void ScanResultCallback(uint16_t ble_evt_type, uint8_t addr_type, 374 RawAddress* bda, uint8_t ble_primary_phy, 375 uint8_t ble_secondary_phy, uint8_t ble_advertising_sid, 376 int8_t ble_tx_power, int8_t rssi, 377 uint16_t ble_periodic_adv_int, 378 std::vector<uint8_t> adv_data) { 379 std::string addr(BtAddrString(bda)); 380 std::lock_guard<std::mutex> lock(g_internal->lock); 381 g_internal->scan_results[addr] = rssi; 382 } 383 384 void ClientConnectCallback(int conn_id, int status, int client_if, 385 const RawAddress& bda) { 386 std::string addr(BtAddrString(&bda)); 387 LOG_INFO(LOG_TAG, "%s: conn_id:%d status:%d client_if:%d %s", __func__, 388 conn_id, status, client_if, addr.c_str()); 389 } 390 391 void ClientDisconnectCallback(int conn_id, int status, int client_if, 392 const RawAddress& bda) { 393 std::string addr(BtAddrString(&bda)); 394 LOG_INFO(LOG_TAG, "%s: conn_id:%d status:%d client_if:%d %s", __func__, 395 conn_id, status, client_if, addr.c_str()); 396 } 397 398 void IndicationSentCallback(UNUSED_ATTR int conn_id, UNUSED_ATTR int status) { 399 // TODO(icoolidge): what to do 400 } 401 402 void ResponseConfirmationCallback(UNUSED_ATTR int status, 403 UNUSED_ATTR int handle) { 404 // TODO(icoolidge): what to do 405 } 406 407 const btgatt_server_callbacks_t gatt_server_callbacks = { 408 RegisterServerCallback, 409 ConnectionCallback, 410 ServiceAddedCallback, 411 ServiceStoppedCallback, 412 nullptr, /* service_deleted_cb */ 413 RequestReadCallback, 414 RequestReadCallback, 415 RequestWriteCallback, 416 RequestWriteCallback, 417 RequestExecWriteCallback, 418 ResponseConfirmationCallback, 419 IndicationSentCallback, 420 nullptr, /* congestion_cb*/ 421 nullptr, /* mtu_changed_cb */ 422 nullptr, /* phy_update_cb */ 423 nullptr, /* conn_update_cb */ 424 }; 425 426 // TODO(eisenbach): Refactor GATT interface to not require servers 427 // to refer to the client interface. 428 const btgatt_client_callbacks_t gatt_client_callbacks = { 429 RegisterClientCallback, 430 ClientConnectCallback, 431 ClientDisconnectCallback, 432 nullptr, /* search_complete_cb; */ 433 nullptr, /* register_for_notification_cb; */ 434 nullptr, /* notify_cb; */ 435 nullptr, /* read_characteristic_cb; */ 436 nullptr, /* write_characteristic_cb; */ 437 nullptr, /* read_descriptor_cb; */ 438 nullptr, /* write_descriptor_cb; */ 439 nullptr, /* execute_write_cb; */ 440 nullptr, /* read_remote_rssi_cb; */ 441 nullptr, /* configure_mtu_cb; */ 442 nullptr, /* congestion_cb; */ 443 nullptr, /* get_gatt_db_cb; */ 444 nullptr, /* services_removed_cb */ 445 nullptr, /* services_added_cb */ 446 nullptr, /* phy_update_cb */ 447 nullptr, /* conn_update_cb */ 448 }; 449 450 const btgatt_scanner_callbacks_t gatt_scanner_callbacks = { 451 ScanResultCallback, 452 nullptr, /* batchscan_reports_cb; */ 453 nullptr, /* batchscan_threshold_cb; */ 454 nullptr, /* track_adv_event_cb; */ 455 }; 456 457 const btgatt_callbacks_t gatt_callbacks = { 458 /** Set to sizeof(btgatt_callbacks_t) */ 459 sizeof(btgatt_callbacks_t), 460 461 /** GATT Client callbacks */ 462 &gatt_client_callbacks, 463 464 /** GATT Server callbacks */ 465 &gatt_server_callbacks, 466 467 /** GATT Server callbacks */ 468 &gatt_scanner_callbacks, 469 }; 470 471 } // namespace 472 473 namespace bluetooth { 474 namespace gatt { 475 476 int ServerInternals::Initialize() { 477 // Get the interface to the GATT profile. 478 const bt_interface_t* bt_iface = 479 hal::BluetoothInterface::Get()->GetHALInterface(); 480 gatt = reinterpret_cast<const btgatt_interface_t*>( 481 bt_iface->get_profile_interface(BT_PROFILE_GATT_ID)); 482 if (!gatt) { 483 LOG_ERROR(LOG_TAG, "Error getting GATT interface"); 484 return -1; 485 } 486 487 bt_status_t btstat = gatt->init(&gatt_callbacks); 488 if (btstat != BT_STATUS_SUCCESS) { 489 LOG_ERROR(LOG_TAG, "Failed to initialize gatt interface"); 490 return -1; 491 } 492 493 int status = pipe(pipefd); 494 if (status == -1) { 495 LOG_ERROR(LOG_TAG, "pipe creation failed: %s", strerror(errno)); 496 return -1; 497 } 498 499 return 0; 500 } 501 502 bt_status_t ServerInternals::AddCharacteristic(const Uuid& uuid, 503 uint8_t properties, 504 uint16_t permissions) { 505 pending_svc_decl.push_back({.type = BTGATT_DB_CHARACTERISTIC, 506 .uuid = uuid, 507 .properties = properties, 508 .permissions = permissions}); 509 return BT_STATUS_SUCCESS; 510 } 511 512 ServerInternals::ServerInternals() 513 : gatt(nullptr), 514 server_if(0), 515 client_if(0), 516 service_handle(0), 517 pipefd{INVALID_FD, INVALID_FD} {} 518 519 ServerInternals::~ServerInternals() { 520 if (pipefd[0] != INVALID_FD) close(pipefd[0]); 521 if (pipefd[1] != INVALID_FD) close(pipefd[1]); 522 523 gatt->server->delete_service(server_if, service_handle); 524 gatt->server->unregister_server(server_if); 525 gatt->client->unregister_client(client_if); 526 } 527 528 Server::Server() : internal_(nullptr) {} 529 530 Server::~Server() {} 531 532 bool Server::Initialize(const Uuid& service_id, int* gatt_pipe) { 533 internal_.reset(new ServerInternals); 534 if (!internal_) { 535 LOG_ERROR(LOG_TAG, "Error creating internals"); 536 return false; 537 } 538 g_internal = internal_.get(); 539 540 std::unique_lock<std::mutex> lock(internal_->lock); 541 int status = internal_->Initialize(); 542 if (status) { 543 LOG_ERROR(LOG_TAG, "Error initializing internals"); 544 return false; 545 } 546 547 bt_status_t btstat = internal_->gatt->server->register_server(service_id); 548 if (btstat != BT_STATUS_SUCCESS) { 549 LOG_ERROR(LOG_TAG, "Failed to register server"); 550 return false; 551 } 552 553 internal_->api_synchronize.wait(lock); 554 // TODO(icoolidge): Better error handling. 555 if (internal_->server_if == 0) { 556 LOG_ERROR(LOG_TAG, "Initialization of server failed"); 557 return false; 558 } 559 560 *gatt_pipe = internal_->pipefd[kPipeReadEnd]; 561 LOG_INFO(LOG_TAG, "Server Initialize succeeded"); 562 return true; 563 } 564 565 bool Server::SetAdvertisement(const std::vector<Uuid>& ids, 566 const std::vector<uint8_t>& service_data, 567 const std::vector<uint8_t>& manufacturer_data, 568 bool transmit_name) { 569 // std::vector<uint8_t> id_data; 570 // const auto& mutable_manufacturer_data = manufacturer_data; 571 // const auto& mutable_service_data = service_data; 572 573 // for (const Uuid &id : ids) { 574 // const auto le_id = id.To128BitLE(); 575 // id_data.insert(id_data.end(), le_id.begin(), le_id.end()); 576 // } 577 578 std::lock_guard<std::mutex> lock(internal_->lock); 579 580 // Setup our advertisement. This has no callback. 581 internal_->gatt->advertiser->SetData(0, false, /* beacon, not scan response */ 582 {}, base::Bind(&DoNothing)); 583 // transmit_name, /* name */ 584 // 2, 2, interval 585 // mutable_manufacturer_data, 586 // mutable_service_data, 587 // id_data); 588 return true; 589 } 590 591 bool Server::SetScanResponse(const std::vector<Uuid>& ids, 592 const std::vector<uint8_t>& service_data, 593 const std::vector<uint8_t>& manufacturer_data, 594 bool transmit_name) { 595 // std::vector<uint8_t> id_data; 596 // const auto& mutable_manufacturer_data = manufacturer_data; 597 // const auto& mutable_service_data = service_data; 598 599 // for (const Uuid &id : ids) { 600 // const auto le_id = id.To128BitLE(); 601 // id_data.insert(id_data.end(), le_id.begin(), le_id.end()); 602 // } 603 604 std::lock_guard<std::mutex> lock(internal_->lock); 605 606 // Setup our advertisement. This has no callback. 607 internal_->gatt->advertiser->SetData(0, true, /* scan response */ 608 {}, base::Bind(&DoNothing)); 609 // transmit_name, /* name */ 610 // false, /* no txpower */ 611 // 2, 2, interval 612 // 0, /* appearance */ 613 // mutable_manufacturer_data, 614 // mutable_service_data, 615 // id_data); 616 return true; 617 } 618 619 bool Server::AddCharacteristic(const Uuid& id, int properties, 620 int permissions) { 621 std::unique_lock<std::mutex> lock(internal_->lock); 622 bt_status_t btstat = 623 internal_->AddCharacteristic(id, properties, permissions); 624 if (btstat != BT_STATUS_SUCCESS) { 625 LOG_ERROR(LOG_TAG, "Failed to add characteristic to service: 0x%04x", 626 internal_->service_handle); 627 return false; 628 } 629 internal_->api_synchronize.wait(lock); 630 const int handle = internal_->uuid_to_attribute[id]; 631 internal_->characteristics[handle].notify = properties & kPropertyNotify; 632 return true; 633 } 634 635 bool Server::AddBlob(const Uuid& id, const Uuid& control_id, int properties, 636 int permissions) { 637 std::unique_lock<std::mutex> lock(internal_->lock); 638 639 // First, add the primary attribute (characteristic value) 640 bt_status_t btstat = 641 internal_->AddCharacteristic(id, properties, permissions); 642 if (btstat != BT_STATUS_SUCCESS) { 643 LOG_ERROR(LOG_TAG, "Failed to set scan response data"); 644 return false; 645 } 646 647 // Next, add the secondary attribute (blob control). 648 // Control attributes have fixed permissions/properties. 649 // Remember position at which blob was added. 650 blob_index.insert(pending_svc_decl.size()); 651 btstat = 652 internal_->AddCharacteristic(control_id, kPropertyRead | kPropertyWrite, 653 kPermissionRead | kPermissionWrite); 654 655 return true; 656 } 657 658 bool Server::Start() { 659 std::unique_lock<std::mutex> lock(internal_->lock); 660 bt_status_t btstat = internal_->gatt->server->add_service( 661 internal_->server_if, pending_svc_decl); 662 if (btstat != BT_STATUS_SUCCESS) { 663 LOG_ERROR(LOG_TAG, "Failed to start service with handle: 0x%04x", 664 internal_->service_handle); 665 return false; 666 } 667 internal_->api_synchronize.wait(lock); 668 return true; 669 } 670 671 bool Server::Stop() { 672 std::unique_lock<std::mutex> lock(internal_->lock); 673 bt_status_t btstat = internal_->gatt->server->stop_service( 674 internal_->server_if, internal_->service_handle); 675 if (btstat != BT_STATUS_SUCCESS) { 676 LOG_ERROR(LOG_TAG, "Failed to stop service with handle: 0x%04x", 677 internal_->service_handle); 678 return false; 679 } 680 internal_->api_synchronize.wait(lock); 681 return true; 682 } 683 684 bool Server::ScanEnable() { 685 internal_->gatt->scanner->Scan(true); 686 return true; 687 } 688 689 bool Server::ScanDisable() { 690 internal_->gatt->scanner->Scan(false); 691 return true; 692 } 693 694 bool Server::GetScanResults(ScanResults* results) { 695 std::lock_guard<std::mutex> lock(internal_->lock); 696 *results = internal_->scan_results; 697 return true; 698 } 699 700 bool Server::SetCharacteristicValue(const Uuid& id, 701 const std::vector<uint8_t>& value) { 702 std::lock_guard<std::mutex> lock(internal_->lock); 703 const int attribute_id = internal_->uuid_to_attribute[id]; 704 Characteristic& ch = internal_->characteristics[attribute_id]; 705 ch.next_blob = value; 706 ch.next_blob_pending = true; 707 708 if (!ch.notify) return true; 709 710 for (auto connection : internal_->connections) { 711 internal_->gatt->server->send_indication(internal_->server_if, attribute_id, 712 connection, true, {0}); 713 } 714 return true; 715 } 716 717 bool Server::GetCharacteristicValue(const Uuid& id, 718 std::vector<uint8_t>* value) { 719 std::lock_guard<std::mutex> lock(internal_->lock); 720 const int attribute_id = internal_->uuid_to_attribute[id]; 721 *value = internal_->characteristics[attribute_id].blob; 722 return true; 723 } 724 725 } // namespace gatt 726 } // namespace bluetooth 727