1 // 2 // Copyright (C) 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 <algorithm> 26 #include <array> 27 #include <condition_variable> 28 #include <map> 29 #include <memory> 30 #include <mutex> 31 #include <set> 32 #include <string> 33 #include <unordered_map> 34 #include <vector> 35 36 #include <hardware/bluetooth.h> 37 #include <hardware/bt_gatt.h> 38 39 #include "service/hal/bluetooth_interface.h" 40 #include "service/logging_helpers.h" 41 42 extern "C" { 43 #include "osi/include/log.h" 44 #include "osi/include/osi.h" 45 } // extern "C" 46 47 namespace { 48 49 const size_t kMaxGattAttributeSize = 512; 50 // TODO(icoolidge): Difficult to generalize without knowing how many attributes. 51 const int kNumBlueDroidHandles = 60; 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 namespace bluetooth { 81 namespace gatt { 82 83 struct Characteristic { 84 UUID uuid; 85 int blob_section; 86 std::vector<uint8_t> blob; 87 88 // Support synchronized blob updates by latching under mutex. 89 std::vector<uint8_t> next_blob; 90 bool next_blob_pending; 91 bool notify; 92 }; 93 94 struct ServerInternals { 95 ServerInternals(); 96 ~ServerInternals(); 97 int Initialize(); 98 bt_status_t AddCharacteristic( 99 const UUID& uuid, 100 int properties, 101 int 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 btgatt_srvc_id_t service_id; 120 std::set<int> connections; 121 122 std::mutex lock; 123 std::condition_variable api_synchronize; 124 int pipefd[kPipeNumEnds]; 125 }; 126 127 } // namespace gatt 128 } // namespace bluetooth 129 130 namespace { 131 132 /** Callback invoked in response to register_server */ 133 void RegisterServerCallback(int status, int server_if, bt_uuid_t *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 btgatt_srvc_id_t service_id; 140 service_id.id.uuid = *app_uuid; 141 service_id.id.inst_id = 0; 142 service_id.is_primary = true; 143 144 g_internal->gatt->server->add_service( 145 server_if, &service_id, kNumBlueDroidHandles); 146 } 147 148 void ServiceAddedCallback(int status, int server_if, btgatt_srvc_id_t *srvc_id, 149 int srvc_handle) { 150 LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d gatt_srvc_id:%u srvc_handle:%d", 151 __func__, status, server_if, srvc_id->id.inst_id, srvc_handle); 152 153 std::lock_guard<std::mutex> lock(g_internal->lock); 154 g_internal->server_if = server_if; 155 g_internal->service_handle = srvc_handle; 156 g_internal->service_id = *srvc_id; 157 // This finishes the Initialize call. 158 g_internal->api_synchronize.notify_one(); 159 } 160 161 void RequestReadCallback(int conn_id, int trans_id, bt_bdaddr_t *bda, 162 int attr_handle, int attribute_offset_octets, 163 bool is_long) { 164 std::lock_guard<std::mutex> lock(g_internal->lock); 165 166 bluetooth::gatt::Characteristic &ch = g_internal->characteristics[attr_handle]; 167 168 // Latch next_blob to blob on a 'fresh' read. 169 if (ch.next_blob_pending && attribute_offset_octets == 0 && 170 ch.blob_section == 0) { 171 std::swap(ch.blob, ch.next_blob); 172 ch.next_blob_pending = false; 173 } 174 175 const size_t blob_offset_octets = 176 std::min(ch.blob.size(), ch.blob_section * kMaxGattAttributeSize); 177 const size_t blob_remaining = ch.blob.size() - blob_offset_octets; 178 const size_t attribute_size = std::min(kMaxGattAttributeSize, blob_remaining); 179 180 std::string addr(BtAddrString(bda)); 181 LOG_INFO(LOG_TAG, 182 "%s: connection:%d (%s) reading attr:%d attribute_offset_octets:%d " 183 "blob_section:%u (is_long:%u)", 184 __func__, conn_id, addr.c_str(), attr_handle, attribute_offset_octets, 185 ch.blob_section, is_long); 186 187 btgatt_response_t response; 188 response.attr_value.len = 0; 189 190 if (attribute_offset_octets < static_cast<int>(attribute_size)) { 191 std::copy(ch.blob.begin() + blob_offset_octets + attribute_offset_octets, 192 ch.blob.begin() + blob_offset_octets + attribute_size, 193 response.attr_value.value); 194 response.attr_value.len = attribute_size - attribute_offset_octets; 195 } 196 197 response.attr_value.handle = attr_handle; 198 response.attr_value.offset = attribute_offset_octets; 199 response.attr_value.auth_req = 0; 200 g_internal->gatt->server->send_response(conn_id, trans_id, 0, &response); 201 } 202 203 void RequestWriteCallback(int conn_id, int trans_id, bt_bdaddr_t *bda, 204 int attr_handle, int attribute_offset, int length, 205 bool need_rsp, bool is_prep, uint8_t *value) { 206 std::string addr(BtAddrString(bda)); 207 LOG_INFO(LOG_TAG, 208 "%s: connection:%d (%s:trans:%d) write attr:%d attribute_offset:%d " 209 "length:%d " 210 "need_resp:%u is_prep:%u", 211 __func__, conn_id, addr.c_str(), trans_id, attr_handle, attribute_offset, 212 length, need_rsp, is_prep); 213 214 std::lock_guard<std::mutex> lock(g_internal->lock); 215 216 bluetooth::gatt::Characteristic &ch = 217 g_internal->characteristics[attr_handle]; 218 219 ch.blob.resize(attribute_offset + length); 220 221 std::copy(value, value + length, ch.blob.begin() + attribute_offset); 222 223 auto target_blob = g_internal->controlled_blobs.find(attr_handle); 224 // If this is a control attribute, adjust offset of the target blob. 225 if (target_blob != g_internal->controlled_blobs.end() && 226 ch.blob.size() == 1u) { 227 g_internal->characteristics[target_blob->second].blob_section = ch.blob[0]; 228 LOG_INFO(LOG_TAG, "%s: updating attribute %d blob_section to %u", __func__, 229 target_blob->second, ch.blob[0]); 230 } else if (!is_prep) { 231 // This is a single frame characteristic write. 232 // Notify upwards because we're done now. 233 const bluetooth::UUID::UUID128Bit &attr_uuid = ch.uuid.GetFullBigEndian(); 234 ssize_t status; 235 OSI_NO_INTR(status = write(g_internal->pipefd[kPipeWriteEnd], 236 attr_uuid.data(), attr_uuid.size())); 237 if (-1 == status) 238 LOG_ERROR(LOG_TAG, "%s: write failed: %s", __func__, strerror(errno)); 239 } else { 240 // This is a multi-frame characteristic write. 241 // Wait for an 'RequestExecWriteCallback' to notify completion. 242 g_internal->last_write = ch.uuid; 243 } 244 245 // Respond only if needed. 246 if (!need_rsp) return; 247 248 btgatt_response_t response; 249 response.attr_value.handle = attr_handle; 250 response.attr_value.offset = attribute_offset; 251 response.attr_value.len = length; 252 response.attr_value.auth_req = 0; 253 // Provide written data back to sender for the response. 254 // Remote stacks use this to validate the success of the write. 255 std::copy(value, value + length, response.attr_value.value); 256 g_internal->gatt->server->send_response(conn_id, trans_id, 0, &response); 257 } 258 259 void RequestExecWriteCallback(int conn_id, int trans_id, bt_bdaddr_t *bda, 260 int exec_write) { 261 std::string addr(BtAddrString(bda)); 262 LOG_INFO(LOG_TAG, "%s: connection:%d (%s:trans:%d) exec_write:%d", __func__, 263 conn_id, addr.c_str(), trans_id, exec_write); 264 265 // This 'response' data is unused for ExecWriteResponses. 266 // It is only used to pass BlueDroid argument validation. 267 btgatt_response_t response = {}; 268 g_internal->gatt->server->send_response(conn_id, trans_id, 0, &response); 269 270 if (!exec_write) 271 return; 272 273 std::lock_guard<std::mutex> lock(g_internal->lock); 274 // Communicate the attribute UUID as notification of a write update. 275 const bluetooth::UUID::UUID128Bit uuid = 276 g_internal->last_write.GetFullBigEndian(); 277 ssize_t status; 278 OSI_NO_INTR(status = write(g_internal->pipefd[kPipeWriteEnd], uuid.data(), 279 uuid.size())); 280 if (-1 == status) 281 LOG_ERROR(LOG_TAG, "%s: write failed: %s", __func__, strerror(errno)); 282 } 283 284 void ConnectionCallback(int conn_id, int server_if, int connected, 285 bt_bdaddr_t *bda) { 286 std::string addr(BtAddrString(bda)); 287 LOG_INFO(LOG_TAG, "%s: connection:%d server_if:%d connected:%d addr:%s", 288 __func__, conn_id, server_if, connected, addr.c_str()); 289 if (connected == 1) { 290 g_internal->connections.insert(conn_id); 291 } else if (connected == 0) { 292 g_internal->connections.erase(conn_id); 293 } 294 } 295 296 void CharacteristicAddedCallback(int status, int server_if, bt_uuid_t *uuid, 297 int srvc_handle, int char_handle) { 298 LOG_INFO(LOG_TAG, 299 "%s: status:%d server_if:%d service_handle:%d char_handle:%d", __func__, 300 status, server_if, srvc_handle, char_handle); 301 302 bluetooth::UUID id(*uuid); 303 304 std::lock_guard<std::mutex> lock(g_internal->lock); 305 306 g_internal->uuid_to_attribute[id] = char_handle; 307 g_internal->characteristics[char_handle].uuid = id; 308 g_internal->characteristics[char_handle].blob_section = 0; 309 310 // This terminates an AddCharacteristic. 311 g_internal->api_synchronize.notify_one(); 312 } 313 314 void DescriptorAddedCallback(int status, int server_if, bt_uuid_t *uuid, 315 int srvc_handle, int descr_handle) { 316 LOG_INFO(LOG_TAG, 317 "%s: status:%d server_if:%d service_handle:%d uuid[0]:%u " 318 "descr_handle:%d", 319 __func__, status, server_if, srvc_handle, uuid->uu[0], descr_handle); 320 } 321 322 void ServiceStartedCallback(int status, int server_if, int srvc_handle) { 323 LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d srvc_handle:%d", __func__, 324 status, server_if, srvc_handle); 325 326 // The UUID provided here is unimportant, and is only used to satisfy 327 // BlueDroid. 328 // It must be different than any other registered UUID. 329 bt_uuid_t client_id = g_internal->service_id.id.uuid; 330 ++client_id.uu[15]; 331 332 bt_status_t btstat = g_internal->gatt->client->register_client(&client_id); 333 if (btstat != BT_STATUS_SUCCESS) { 334 LOG_ERROR(LOG_TAG, "%s: Failed to register client", __func__); 335 } 336 } 337 338 void RegisterClientCallback(int status, int client_if, bt_uuid_t *app_uuid) { 339 LOG_INFO(LOG_TAG, "%s: status:%d client_if:%d uuid[0]:%u", __func__, status, 340 client_if, app_uuid->uu[0]); 341 g_internal->client_if = client_if; 342 343 // Setup our advertisement. This has no callback. 344 bt_status_t btstat = g_internal->gatt->client->set_adv_data( 345 client_if, false, /* beacon, not scan response */ 346 false, /* name */ 347 false, /* no txpower */ 348 2, 2, /* interval */ 349 0, /* appearance */ 350 0, nullptr, /* no mfg data */ 351 0, nullptr, /* no service data */ 352 0, nullptr /* no service id yet */); 353 if (btstat != BT_STATUS_SUCCESS) { 354 LOG_ERROR(LOG_TAG, "Failed to set advertising data"); 355 return; 356 } 357 358 // TODO(icoolidge): Deprecated, use multi-adv interface. 359 // This calls back to ListenCallback. 360 btstat = g_internal->gatt->client->listen(client_if, true); 361 if (btstat != BT_STATUS_SUCCESS) { 362 LOG_ERROR(LOG_TAG, "Failed to start listening"); 363 } 364 } 365 366 void ListenCallback(int status, int client_if) { 367 LOG_INFO(LOG_TAG, "%s: status:%d client_if:%d", __func__, status, client_if); 368 // This terminates a Start call. 369 std::lock_guard<std::mutex> lock(g_internal->lock); 370 g_internal->api_synchronize.notify_one(); 371 } 372 373 void ServiceStoppedCallback(int status, int server_if, int srvc_handle) { 374 LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d srvc_handle:%d", __func__, 375 status, server_if, srvc_handle); 376 // This terminates a Stop call. 377 // TODO(icoolidge): make this symmetric with start 378 std::lock_guard<std::mutex> lock(g_internal->lock); 379 g_internal->api_synchronize.notify_one(); 380 } 381 382 void ScanResultCallback(bt_bdaddr_t *bda, int rssi, uint8_t *adv_data) { 383 std::string addr(BtAddrString(bda)); 384 (void)adv_data; 385 std::lock_guard<std::mutex> lock(g_internal->lock); 386 g_internal->scan_results[addr] = rssi; 387 } 388 389 void ClientConnectCallback(int conn_id, int status, int client_if, 390 bt_bdaddr_t *bda) { 391 std::string addr(BtAddrString(bda)); 392 LOG_INFO(LOG_TAG, "%s: conn_id:%d status:%d client_if:%d %s", __func__, 393 conn_id, status, client_if, addr.c_str()); 394 } 395 396 void ClientDisconnectCallback(int conn_id, int status, int client_if, 397 bt_bdaddr_t *bda) { 398 std::string addr(BtAddrString(bda)); 399 LOG_INFO(LOG_TAG, "%s: conn_id:%d status:%d client_if:%d %s", __func__, 400 conn_id, status, client_if, addr.c_str()); 401 } 402 403 void IndicationSentCallback(UNUSED_ATTR int conn_id, 404 UNUSED_ATTR int status) { 405 // TODO(icoolidge): what to do 406 } 407 408 void ResponseConfirmationCallback(UNUSED_ATTR int status, 409 UNUSED_ATTR int handle) { 410 // TODO(icoolidge): what to do 411 } 412 413 const btgatt_server_callbacks_t gatt_server_callbacks = { 414 RegisterServerCallback, 415 ConnectionCallback, 416 ServiceAddedCallback, 417 nullptr, /* included_service_added_cb */ 418 CharacteristicAddedCallback, 419 DescriptorAddedCallback, 420 ServiceStartedCallback, 421 ServiceStoppedCallback, 422 nullptr, /* service_deleted_cb */ 423 RequestReadCallback, 424 RequestWriteCallback, 425 RequestExecWriteCallback, 426 ResponseConfirmationCallback, 427 IndicationSentCallback, 428 nullptr, /* congestion_cb*/ 429 nullptr, /* mtu_changed_cb */ 430 }; 431 432 // TODO(eisenbach): Refactor GATT interface to not require servers 433 // to refer to the client interface. 434 const btgatt_client_callbacks_t gatt_client_callbacks = { 435 RegisterClientCallback, 436 ScanResultCallback, 437 ClientConnectCallback, 438 ClientDisconnectCallback, 439 nullptr, /* search_complete_cb; */ 440 nullptr, /* register_for_notification_cb; */ 441 nullptr, /* notify_cb; */ 442 nullptr, /* read_characteristic_cb; */ 443 nullptr, /* write_characteristic_cb; */ 444 nullptr, /* read_descriptor_cb; */ 445 nullptr, /* write_descriptor_cb; */ 446 nullptr, /* execute_write_cb; */ 447 nullptr, /* read_remote_rssi_cb; */ 448 ListenCallback, 449 nullptr, /* configure_mtu_cb; */ 450 nullptr, /* scan_filter_cfg_cb; */ 451 nullptr, /* scan_filter_param_cb; */ 452 nullptr, /* scan_filter_status_cb; */ 453 nullptr, /* multi_adv_enable_cb */ 454 nullptr, /* multi_adv_update_cb; */ 455 nullptr, /* multi_adv_data_cb*/ 456 nullptr, /* multi_adv_disable_cb; */ 457 nullptr, /* congestion_cb; */ 458 nullptr, /* batchscan_cfg_storage_cb; */ 459 nullptr, /* batchscan_enb_disable_cb; */ 460 nullptr, /* batchscan_reports_cb; */ 461 nullptr, /* batchscan_threshold_cb; */ 462 nullptr, /* track_adv_event_cb; */ 463 nullptr, /* scan_parameter_setup_completed_cb; */ 464 nullptr, /* get_gatt_db_cb; */ 465 nullptr, /* services_removed_cb */ 466 nullptr, /* services_added_cb */ 467 }; 468 469 const btgatt_callbacks_t gatt_callbacks = { 470 /** Set to sizeof(btgatt_callbacks_t) */ 471 sizeof(btgatt_callbacks_t), 472 473 /** GATT Client callbacks */ 474 &gatt_client_callbacks, 475 476 /** GATT Server callbacks */ 477 &gatt_server_callbacks}; 478 479 } // namespace 480 481 namespace bluetooth { 482 namespace gatt { 483 484 int ServerInternals::Initialize() { 485 // Get the interface to the GATT profile. 486 const bt_interface_t* bt_iface = 487 hal::BluetoothInterface::Get()->GetHALInterface(); 488 gatt = reinterpret_cast<const btgatt_interface_t *>( 489 bt_iface->get_profile_interface(BT_PROFILE_GATT_ID)); 490 if (!gatt) { 491 LOG_ERROR(LOG_TAG, "Error getting GATT interface"); 492 return -1; 493 } 494 495 bt_status_t btstat = gatt->init(&gatt_callbacks); 496 if (btstat != BT_STATUS_SUCCESS) { 497 LOG_ERROR(LOG_TAG, "Failed to initialize gatt interface"); 498 return -1; 499 } 500 501 int status = pipe(pipefd); 502 if (status == -1) { 503 LOG_ERROR(LOG_TAG, "pipe creation failed: %s", strerror(errno)); 504 return -1; 505 } 506 507 return 0; 508 } 509 510 bt_status_t ServerInternals::AddCharacteristic( 511 const UUID& uuid, 512 int properties, 513 int permissions) { 514 bt_uuid_t c_uuid = uuid.GetBlueDroid(); 515 return gatt->server->add_characteristic( 516 server_if, service_handle, &c_uuid, properties, permissions); 517 } 518 519 ServerInternals::ServerInternals() 520 : gatt(nullptr), 521 server_if(0), 522 client_if(0), 523 service_handle(0), 524 pipefd{INVALID_FD, INVALID_FD} {} 525 526 ServerInternals::~ServerInternals() { 527 if (pipefd[0] != INVALID_FD) 528 close(pipefd[0]); 529 if (pipefd[1] != INVALID_FD) 530 close(pipefd[1]); 531 532 gatt->server->delete_service(server_if, service_handle); 533 gatt->server->unregister_server(server_if); 534 gatt->client->unregister_client(client_if); 535 } 536 537 Server::Server() : internal_(nullptr) {} 538 539 Server::~Server() {} 540 541 bool Server::Initialize(const UUID& service_id, int* gatt_pipe) { 542 internal_.reset(new ServerInternals); 543 if (!internal_) { 544 LOG_ERROR(LOG_TAG, "Error creating internals"); 545 return false; 546 } 547 g_internal = internal_.get(); 548 549 std::unique_lock<std::mutex> lock(internal_->lock); 550 int status = internal_->Initialize(); 551 if (status) { 552 LOG_ERROR(LOG_TAG, "Error initializing internals"); 553 return false; 554 } 555 556 bt_uuid_t uuid = service_id.GetBlueDroid(); 557 558 bt_status_t btstat = internal_->gatt->server->register_server(&uuid); 559 if (btstat != BT_STATUS_SUCCESS) { 560 LOG_ERROR(LOG_TAG, "Failed to register server"); 561 return false; 562 } 563 564 internal_->api_synchronize.wait(lock); 565 // TODO(icoolidge): Better error handling. 566 if (internal_->server_if == 0) { 567 LOG_ERROR(LOG_TAG, "Initialization of server failed"); 568 return false; 569 } 570 571 *gatt_pipe = internal_->pipefd[kPipeReadEnd]; 572 LOG_INFO(LOG_TAG, "Server Initialize succeeded"); 573 return true; 574 } 575 576 bool Server::SetAdvertisement(const std::vector<UUID>& ids, 577 const std::vector<uint8_t>& service_data, 578 const std::vector<uint8_t>& manufacturer_data, 579 bool transmit_name) { 580 std::vector<uint8_t> id_data; 581 auto mutable_manufacturer_data = manufacturer_data; 582 auto mutable_service_data = service_data; 583 584 for (const UUID &id : ids) { 585 const auto le_id = id.GetFullLittleEndian(); 586 id_data.insert(id_data.end(), le_id.begin(), le_id.end()); 587 } 588 589 std::lock_guard<std::mutex> lock(internal_->lock); 590 591 // Setup our advertisement. This has no callback. 592 bt_status_t btstat = internal_->gatt->client->set_adv_data( 593 internal_->client_if, false, /* beacon, not scan response */ 594 transmit_name, /* name */ 595 false, /* no txpower */ 596 2, 2, /* interval */ 597 0, /* appearance */ 598 mutable_manufacturer_data.size(), 599 reinterpret_cast<char *>(mutable_manufacturer_data.data()), 600 mutable_service_data.size(), 601 reinterpret_cast<char *>(mutable_service_data.data()), id_data.size(), 602 reinterpret_cast<char *>(id_data.data())); 603 if (btstat != BT_STATUS_SUCCESS) { 604 LOG_ERROR(LOG_TAG, "Failed to set advertising data"); 605 return false; 606 } 607 return true; 608 } 609 610 bool Server::SetScanResponse(const std::vector<UUID>& ids, 611 const std::vector<uint8_t>& service_data, 612 const std::vector<uint8_t>& manufacturer_data, 613 bool transmit_name) { 614 std::vector<uint8_t> id_data; 615 auto mutable_manufacturer_data = manufacturer_data; 616 auto mutable_service_data = service_data; 617 618 for (const UUID &id : ids) { 619 const auto le_id = id.GetFullLittleEndian(); 620 id_data.insert(id_data.end(), le_id.begin(), le_id.end()); 621 } 622 623 std::lock_guard<std::mutex> lock(internal_->lock); 624 625 // Setup our advertisement. This has no callback. 626 bt_status_t btstat = internal_->gatt->client->set_adv_data( 627 internal_->client_if, true, /* scan response */ 628 transmit_name, /* name */ 629 false, /* no txpower */ 630 2, 2, /* interval */ 631 0, /* appearance */ 632 mutable_manufacturer_data.size(), 633 reinterpret_cast<char *>(mutable_manufacturer_data.data()), 634 mutable_service_data.size(), 635 reinterpret_cast<char *>(mutable_service_data.data()), id_data.size(), 636 reinterpret_cast<char *>(id_data.data())); 637 if (btstat != BT_STATUS_SUCCESS) { 638 LOG_ERROR(LOG_TAG, "Failed to set scan response data"); 639 return false; 640 } 641 return true; 642 } 643 644 bool Server::AddCharacteristic( 645 const UUID &id, int properties, int permissions) { 646 std::unique_lock<std::mutex> lock(internal_->lock); 647 bt_status_t btstat = internal_->AddCharacteristic( 648 id, properties, permissions); 649 if (btstat != BT_STATUS_SUCCESS) { 650 LOG_ERROR(LOG_TAG, "Failed to add characteristic to service: 0x%04x", 651 internal_->service_handle); 652 return false; 653 } 654 internal_->api_synchronize.wait(lock); 655 const int handle = internal_->uuid_to_attribute[id]; 656 internal_->characteristics[handle].notify = properties & kPropertyNotify; 657 return true; 658 } 659 660 bool Server::AddBlob(const UUID &id, const UUID &control_id, int properties, 661 int permissions) { 662 std::unique_lock<std::mutex> lock(internal_->lock); 663 664 // First, add the primary attribute (characteristic value) 665 bt_status_t btstat = internal_->AddCharacteristic( 666 id, properties, permissions); 667 if (btstat != BT_STATUS_SUCCESS) { 668 LOG_ERROR(LOG_TAG, "Failed to set scan response data"); 669 return false; 670 } 671 672 internal_->api_synchronize.wait(lock); 673 674 // Next, add the secondary attribute (blob control). 675 // Control attributes have fixed permissions/properties. 676 btstat = internal_->AddCharacteristic( 677 control_id, 678 kPropertyRead | kPropertyWrite, 679 kPermissionRead | kPermissionWrite); 680 internal_->api_synchronize.wait(lock); 681 682 // Finally, associate the control attribute with the value attribute. 683 // Also, initialize the control attribute to a readable zero. 684 const int control_attribute = internal_->uuid_to_attribute[control_id]; 685 const int blob_attribute = internal_->uuid_to_attribute[id]; 686 internal_->controlled_blobs[control_attribute] = blob_attribute; 687 internal_->characteristics[blob_attribute].notify = 688 properties & kPropertyNotify; 689 690 Characteristic &ctrl = internal_->characteristics[control_attribute]; 691 ctrl.next_blob.clear(); 692 ctrl.next_blob.push_back(0); 693 ctrl.next_blob_pending = true; 694 ctrl.blob_section = 0; 695 ctrl.notify = false; 696 return true; 697 } 698 699 bool Server::Start() { 700 std::unique_lock<std::mutex> lock(internal_->lock); 701 bt_status_t btstat = internal_->gatt->server->start_service( 702 internal_->server_if, internal_->service_handle, GATT_TRANSPORT_LE); 703 if (btstat != BT_STATUS_SUCCESS) { 704 LOG_ERROR(LOG_TAG, "Failed to start service with handle: 0x%04x", 705 internal_->service_handle); 706 return false; 707 } 708 internal_->api_synchronize.wait(lock); 709 return true; 710 } 711 712 bool Server::Stop() { 713 std::unique_lock<std::mutex> lock(internal_->lock); 714 bt_status_t btstat = internal_->gatt->server->stop_service( 715 internal_->server_if, internal_->service_handle); 716 if (btstat != BT_STATUS_SUCCESS) { 717 LOG_ERROR(LOG_TAG, "Failed to stop service with handle: 0x%04x", 718 internal_->service_handle); 719 return false; 720 } 721 internal_->api_synchronize.wait(lock); 722 return true; 723 } 724 725 bool Server::ScanEnable() { 726 bt_status_t btstat = internal_->gatt->client->scan(true); 727 if (btstat) { 728 LOG_ERROR(LOG_TAG, "Enable scan failed: %d", btstat); 729 return false; 730 } 731 return true; 732 } 733 734 bool Server::ScanDisable() { 735 bt_status_t btstat = internal_->gatt->client->scan(false); 736 if (btstat) { 737 LOG_ERROR(LOG_TAG, "Disable scan failed: %d", btstat); 738 return false; 739 } 740 return true; 741 } 742 743 bool Server::GetScanResults(ScanResults *results) { 744 std::lock_guard<std::mutex> lock(internal_->lock); 745 *results = internal_->scan_results; 746 return true; 747 } 748 749 bool Server::SetCharacteristicValue(const UUID &id, 750 const std::vector<uint8_t> &value) { 751 std::lock_guard<std::mutex> lock(internal_->lock); 752 const int attribute_id = internal_->uuid_to_attribute[id]; 753 Characteristic &ch = internal_->characteristics[attribute_id]; 754 ch.next_blob = value; 755 ch.next_blob_pending = true; 756 757 if (!ch.notify) 758 return true; 759 760 for (auto connection : internal_->connections) { 761 char dummy = 0; 762 internal_->gatt->server->send_indication(internal_->server_if, 763 attribute_id, 764 connection, 765 sizeof(dummy), 766 true, 767 &dummy); 768 } 769 return true; 770 } 771 772 bool Server::GetCharacteristicValue(const UUID &id, std::vector<uint8_t> *value) { 773 std::lock_guard<std::mutex> lock(internal_->lock); 774 const int attribute_id = internal_->uuid_to_attribute[id]; 775 *value = internal_->characteristics[attribute_id].blob; 776 return true; 777 } 778 779 } // namespace gatt 780 } // namespace bluetooth 781