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