blob: 40db1117362ce1989853e519bdfb145cec9a62a6 [file] [log] [blame]
Ian Coolidge611fcf92015-06-03 17:20:30 -07001//
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//
Marie Janssen49a86702015-07-08 11:48:57 -070016
17#define LOG_TAG "bt_gatts"
18
Ian Coolidge611fcf92015-06-03 17:20:30 -070019#include "gatt_server.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
Ian Coolidge611fcf92015-06-03 17:20:30 -070036#include "core_stack.h"
37#include "hardware/bluetooth.h"
38#include "hardware/bt_gatt.h"
39#include "logging_helpers.h"
Marie Janssen49a86702015-07-08 11:48:57 -070040#include "osi/include/log.h"
Ian Coolidge611fcf92015-06-03 17:20:30 -070041#include "osi/include/osi.h"
42#include "uuid.h"
43
44namespace {
45
46const size_t kMaxGattAttributeSize = 512;
47// TODO(icoolidge): Difficult to generalize without knowing how many attributes.
48const int kNumBlueDroidHandles = 60;
49
50// TODO(icoolidge): Support multiple instances
Arman Ugurayf2d64342015-07-08 15:47:39 -070051// TODO(armansito): Remove this variable. No point of having this if
52// each bluetooth::gatt::Server instance already keeps a pointer to the
53// ServerInternals that is associated with it (which is much cleaner). It looks
54// like this variable exists because the btif callbacks don't allow the
55// upper-layer to pass user data to them. We could:
56//
57// 1. Fix the btif callbacks so that some sort of continuation can be
58// attached to a callback. This might be a long shot since the callback
59// interface doesn't allow more than one caller to register its own callbacks
60// (which might be what we want though, since this would make the API more
61// flexible).
62//
63// 2. Allow creation of Server objects using a factory method that returns
64// the result asynchronously in a base::Callback. The RegisterServerCallback
65// provides an |app_uuid|, which can be used to store callback structures in
66// a map and lazily instantiate the Server and invoke the correct callback.
67// This is a general pattern that we should use throughout the daemon, since
68// all operations can timeout or fail and this is best reported in an
69// asynchronous base::Callback.
70//
71static bluetooth::gatt::ServerInternals *g_internal = nullptr;
Ian Coolidge611fcf92015-06-03 17:20:30 -070072
73enum { kPipeReadEnd = 0, kPipeWriteEnd = 1, kPipeNumEnds = 2 };
74
75} // namespace
76
77namespace bluetooth {
78namespace gatt {
79
80struct Characteristic {
81 Uuid uuid;
82 int blob_section;
83 std::vector<uint8_t> blob;
84
85 // Support synchronized blob updates by latching under mutex.
86 std::vector<uint8_t> next_blob;
87 bool next_blob_pending;
88 bool notify;
89};
90
91struct ServerInternals {
92 ServerInternals();
93 ~ServerInternals();
94 int Initialize(CoreStack *bt);
Arman Ugurayf2d64342015-07-08 15:47:39 -070095 bt_status_t AddCharacteristic(
96 const Uuid& uuid,
97 int properties,
98 int permissions);
Ian Coolidge611fcf92015-06-03 17:20:30 -070099
100 // This maps API attribute UUIDs to BlueDroid handles.
101 std::map<Uuid, int> uuid_to_attribute;
102
103 // The attribute cache, indexed by BlueDroid handles.
104 std::unordered_map<int, Characteristic> characteristics;
105
106 // Associate a control attribute with its value attribute.
107 std::unordered_map<int, int> controlled_blobs;
108
109 ScanResults scan_results;
110
111 Uuid last_write;
112 const btgatt_interface_t *gatt;
113 int server_if;
114 int client_if;
115 int service_handle;
116 btgatt_srvc_id_t service_id;
117 std::set<int> connections;
118
119 std::mutex lock;
120 std::condition_variable api_synchronize;
121 int pipefd[kPipeNumEnds];
122};
123
124} // namespace gatt
125} // namespace bluetooth
126
127namespace {
128
129/** Callback invoked in response to register_server */
130void RegisterServerCallback(int status, int server_if, bt_uuid_t *app_uuid) {
Marie Janssen49120dc2015-07-07 16:47:20 -0700131 LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d app_uuid:%p", __func__, status,
Ian Coolidge611fcf92015-06-03 17:20:30 -0700132 server_if, app_uuid);
133
Arman Ugurayf2d64342015-07-08 15:47:39 -0700134 g_internal->server_if = server_if;
Ian Coolidge611fcf92015-06-03 17:20:30 -0700135
136 btgatt_srvc_id_t service_id;
137 service_id.id.uuid = *app_uuid;
138 service_id.id.inst_id = 0;
139 service_id.is_primary = true;
140
Arman Ugurayf2d64342015-07-08 15:47:39 -0700141 g_internal->gatt->server->add_service(
Ian Coolidge611fcf92015-06-03 17:20:30 -0700142 server_if, &service_id, kNumBlueDroidHandles);
143}
144
145void ServiceAddedCallback(int status, int server_if, btgatt_srvc_id_t *srvc_id,
146 int srvc_handle) {
Marie Janssen49120dc2015-07-07 16:47:20 -0700147 LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d gatt_srvc_id:%u srvc_handle:%d",
Ian Coolidge611fcf92015-06-03 17:20:30 -0700148 __func__, status, server_if, srvc_id->id.inst_id, srvc_handle);
149
Arman Ugurayf2d64342015-07-08 15:47:39 -0700150 std::lock_guard<std::mutex> lock(g_internal->lock);
151 g_internal->server_if = server_if;
152 g_internal->service_handle = srvc_handle;
153 g_internal->service_id = *srvc_id;
Ian Coolidge611fcf92015-06-03 17:20:30 -0700154 // This finishes the Initialize call.
Arman Ugurayf2d64342015-07-08 15:47:39 -0700155 g_internal->api_synchronize.notify_one();
Ian Coolidge611fcf92015-06-03 17:20:30 -0700156}
157
158void RequestReadCallback(int conn_id, int trans_id, bt_bdaddr_t *bda,
159 int attr_handle, int attribute_offset_octets,
160 bool is_long) {
Arman Ugurayf2d64342015-07-08 15:47:39 -0700161 std::lock_guard<std::mutex> lock(g_internal->lock);
Ian Coolidge611fcf92015-06-03 17:20:30 -0700162
Arman Ugurayf2d64342015-07-08 15:47:39 -0700163 bluetooth::gatt::Characteristic &ch = g_internal->characteristics[attr_handle];
Ian Coolidge611fcf92015-06-03 17:20:30 -0700164
165 // Latch next_blob to blob on a 'fresh' read.
166 if (ch.next_blob_pending && attribute_offset_octets == 0 &&
167 ch.blob_section == 0) {
168 std::swap(ch.blob, ch.next_blob);
169 ch.next_blob_pending = false;
170 }
171
172 const size_t blob_offset_octets =
173 std::min(ch.blob.size(), ch.blob_section * kMaxGattAttributeSize);
174 const size_t blob_remaining = ch.blob.size() - blob_offset_octets;
175 const size_t attribute_size = std::min(kMaxGattAttributeSize, blob_remaining);
176
177 std::string addr(BtAddrString(bda));
Marie Janssen49120dc2015-07-07 16:47:20 -0700178 LOG_INFO(LOG_TAG,
Ian Coolidge611fcf92015-06-03 17:20:30 -0700179 "%s: connection:%d (%s) reading attr:%d attribute_offset_octets:%d "
180 "blob_section:%u (is_long:%u)",
181 __func__, conn_id, addr.c_str(), attr_handle, attribute_offset_octets,
182 ch.blob_section, is_long);
183
184 btgatt_response_t response;
185 response.attr_value.len = 0;
186
187 if (attribute_offset_octets < static_cast<int>(attribute_size)) {
188 std::copy(ch.blob.begin() + blob_offset_octets + attribute_offset_octets,
189 ch.blob.begin() + blob_offset_octets + attribute_size,
190 response.attr_value.value);
191 response.attr_value.len = attribute_size - attribute_offset_octets;
192 }
193
194 response.attr_value.handle = attr_handle;
195 response.attr_value.offset = attribute_offset_octets;
196 response.attr_value.auth_req = 0;
Arman Ugurayf2d64342015-07-08 15:47:39 -0700197 g_internal->gatt->server->send_response(conn_id, trans_id, 0, &response);
Ian Coolidge611fcf92015-06-03 17:20:30 -0700198}
199
200void RequestWriteCallback(int conn_id, int trans_id, bt_bdaddr_t *bda,
201 int attr_handle, int attribute_offset, int length,
202 bool need_rsp, bool is_prep, uint8_t *value) {
203 std::string addr(BtAddrString(bda));
Marie Janssen49120dc2015-07-07 16:47:20 -0700204 LOG_INFO(LOG_TAG,
Ian Coolidge611fcf92015-06-03 17:20:30 -0700205 "%s: connection:%d (%s:trans:%d) write attr:%d attribute_offset:%d "
206 "length:%d "
207 "need_resp:%u is_prep:%u",
208 __func__, conn_id, addr.c_str(), trans_id, attr_handle, attribute_offset,
209 length, need_rsp, is_prep);
210
Arman Ugurayf2d64342015-07-08 15:47:39 -0700211 std::lock_guard<std::mutex> lock(g_internal->lock);
Ian Coolidge611fcf92015-06-03 17:20:30 -0700212
Arman Ugurayf2d64342015-07-08 15:47:39 -0700213 bluetooth::gatt::Characteristic &ch =
214 g_internal->characteristics[attr_handle];
Ian Coolidge611fcf92015-06-03 17:20:30 -0700215
216 ch.blob.resize(attribute_offset + length);
217
218 std::copy(value, value + length, ch.blob.begin() + attribute_offset);
219
Arman Ugurayf2d64342015-07-08 15:47:39 -0700220 auto target_blob = g_internal->controlled_blobs.find(attr_handle);
Ian Coolidge611fcf92015-06-03 17:20:30 -0700221 // If this is a control attribute, adjust offset of the target blob.
Arman Ugurayf2d64342015-07-08 15:47:39 -0700222 if (target_blob != g_internal->controlled_blobs.end() &&
223 ch.blob.size() == 1u) {
224 g_internal->characteristics[target_blob->second].blob_section = ch.blob[0];
Marie Janssen49120dc2015-07-07 16:47:20 -0700225 LOG_INFO(LOG_TAG, "%s: updating attribute %d blob_section to %u", __func__,
226 target_blob->second, ch.blob[0]);
Ian Coolidge611fcf92015-06-03 17:20:30 -0700227 } else if (!is_prep) {
228 // This is a single frame characteristic write.
229 // Notify upwards because we're done now.
230 const bluetooth::Uuid::Uuid128Bit &attr_uuid = ch.uuid.GetFullBigEndian();
Arman Ugurayf2d64342015-07-08 15:47:39 -0700231 int status = write(g_internal->pipefd[kPipeWriteEnd], attr_uuid.data(),
Ian Coolidge611fcf92015-06-03 17:20:30 -0700232 attr_uuid.size());
233 if (-1 == status)
Marie Janssendb554582015-06-26 14:53:46 -0700234 LOG_ERROR(LOG_TAG, "%s: write failed: %s", __func__, strerror(errno));
Ian Coolidge611fcf92015-06-03 17:20:30 -0700235 } else {
236 // This is a multi-frame characteristic write.
237 // Wait for an 'RequestExecWriteCallback' to notify completion.
Arman Ugurayf2d64342015-07-08 15:47:39 -0700238 g_internal->last_write = ch.uuid;
Ian Coolidge611fcf92015-06-03 17:20:30 -0700239 }
240
241 // Respond only if needed.
242 if (!need_rsp) return;
243
244 btgatt_response_t response;
245 response.attr_value.handle = attr_handle;
246 response.attr_value.offset = attribute_offset;
247 response.attr_value.len = length;
248 response.attr_value.auth_req = 0;
Ian Coolidgefd4745e2015-07-13 18:22:46 -0700249 // Provide written data back to sender for the response.
250 // Remote stacks use this to validate the success of the write.
251 std::copy(value, value + length, response.attr_value.value);
Arman Ugurayf2d64342015-07-08 15:47:39 -0700252 g_internal->gatt->server->send_response(conn_id, trans_id, 0, &response);
Ian Coolidge611fcf92015-06-03 17:20:30 -0700253}
254
255void RequestExecWriteCallback(int conn_id, int trans_id, bt_bdaddr_t *bda,
256 int exec_write) {
257 std::string addr(BtAddrString(bda));
Marie Janssen49120dc2015-07-07 16:47:20 -0700258 LOG_INFO(LOG_TAG, "%s: connection:%d (%s:trans:%d) exec_write:%d", __func__,
259 conn_id, addr.c_str(), trans_id, exec_write);
Ian Coolidge611fcf92015-06-03 17:20:30 -0700260
Ian Coolidgefd4745e2015-07-13 18:22:46 -0700261 // This 'response' data is unused for ExecWriteResponses.
262 // It is only used to pass BlueDroid argument validation.
263 btgatt_response_t response = {};
Arman Ugurayf2d64342015-07-08 15:47:39 -0700264 g_internal->gatt->server->send_response(conn_id, trans_id, 0, &response);
Ian Coolidgefd4745e2015-07-13 18:22:46 -0700265
Ian Coolidge611fcf92015-06-03 17:20:30 -0700266 if (!exec_write)
267 return;
268
Arman Ugurayf2d64342015-07-08 15:47:39 -0700269 std::lock_guard<std::mutex> lock(g_internal->lock);
Ian Coolidge611fcf92015-06-03 17:20:30 -0700270 // Communicate the attribute UUID as notification of a write update.
271 const bluetooth::Uuid::Uuid128Bit uuid =
Arman Ugurayf2d64342015-07-08 15:47:39 -0700272 g_internal->last_write.GetFullBigEndian();
273 int status = write(g_internal->pipefd[kPipeWriteEnd],
274 uuid.data(), uuid.size());
Ian Coolidge611fcf92015-06-03 17:20:30 -0700275 if (-1 == status)
Marie Janssendb554582015-06-26 14:53:46 -0700276 LOG_ERROR(LOG_TAG, "%s: write failed: %s", __func__, strerror(errno));
Ian Coolidge611fcf92015-06-03 17:20:30 -0700277}
278
279void ConnectionCallback(int conn_id, int server_if, int connected,
280 bt_bdaddr_t *bda) {
281 std::string addr(BtAddrString(bda));
Marie Janssen49120dc2015-07-07 16:47:20 -0700282 LOG_INFO(LOG_TAG, "%s: connection:%d server_if:%d connected:%d addr:%s",
283 __func__, conn_id, server_if, connected, addr.c_str());
Ian Coolidge611fcf92015-06-03 17:20:30 -0700284 if (connected == 1) {
Arman Ugurayf2d64342015-07-08 15:47:39 -0700285 g_internal->connections.insert(conn_id);
Ian Coolidge611fcf92015-06-03 17:20:30 -0700286 } else if (connected == 0) {
Arman Ugurayf2d64342015-07-08 15:47:39 -0700287 g_internal->connections.erase(conn_id);
Ian Coolidge611fcf92015-06-03 17:20:30 -0700288 }
289}
290
291void CharacteristicAddedCallback(int status, int server_if, bt_uuid_t *uuid,
292 int srvc_handle, int char_handle) {
Marie Janssen49120dc2015-07-07 16:47:20 -0700293 LOG_INFO(LOG_TAG,
Arman Ugurayf2d64342015-07-08 15:47:39 -0700294 "%s: status:%d server_if:%d service_handle:%d char_handle:%d", __func__,
Marie Janssen49120dc2015-07-07 16:47:20 -0700295 status, server_if, srvc_handle, char_handle);
Ian Coolidge611fcf92015-06-03 17:20:30 -0700296
297 bluetooth::Uuid id(*uuid);
298
Arman Ugurayf2d64342015-07-08 15:47:39 -0700299 std::lock_guard<std::mutex> lock(g_internal->lock);
Ian Coolidge611fcf92015-06-03 17:20:30 -0700300
Arman Ugurayf2d64342015-07-08 15:47:39 -0700301 g_internal->uuid_to_attribute[id] = char_handle;
302 g_internal->characteristics[char_handle].uuid = id;
303 g_internal->characteristics[char_handle].blob_section = 0;
Ian Coolidge611fcf92015-06-03 17:20:30 -0700304
305 // This terminates an AddCharacteristic.
Arman Ugurayf2d64342015-07-08 15:47:39 -0700306 g_internal->api_synchronize.notify_one();
Ian Coolidge611fcf92015-06-03 17:20:30 -0700307}
308
309void DescriptorAddedCallback(int status, int server_if, bt_uuid_t *uuid,
310 int srvc_handle, int descr_handle) {
Marie Janssen49120dc2015-07-07 16:47:20 -0700311 LOG_INFO(LOG_TAG,
Ian Coolidge611fcf92015-06-03 17:20:30 -0700312 "%s: status:%d server_if:%d service_handle:%d uuid[0]:%u "
313 "descr_handle:%d",
314 __func__, status, server_if, srvc_handle, uuid->uu[0], descr_handle);
315}
316
317void ServiceStartedCallback(int status, int server_if, int srvc_handle) {
Marie Janssen49120dc2015-07-07 16:47:20 -0700318 LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d srvc_handle:%d", __func__,
319 status, server_if, srvc_handle);
Ian Coolidge611fcf92015-06-03 17:20:30 -0700320
321 // The UUID provided here is unimportant, and is only used to satisfy
322 // BlueDroid.
323 // It must be different than any other registered UUID.
Arman Ugurayf2d64342015-07-08 15:47:39 -0700324 bt_uuid_t client_id = g_internal->service_id.id.uuid;
Ian Coolidge611fcf92015-06-03 17:20:30 -0700325 ++client_id.uu[15];
326
Arman Ugurayf2d64342015-07-08 15:47:39 -0700327 bt_status_t btstat = g_internal->gatt->client->register_client(&client_id);
Ian Coolidge611fcf92015-06-03 17:20:30 -0700328 if (btstat != BT_STATUS_SUCCESS) {
Marie Janssendb554582015-06-26 14:53:46 -0700329 LOG_ERROR(LOG_TAG, "%s: Failed to register client", __func__);
Ian Coolidge611fcf92015-06-03 17:20:30 -0700330 }
331}
332
333void RegisterClientCallback(int status, int client_if, bt_uuid_t *app_uuid) {
Marie Janssen49120dc2015-07-07 16:47:20 -0700334 LOG_INFO(LOG_TAG, "%s: status:%d client_if:%d uuid[0]:%u", __func__, status,
335 client_if, app_uuid->uu[0]);
Arman Ugurayf2d64342015-07-08 15:47:39 -0700336 g_internal->client_if = client_if;
Ian Coolidge611fcf92015-06-03 17:20:30 -0700337
338 // Setup our advertisement. This has no callback.
Arman Ugurayf2d64342015-07-08 15:47:39 -0700339 bt_status_t btstat = g_internal->gatt->client->set_adv_data(
Ian Coolidge611fcf92015-06-03 17:20:30 -0700340 client_if, false, /* beacon, not scan response */
341 false, /* name */
342 false, /* no txpower */
343 2, 2, /* interval */
344 0, /* appearance */
345 0, nullptr, /* no mfg data */
346 0, nullptr, /* no service data */
347 0, nullptr /* no service id yet */);
348 if (btstat != BT_STATUS_SUCCESS) {
Marie Janssendb554582015-06-26 14:53:46 -0700349 LOG_ERROR(LOG_TAG, "Failed to set advertising data");
Ian Coolidge611fcf92015-06-03 17:20:30 -0700350 return;
351 }
352
353 // TODO(icoolidge): Deprecated, use multi-adv interface.
354 // This calls back to ListenCallback.
Arman Ugurayf2d64342015-07-08 15:47:39 -0700355 btstat = g_internal->gatt->client->listen(client_if, true);
Ian Coolidge611fcf92015-06-03 17:20:30 -0700356 if (btstat != BT_STATUS_SUCCESS) {
Marie Janssendb554582015-06-26 14:53:46 -0700357 LOG_ERROR(LOG_TAG, "Failed to start listening");
Ian Coolidge611fcf92015-06-03 17:20:30 -0700358 }
359}
360
361void ListenCallback(int status, int client_if) {
Marie Janssen49120dc2015-07-07 16:47:20 -0700362 LOG_INFO(LOG_TAG, "%s: status:%d client_if:%d", __func__, status, client_if);
Ian Coolidge611fcf92015-06-03 17:20:30 -0700363 // This terminates a Start call.
Arman Ugurayf2d64342015-07-08 15:47:39 -0700364 std::lock_guard<std::mutex> lock(g_internal->lock);
365 g_internal->api_synchronize.notify_one();
Ian Coolidge611fcf92015-06-03 17:20:30 -0700366}
367
368void ServiceStoppedCallback(int status, int server_if, int srvc_handle) {
Arman Ugurayf2d64342015-07-08 15:47:39 -0700369 LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d srvc_handle:%d", __func__,
Marie Janssen49120dc2015-07-07 16:47:20 -0700370 status, server_if, srvc_handle);
Ian Coolidge611fcf92015-06-03 17:20:30 -0700371 // This terminates a Stop call.
372 // TODO(icoolidge): make this symmetric with start
Arman Ugurayf2d64342015-07-08 15:47:39 -0700373 std::lock_guard<std::mutex> lock(g_internal->lock);
374 g_internal->api_synchronize.notify_one();
Ian Coolidge611fcf92015-06-03 17:20:30 -0700375}
376
377void ScanResultCallback(bt_bdaddr_t *bda, int rssi, uint8_t *adv_data) {
378 std::string addr(BtAddrString(bda));
379 (void)adv_data;
Arman Ugurayf2d64342015-07-08 15:47:39 -0700380 std::lock_guard<std::mutex> lock(g_internal->lock);
381 g_internal->scan_results[addr] = rssi;
Ian Coolidge611fcf92015-06-03 17:20:30 -0700382}
383
384void ClientConnectCallback(int conn_id, int status, int client_if,
385 bt_bdaddr_t *bda) {
386 std::string addr(BtAddrString(bda));
Arman Ugurayf2d64342015-07-08 15:47:39 -0700387 LOG_INFO(LOG_TAG, "%s: conn_id:%d status:%d client_if:%d %s", __func__,
Marie Janssen49120dc2015-07-07 16:47:20 -0700388 conn_id, status, client_if, addr.c_str());
Ian Coolidge611fcf92015-06-03 17:20:30 -0700389}
390
391void ClientDisconnectCallback(int conn_id, int status, int client_if,
392 bt_bdaddr_t *bda) {
393 std::string addr(BtAddrString(bda));
Marie Janssen49120dc2015-07-07 16:47:20 -0700394 LOG_INFO(LOG_TAG, "%s: conn_id:%d status:%d client_if:%d %s", __func__,
395 conn_id, status, client_if, addr.c_str());
Ian Coolidge611fcf92015-06-03 17:20:30 -0700396}
397
398void IndicationSentCallback(UNUSED_ATTR int conn_id,
399 UNUSED_ATTR int status) {
400 // TODO(icoolidge): what to do
401}
402
403void ResponseConfirmationCallback(UNUSED_ATTR int status,
404 UNUSED_ATTR int handle) {
405 // TODO(icoolidge): what to do
406}
407
408const btgatt_server_callbacks_t gatt_server_callbacks = {
409 RegisterServerCallback,
410 ConnectionCallback,
411 ServiceAddedCallback,
412 nullptr, /* included_service_added_cb */
413 CharacteristicAddedCallback,
414 DescriptorAddedCallback,
415 ServiceStartedCallback,
416 ServiceStoppedCallback,
417 nullptr, /* service_deleted_cb */
418 RequestReadCallback,
419 RequestWriteCallback,
420 RequestExecWriteCallback,
421 ResponseConfirmationCallback,
422 IndicationSentCallback,
423 nullptr, /* congestion_cb*/
424 nullptr, /* mtu_changed_cb */
425};
426
427// TODO(eisenbach): Refactor GATT interface to not require servers
428// to refer to the client interface.
429const btgatt_client_callbacks_t gatt_client_callbacks = {
430 RegisterClientCallback,
431 ScanResultCallback,
432 ClientConnectCallback,
433 ClientDisconnectCallback,
434 nullptr, /* search_complete_cb; */
435 nullptr, /* search_result_cb; */
436 nullptr, /* get_characteristic_cb; */
437 nullptr, /* get_descriptor_cb; */
438 nullptr, /* get_included_service_cb; */
439 nullptr, /* register_for_notification_cb; */
440 nullptr, /* notify_cb; */
441 nullptr, /* read_characteristic_cb; */
442 nullptr, /* write_characteristic_cb; */
443 nullptr, /* read_descriptor_cb; */
444 nullptr, /* write_descriptor_cb; */
445 nullptr, /* execute_write_cb; */
446 nullptr, /* read_remote_rssi_cb; */
447 ListenCallback,
448 nullptr, /* configure_mtu_cb; */
449 nullptr, /* scan_filter_cfg_cb; */
450 nullptr, /* scan_filter_param_cb; */
451 nullptr, /* scan_filter_status_cb; */
452 nullptr, /* multi_adv_enable_cb */
453 nullptr, /* multi_adv_update_cb; */
454 nullptr, /* multi_adv_data_cb*/
455 nullptr, /* multi_adv_disable_cb; */
456 nullptr, /* congestion_cb; */
457 nullptr, /* batchscan_cfg_storage_cb; */
458 nullptr, /* batchscan_enb_disable_cb; */
459 nullptr, /* batchscan_reports_cb; */
460 nullptr, /* batchscan_threshold_cb; */
461 nullptr, /* track_adv_event_cb; */
Ian Coolidgefd8fdca2015-06-10 20:34:43 -0700462 nullptr, /* scan_parameter_setup_completed_cb; */
Ian Coolidge611fcf92015-06-03 17:20:30 -0700463};
464
465const btgatt_callbacks_t gatt_callbacks = {
466 /** Set to sizeof(btgatt_callbacks_t) */
467 sizeof(btgatt_callbacks_t),
468
469 /** GATT Client callbacks */
470 &gatt_client_callbacks,
471
472 /** GATT Server callbacks */
473 &gatt_server_callbacks};
474
475} // namespace
476
477namespace bluetooth {
478namespace gatt {
479
480int ServerInternals::Initialize(CoreStack *bt) {
481 // Get the interface to the GATT profile.
482 gatt = reinterpret_cast<const btgatt_interface_t *>(
483 bt->GetInterface(BT_PROFILE_GATT_ID));
484 if (!gatt) {
Marie Janssendb554582015-06-26 14:53:46 -0700485 LOG_ERROR(LOG_TAG, "Error getting GATT interface");
Ian Coolidge611fcf92015-06-03 17:20:30 -0700486 return -1;
487 }
488
489 bt_status_t btstat = gatt->init(&gatt_callbacks);
490 if (btstat != BT_STATUS_SUCCESS) {
Marie Janssendb554582015-06-26 14:53:46 -0700491 LOG_ERROR(LOG_TAG, "Failed to initialize gatt interface");
Ian Coolidge611fcf92015-06-03 17:20:30 -0700492 return -1;
493 }
494
495 int status = pipe(pipefd);
496 if (status == -1) {
Marie Janssendb554582015-06-26 14:53:46 -0700497 LOG_ERROR(LOG_TAG, "pipe creation failed: %s", strerror(errno));
Ian Coolidge611fcf92015-06-03 17:20:30 -0700498 return -1;
499 }
500
501 return 0;
502}
503
Arman Ugurayf2d64342015-07-08 15:47:39 -0700504bt_status_t ServerInternals::AddCharacteristic(
505 const Uuid& uuid,
506 int properties,
507 int permissions) {
508 bt_uuid_t c_uuid = uuid.GetBlueDroid();
509 return gatt->server->add_characteristic(
510 server_if, service_handle, &c_uuid, properties, permissions);
511}
512
Ian Coolidge611fcf92015-06-03 17:20:30 -0700513ServerInternals::ServerInternals()
514 : gatt(nullptr),
515 server_if(0),
516 client_if(0),
517 service_handle(0),
518 pipefd{INVALID_FD, INVALID_FD} {}
519
520ServerInternals::~ServerInternals() {
521 if (pipefd[0] != INVALID_FD)
522 close(pipefd[0]);
523 if (pipefd[1] != INVALID_FD)
524 close(pipefd[1]);
Ian Coolidgefd4745e2015-07-13 18:22:46 -0700525
526 gatt->server->delete_service(server_if, service_handle);
527 gatt->server->unregister_server(server_if);
528 gatt->client->unregister_client(client_if);
Ian Coolidge611fcf92015-06-03 17:20:30 -0700529}
530
531Server::Server() : internal_(nullptr) {}
532
533Server::~Server() {}
534
535bool Server::Initialize(const Uuid &service_id, int *gatt_pipe, CoreStack *bt) {
536 internal_.reset(new ServerInternals);
537 if (!internal_) {
Marie Janssendb554582015-06-26 14:53:46 -0700538 LOG_ERROR(LOG_TAG, "Error creating internals");
Ian Coolidge611fcf92015-06-03 17:20:30 -0700539 return false;
540 }
Arman Ugurayf2d64342015-07-08 15:47:39 -0700541 g_internal = internal_.get();
Ian Coolidge611fcf92015-06-03 17:20:30 -0700542
543 std::unique_lock<std::mutex> lock(internal_->lock);
544 int status = internal_->Initialize(bt);
545 if (status) {
Marie Janssendb554582015-06-26 14:53:46 -0700546 LOG_ERROR(LOG_TAG, "Error initializing internals");
Ian Coolidge611fcf92015-06-03 17:20:30 -0700547 return false;
548 }
549
550 bt_uuid_t uuid = service_id.GetBlueDroid();
551
552 bt_status_t btstat = internal_->gatt->server->register_server(&uuid);
553 if (btstat != BT_STATUS_SUCCESS) {
Marie Janssendb554582015-06-26 14:53:46 -0700554 LOG_ERROR(LOG_TAG, "Failed to register server");
Ian Coolidge611fcf92015-06-03 17:20:30 -0700555 return false;
556 }
557
558 internal_->api_synchronize.wait(lock);
559 // TODO(icoolidge): Better error handling.
560 if (internal_->server_if == 0) {
Marie Janssendb554582015-06-26 14:53:46 -0700561 LOG_ERROR(LOG_TAG, "Initialization of server failed");
Ian Coolidge611fcf92015-06-03 17:20:30 -0700562 return false;
563 }
564
565 *gatt_pipe = internal_->pipefd[kPipeReadEnd];
Marie Janssen49120dc2015-07-07 16:47:20 -0700566 LOG_INFO(LOG_TAG, "Server Initialize succeeded");
Ian Coolidge611fcf92015-06-03 17:20:30 -0700567 return true;
568}
569
570bool Server::SetAdvertisement(const std::vector<Uuid> &ids,
571 const std::vector<uint8_t> &service_data,
572 bool transmit_name) {
573 std::vector<uint8_t> id_data;
574 auto mutable_service_data = service_data;
575
576 for (const Uuid &id : ids) {
577 const auto le_id = id.GetFullLittleEndian();
578 id_data.insert(id_data.end(), le_id.begin(), le_id.end());
579 }
580
581 std::lock_guard<std::mutex> lock(internal_->lock);
582
583 // Setup our advertisement. This has no callback.
Arman Ugurayf2d64342015-07-08 15:47:39 -0700584 bt_status_t btstat = internal_->gatt->client->set_adv_data(
Ian Coolidge611fcf92015-06-03 17:20:30 -0700585 internal_->client_if, false, /* beacon, not scan response */
586 transmit_name, /* name */
587 false, /* no txpower */
588 2, 2, /* interval */
589 0, /* appearance */
590 0, nullptr, /* no mfg data */
591 mutable_service_data.size(),
592 reinterpret_cast<char *>(mutable_service_data.data()), id_data.size(),
593 reinterpret_cast<char *>(id_data.data()));
594 if (btstat != BT_STATUS_SUCCESS) {
Marie Janssendb554582015-06-26 14:53:46 -0700595 LOG_ERROR(LOG_TAG, "Failed to set advertising data");
Ian Coolidge611fcf92015-06-03 17:20:30 -0700596 return false;
597 }
598 return true;
599}
600
601bool Server::SetScanResponse(const std::vector<Uuid> &ids,
602 const std::vector<uint8_t> &service_data,
603 bool transmit_name) {
604 std::vector<uint8_t> id_data;
605 auto mutable_service_data = service_data;
606
607 for (const Uuid &id : ids) {
608 const auto le_id = id.GetFullLittleEndian();
609 id_data.insert(id_data.end(), le_id.begin(), le_id.end());
610 }
611
612 std::lock_guard<std::mutex> lock(internal_->lock);
613
614 // Setup our advertisement. This has no callback.
Arman Ugurayf2d64342015-07-08 15:47:39 -0700615 bt_status_t btstat = internal_->gatt->client->set_adv_data(
Ian Coolidge611fcf92015-06-03 17:20:30 -0700616 internal_->client_if, true, /* scan response */
617 transmit_name, /* name */
618 false, /* no txpower */
619 2, 2, /* interval */
620 0, /* appearance */
621 0, nullptr, /* no mfg data */
622 mutable_service_data.size(),
623 reinterpret_cast<char *>(mutable_service_data.data()), id_data.size(),
624 reinterpret_cast<char *>(id_data.data()));
625 if (btstat != BT_STATUS_SUCCESS) {
Marie Janssendb554582015-06-26 14:53:46 -0700626 LOG_ERROR(LOG_TAG, "Failed to set scan response data");
Ian Coolidge611fcf92015-06-03 17:20:30 -0700627 return false;
628 }
629 return true;
630}
631
Arman Ugurayf2d64342015-07-08 15:47:39 -0700632bool Server::AddCharacteristic(
633 const Uuid &id, int properties, int permissions) {
634 std::unique_lock<std::mutex> lock(internal_->lock);
635 bt_status_t btstat = internal_->AddCharacteristic(
636 id, properties, permissions);
637 if (btstat != BT_STATUS_SUCCESS) {
638 LOG_ERROR(LOG_TAG, "Failed to add characteristic to service: 0x%04x",
639 internal_->service_handle);
640 return false;
641 }
Ian Coolidge611fcf92015-06-03 17:20:30 -0700642 internal_->api_synchronize.wait(lock);
Arman Ugurayf2d64342015-07-08 15:47:39 -0700643 const int handle = internal_->uuid_to_attribute[id];
644 internal_->characteristics[handle].notify = properties & kPropertyNotify;
Ian Coolidge611fcf92015-06-03 17:20:30 -0700645 return true;
646}
647
648bool Server::AddBlob(const Uuid &id, const Uuid &control_id, int properties,
649 int permissions) {
Arman Ugurayf2d64342015-07-08 15:47:39 -0700650 std::unique_lock<std::mutex> lock(internal_->lock);
Ian Coolidge611fcf92015-06-03 17:20:30 -0700651
652 // First, add the primary attribute (characteristic value)
Arman Ugurayf2d64342015-07-08 15:47:39 -0700653 bt_status_t btstat = internal_->AddCharacteristic(
654 id, properties, permissions);
655 if (btstat != BT_STATUS_SUCCESS) {
656 LOG_ERROR(LOG_TAG, "Failed to set scan response data");
657 return false;
658 }
659
660 internal_->api_synchronize.wait(lock);
Ian Coolidge611fcf92015-06-03 17:20:30 -0700661
662 // Next, add the secondary attribute (blob control).
663 // Control attributes have fixed permissions/properties.
Arman Ugurayf2d64342015-07-08 15:47:39 -0700664 btstat = internal_->AddCharacteristic(
665 control_id,
666 kPermissionRead | kPermissionWrite,
667 kPropertyRead | kPropertyWrite);
668 internal_->api_synchronize.wait(lock);
Ian Coolidge611fcf92015-06-03 17:20:30 -0700669
670 // Finally, associate the control attribute with the value attribute.
671 // Also, initialize the control attribute to a readable zero.
Arman Ugurayf2d64342015-07-08 15:47:39 -0700672 const int control_attribute = internal_->uuid_to_attribute[control_id];
673 const int blob_attribute = internal_->uuid_to_attribute[id];
674 internal_->controlled_blobs[control_attribute] = blob_attribute;
675 internal_->characteristics[blob_attribute].notify =
676 properties & kPropertyNotify;
Ian Coolidge611fcf92015-06-03 17:20:30 -0700677
Arman Ugurayf2d64342015-07-08 15:47:39 -0700678 Characteristic &ctrl = internal_->characteristics[control_attribute];
Ian Coolidge611fcf92015-06-03 17:20:30 -0700679 ctrl.next_blob.clear();
680 ctrl.next_blob.push_back(0);
681 ctrl.next_blob_pending = true;
682 ctrl.blob_section = 0;
683 ctrl.notify = false;
684 return true;
685}
686
687bool Server::Start() {
688 std::unique_lock<std::mutex> lock(internal_->lock);
689 bt_status_t btstat = internal_->gatt->server->start_service(
690 internal_->server_if, internal_->service_handle, GATT_TRANSPORT_LE);
Arman Ugurayf2d64342015-07-08 15:47:39 -0700691 if (btstat != BT_STATUS_SUCCESS) {
692 LOG_ERROR(LOG_TAG, "Failed to start service with handle: 0x%04x",
693 internal_->service_handle);
694 return false;
695 }
Ian Coolidge611fcf92015-06-03 17:20:30 -0700696 internal_->api_synchronize.wait(lock);
697 return true;
698}
699
700bool Server::Stop() {
701 std::unique_lock<std::mutex> lock(internal_->lock);
702 bt_status_t btstat = internal_->gatt->server->stop_service(
703 internal_->server_if, internal_->service_handle);
Arman Ugurayf2d64342015-07-08 15:47:39 -0700704 if (btstat != BT_STATUS_SUCCESS) {
705 LOG_ERROR(LOG_TAG, "Failed to stop service with handle: 0x%04x",
706 internal_->service_handle);
707 return false;
708 }
Ian Coolidge611fcf92015-06-03 17:20:30 -0700709 internal_->api_synchronize.wait(lock);
710 return true;
711}
712
713bool Server::ScanEnable() {
714 bt_status_t btstat = internal_->gatt->client->scan(true);
715 if (btstat) {
Marie Janssendb554582015-06-26 14:53:46 -0700716 LOG_ERROR(LOG_TAG, "Enable scan failed: %d", btstat);
Ian Coolidge611fcf92015-06-03 17:20:30 -0700717 return false;
718 }
719 return true;
720}
721
722bool Server::ScanDisable() {
723 bt_status_t btstat = internal_->gatt->client->scan(false);
724 if (btstat) {
Marie Janssendb554582015-06-26 14:53:46 -0700725 LOG_ERROR(LOG_TAG, "Disable scan failed: %d", btstat);
Ian Coolidge611fcf92015-06-03 17:20:30 -0700726 return false;
727 }
728 return true;
729}
730
731bool Server::GetScanResults(ScanResults *results) {
732 std::lock_guard<std::mutex> lock(internal_->lock);
733 *results = internal_->scan_results;
734 return true;
735}
736
737bool Server::SetCharacteristicValue(const Uuid &id,
738 const std::vector<uint8_t> &value) {
Arman Ugurayf2d64342015-07-08 15:47:39 -0700739 std::lock_guard<std::mutex> lock(internal_->lock);
740 const int attribute_id = internal_->uuid_to_attribute[id];
741 Characteristic &ch = internal_->characteristics[attribute_id];
Ian Coolidge611fcf92015-06-03 17:20:30 -0700742 ch.next_blob = value;
743 ch.next_blob_pending = true;
744
745 if (!ch.notify)
746 return true;
747
Arman Ugurayf2d64342015-07-08 15:47:39 -0700748 for (auto connection : internal_->connections) {
Ian Coolidge611fcf92015-06-03 17:20:30 -0700749 char dummy = 0;
Arman Ugurayf2d64342015-07-08 15:47:39 -0700750 internal_->gatt->server->send_indication(internal_->server_if,
Ian Coolidge611fcf92015-06-03 17:20:30 -0700751 attribute_id,
752 connection,
753 sizeof(dummy),
754 true,
755 &dummy);
756 }
757 return true;
758}
759
760bool Server::GetCharacteristicValue(const Uuid &id, std::vector<uint8_t> *value) {
761 std::lock_guard<std::mutex> lock(internal_->lock);
762 const int attribute_id = internal_->uuid_to_attribute[id];
763 *value = internal_->characteristics[attribute_id].blob;
764 return true;
765}
766
767} // namespace gatt
768} // namespace bluetooth