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
42extern "C" {
43#include "osi/include/log.h"
44#include "osi/include/osi.h"
45}  // extern "C"
46
47namespace {
48
49const size_t kMaxGattAttributeSize = 512;
50// TODO(icoolidge): Difficult to generalize without knowing how many attributes.
51const 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//
74static bluetooth::gatt::ServerInternals *g_internal = nullptr;
75
76enum { kPipeReadEnd = 0, kPipeWriteEnd = 1, kPipeNumEnds = 2 };
77
78}  // namespace
79
80namespace bluetooth {
81namespace gatt {
82
83struct 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
94struct 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
130namespace {
131
132/** Callback invoked in response to register_server */
133void 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
148void 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
161void 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
203void 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
259void 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
284void 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
296void 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
314void 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
322void 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
338void 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
366void 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
373void 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
382void 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
389void 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
396void 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
403void IndicationSentCallback(UNUSED_ATTR int conn_id,
404                            UNUSED_ATTR int status) {
405  // TODO(icoolidge): what to do
406}
407
408void ResponseConfirmationCallback(UNUSED_ATTR int status,
409                                  UNUSED_ATTR int handle) {
410  // TODO(icoolidge): what to do
411}
412
413const 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.
434const 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
469const 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
481namespace bluetooth {
482namespace gatt {
483
484int 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
510bt_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
519ServerInternals::ServerInternals()
520    : gatt(nullptr),
521      server_if(0),
522      client_if(0),
523      service_handle(0),
524      pipefd{INVALID_FD, INVALID_FD} {}
525
526ServerInternals::~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
537Server::Server() : internal_(nullptr) {}
538
539Server::~Server() {}
540
541bool 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
576bool 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
610bool 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
644bool 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
660bool 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
699bool 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
712bool 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
725bool 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
734bool 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
743bool Server::GetScanResults(ScanResults *results) {
744  std::lock_guard<std::mutex> lock(internal_->lock);
745  *results = internal_->scan_results;
746  return true;
747}
748
749bool 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
772bool 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