Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 1 | // |
Jakub Pawlowski | 5b790fe | 2017-09-18 09:00:20 -0700 | [diff] [blame] | 2 | // Copyright 2015 Google, Inc. |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 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 | |
Jakub Pawlowski | a8d73ef | 2016-10-31 11:15:20 -0700 | [diff] [blame] | 25 | #include <base/bind.h> |
Jakub Pawlowski | 67f5f37 | 2018-07-23 10:00:25 -0700 | [diff] [blame] | 26 | #include <base/bind_helpers.h> |
| 27 | #include <base/callback.h> |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 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> |
Jakub Pawlowski | a641b6f | 2016-03-26 00:47:23 -0700 | [diff] [blame] | 37 | #include <unordered_set> |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 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" |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 45 | |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 46 | #include "osi/include/log.h" |
| 47 | #include "osi/include/osi.h" |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 48 | |
| 49 | namespace { |
| 50 | |
| 51 | const size_t kMaxGattAttributeSize = 512; |
Jakub Pawlowski | a641b6f | 2016-03-26 00:47:23 -0700 | [diff] [blame] | 52 | std::vector<btgatt_db_element_t> pending_svc_decl; |
| 53 | std::unordered_set<int> blob_index; |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 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 | // |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 76 | static bluetooth::gatt::ServerInternals* g_internal = nullptr; |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 77 | |
| 78 | enum { kPipeReadEnd = 0, kPipeWriteEnd = 1, kPipeNumEnds = 2 }; |
| 79 | |
| 80 | } // namespace |
| 81 | |
| 82 | namespace bluetooth { |
| 83 | namespace gatt { |
| 84 | |
| 85 | struct Characteristic { |
Jakub Pawlowski | 819e2ec | 2017-07-10 09:56:09 -0700 | [diff] [blame] | 86 | Uuid uuid; |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 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(); |
Jakub Pawlowski | 819e2ec | 2017-07-10 09:56:09 -0700 | [diff] [blame] | 100 | bt_status_t AddCharacteristic(const Uuid& uuid, uint8_t properties, |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 101 | uint16_t permissions); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 102 | |
Jakub Pawlowski | 819e2ec | 2017-07-10 09:56:09 -0700 | [diff] [blame] | 103 | // This maps API attribute Uuids to BlueDroid handles. |
| 104 | std::map<Uuid, int> uuid_to_attribute; |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 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 | |
Jakub Pawlowski | 819e2ec | 2017-07-10 09:56:09 -0700 | [diff] [blame] | 114 | Uuid last_write; |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 115 | const btgatt_interface_t* gatt; |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 116 | int server_if; |
| 117 | int client_if; |
| 118 | int service_handle; |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 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 */ |
Jakub Pawlowski | 96ac0a3 | 2017-06-21 00:00:18 -0700 | [diff] [blame] | 132 | void RegisterServerCallback(int status, int server_if, |
Jakub Pawlowski | 819e2ec | 2017-07-10 09:56:09 -0700 | [diff] [blame] | 133 | const bluetooth::Uuid& app_uuid) { |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 134 | LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d app_uuid:%p", __func__, status, |
Jakub Pawlowski | 96ac0a3 | 2017-06-21 00:00:18 -0700 | [diff] [blame] | 135 | server_if, &app_uuid); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 136 | |
| 137 | g_internal->server_if = server_if; |
Jakub Pawlowski | 819e2ec | 2017-07-10 09:56:09 -0700 | [diff] [blame] | 138 | |
Nick Desaulniers | 7ee5835 | 2019-10-09 11:06:55 -0700 | [diff] [blame] | 139 | pending_svc_decl.push_back({ |
| 140 | .uuid = app_uuid, |
| 141 | .type = BTGATT_DB_PRIMARY_SERVICE, |
| 142 | }); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 143 | } |
| 144 | |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 145 | void ServiceAddedCallback(int status, int server_if, |
Pavlin Radoslavov | b324a8d | 2016-12-09 17:50:59 -0800 | [diff] [blame] | 146 | std::vector<btgatt_db_element_t> service) { |
Jakub Pawlowski | a641b6f | 2016-03-26 00:47:23 -0700 | [diff] [blame] | 147 | LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d count:%zu svc_handle:%d", |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 148 | __func__, status, server_if, service.size(), |
| 149 | service[0].attribute_handle); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 150 | |
| 151 | std::lock_guard<std::mutex> lock(g_internal->lock); |
| 152 | g_internal->server_if = server_if; |
Jakub Pawlowski | a641b6f | 2016-03-26 00:47:23 -0700 | [diff] [blame] | 153 | |
| 154 | g_internal->service_handle = service[0].attribute_handle; |
| 155 | |
| 156 | uint16_t prev_char_handle = 0; |
| 157 | uint16_t prev_char_properties = 0; |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 158 | for (size_t i = 1; i < service.size(); i++) { |
| 159 | const btgatt_db_element_t& el = service[i]; |
Jakub Pawlowski | aeafd39 | 2016-09-19 10:38:20 -0700 | [diff] [blame] | 160 | if (el.type == BTGATT_DB_DESCRIPTOR) { |
Jakub Pawlowski | a641b6f | 2016-03-26 00:47:23 -0700 | [diff] [blame] | 161 | LOG_INFO(LOG_TAG, "%s: descr_handle:%d", __func__, el.attribute_handle); |
| 162 | } else if (el.type == BTGATT_DB_CHARACTERISTIC) { |
Jakub Pawlowski | 819e2ec | 2017-07-10 09:56:09 -0700 | [diff] [blame] | 163 | bluetooth::Uuid id(el.uuid); |
Jakub Pawlowski | a641b6f | 2016-03-26 00:47:23 -0700 | [diff] [blame] | 164 | uint16_t char_handle = el.attribute_handle; |
| 165 | |
| 166 | LOG_INFO(LOG_TAG, "%s: char_handle:%d", __func__, char_handle); |
| 167 | |
| 168 | g_internal->uuid_to_attribute[id] = char_handle; |
| 169 | g_internal->characteristics[char_handle].uuid = id; |
| 170 | g_internal->characteristics[char_handle].blob_section = 0; |
| 171 | |
| 172 | // If the added characteristic is blob |
| 173 | if (blob_index.find(i) != blob_index.end()) { |
| 174 | // Finally, associate the control attribute with the value attribute. |
| 175 | // Also, initialize the control attribute to a readable zero. |
| 176 | const uint16_t control_attribute = char_handle; |
| 177 | const uint16_t blob_attribute = prev_char_handle; |
| 178 | g_internal->controlled_blobs[control_attribute] = blob_attribute; |
| 179 | g_internal->characteristics[blob_attribute].notify = |
| 180 | prev_char_properties & bluetooth::gatt::kPropertyNotify; |
| 181 | |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 182 | bluetooth::gatt::Characteristic& ctrl = |
Jakub Pawlowski | a641b6f | 2016-03-26 00:47:23 -0700 | [diff] [blame] | 183 | g_internal->characteristics[control_attribute]; |
| 184 | ctrl.next_blob.clear(); |
| 185 | ctrl.next_blob.push_back(0); |
| 186 | ctrl.next_blob_pending = true; |
| 187 | ctrl.blob_section = 0; |
| 188 | ctrl.notify = false; |
| 189 | } |
| 190 | prev_char_handle = char_handle; |
| 191 | prev_char_properties = el.properties; |
| 192 | } |
| 193 | } |
| 194 | |
| 195 | pending_svc_decl.clear(); |
| 196 | blob_index.clear(); |
| 197 | |
Jakub Pawlowski | 819e2ec | 2017-07-10 09:56:09 -0700 | [diff] [blame] | 198 | // The Uuid provided here is unimportant, and is only used to satisfy |
Jakub Pawlowski | a641b6f | 2016-03-26 00:47:23 -0700 | [diff] [blame] | 199 | // BlueDroid. |
Jakub Pawlowski | 819e2ec | 2017-07-10 09:56:09 -0700 | [diff] [blame] | 200 | // It must be different than any other registered Uuid. |
| 201 | bluetooth::Uuid client_id = bluetooth::Uuid::GetRandom(); |
Jakub Pawlowski | a641b6f | 2016-03-26 00:47:23 -0700 | [diff] [blame] | 202 | |
Jakub Pawlowski | 96ac0a3 | 2017-06-21 00:00:18 -0700 | [diff] [blame] | 203 | bt_status_t btstat = g_internal->gatt->client->register_client(client_id); |
Jakub Pawlowski | a641b6f | 2016-03-26 00:47:23 -0700 | [diff] [blame] | 204 | if (btstat != BT_STATUS_SUCCESS) { |
| 205 | LOG_ERROR(LOG_TAG, "%s: Failed to register client", __func__); |
| 206 | } |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 207 | } |
| 208 | |
Jakub Pawlowski | a484a88 | 2017-06-24 17:30:18 -0700 | [diff] [blame] | 209 | void RequestReadCallback(int conn_id, int trans_id, const RawAddress& bda, |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 210 | int attr_handle, int attribute_offset_octets, |
| 211 | bool is_long) { |
| 212 | std::lock_guard<std::mutex> lock(g_internal->lock); |
| 213 | |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 214 | bluetooth::gatt::Characteristic& ch = |
| 215 | g_internal->characteristics[attr_handle]; |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 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 | |
Jakub Pawlowski | 96ac0a3 | 2017-06-21 00:00:18 -0700 | [diff] [blame] | 229 | std::string addr(BtAddrString(&bda)); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 230 | LOG_INFO(LOG_TAG, |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 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, |
| 234 | attribute_offset_octets, ch.blob_section, is_long); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 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; |
Jakub Pawlowski | 96ac0a3 | 2017-06-21 00:00:18 -0700 | [diff] [blame] | 249 | g_internal->gatt->server->send_response(conn_id, trans_id, 0, response); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 250 | } |
| 251 | |
Jakub Pawlowski | a484a88 | 2017-06-24 17:30:18 -0700 | [diff] [blame] | 252 | void RequestWriteCallback(int conn_id, int trans_id, const RawAddress& bda, |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 253 | int attr_handle, int attribute_offset, bool need_rsp, |
Pavlin Radoslavov | b324a8d | 2016-12-09 17:50:59 -0800 | [diff] [blame] | 254 | bool is_prep, std::vector<uint8_t> value) { |
Jakub Pawlowski | 96ac0a3 | 2017-06-21 00:00:18 -0700 | [diff] [blame] | 255 | std::string addr(BtAddrString(&bda)); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 256 | LOG_INFO(LOG_TAG, |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 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, |
| 261 | attribute_offset, value.size(), need_rsp, is_prep); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 262 | |
| 263 | std::lock_guard<std::mutex> lock(g_internal->lock); |
| 264 | |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 265 | bluetooth::gatt::Characteristic& ch = |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 266 | g_internal->characteristics[attr_handle]; |
| 267 | |
Jakub Pawlowski | 16102de | 2016-05-31 13:14:13 -0700 | [diff] [blame] | 268 | ch.blob.resize(attribute_offset + value.size()); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 269 | |
Jakub Pawlowski | 16102de | 2016-05-31 13:14:13 -0700 | [diff] [blame] | 270 | std::copy(value.begin(), value.end(), ch.blob.begin() + attribute_offset); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 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(LOG_TAG, "%s: updating attribute %d blob_section to %u", __func__, |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 278 | target_blob->second, ch.blob[0]); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 279 | } else if (!is_prep) { |
| 280 | // This is a single frame characteristic write. |
| 281 | // Notify upwards because we're done now. |
Jakub Pawlowski | 819e2ec | 2017-07-10 09:56:09 -0700 | [diff] [blame] | 282 | const bluetooth::Uuid::UUID128Bit& attr_uuid = ch.uuid.To128BitBE(); |
Pavlin Radoslavov | d6121a3 | 2016-05-12 11:36:44 -0700 | [diff] [blame] | 283 | ssize_t status; |
| 284 | OSI_NO_INTR(status = write(g_internal->pipefd[kPipeWriteEnd], |
| 285 | attr_uuid.data(), attr_uuid.size())); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 286 | if (-1 == status) |
| 287 | LOG_ERROR(LOG_TAG, "%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; |
Jakub Pawlowski | 16102de | 2016-05-31 13:14:13 -0700 | [diff] [blame] | 300 | response.attr_value.len = value.size(); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 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. |
Jakub Pawlowski | 16102de | 2016-05-31 13:14:13 -0700 | [diff] [blame] | 304 | std::copy(value.begin(), value.end(), response.attr_value.value); |
Jakub Pawlowski | 96ac0a3 | 2017-06-21 00:00:18 -0700 | [diff] [blame] | 305 | g_internal->gatt->server->send_response(conn_id, trans_id, 0, response); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 306 | } |
| 307 | |
Jakub Pawlowski | a484a88 | 2017-06-24 17:30:18 -0700 | [diff] [blame] | 308 | void RequestExecWriteCallback(int conn_id, int trans_id, const RawAddress& bda, |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 309 | int exec_write) { |
Jakub Pawlowski | 96ac0a3 | 2017-06-21 00:00:18 -0700 | [diff] [blame] | 310 | std::string addr(BtAddrString(&bda)); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 311 | LOG_INFO(LOG_TAG, "%s: connection:%d (%s:trans:%d) exec_write:%d", __func__, |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 312 | conn_id, addr.c_str(), trans_id, exec_write); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 313 | |
| 314 | // This 'response' data is unused for ExecWriteResponses. |
| 315 | // It is only used to pass BlueDroid argument validation. |
| 316 | btgatt_response_t response = {}; |
Jakub Pawlowski | 96ac0a3 | 2017-06-21 00:00:18 -0700 | [diff] [blame] | 317 | g_internal->gatt->server->send_response(conn_id, trans_id, 0, response); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 318 | |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 319 | if (!exec_write) return; |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 320 | |
| 321 | std::lock_guard<std::mutex> lock(g_internal->lock); |
Jakub Pawlowski | 819e2ec | 2017-07-10 09:56:09 -0700 | [diff] [blame] | 322 | // Communicate the attribute Uuid as notification of a write update. |
| 323 | const bluetooth::Uuid::UUID128Bit uuid = g_internal->last_write.To128BitBE(); |
Pavlin Radoslavov | d6121a3 | 2016-05-12 11:36:44 -0700 | [diff] [blame] | 324 | ssize_t status; |
| 325 | OSI_NO_INTR(status = write(g_internal->pipefd[kPipeWriteEnd], uuid.data(), |
| 326 | uuid.size())); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 327 | if (-1 == status) |
| 328 | LOG_ERROR(LOG_TAG, "%s: write failed: %s", __func__, strerror(errno)); |
| 329 | } |
| 330 | |
| 331 | void ConnectionCallback(int conn_id, int server_if, int connected, |
Jakub Pawlowski | a484a88 | 2017-06-24 17:30:18 -0700 | [diff] [blame] | 332 | const RawAddress& bda) { |
Jakub Pawlowski | 96ac0a3 | 2017-06-21 00:00:18 -0700 | [diff] [blame] | 333 | std::string addr(BtAddrString(&bda)); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 334 | LOG_INFO(LOG_TAG, "%s: connection:%d server_if:%d connected:%d addr:%s", |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 335 | __func__, conn_id, server_if, connected, addr.c_str()); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 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 | |
Jakub Pawlowski | a8d73ef | 2016-10-31 11:15:20 -0700 | [diff] [blame] | 343 | void EnableAdvertisingCallback(uint8_t status) { |
| 344 | LOG_INFO(LOG_TAG, "%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 | |
Jakub Pawlowski | 96ac0a3 | 2017-06-21 00:00:18 -0700 | [diff] [blame] | 350 | void RegisterClientCallback(int status, int client_if, |
Jakub Pawlowski | 819e2ec | 2017-07-10 09:56:09 -0700 | [diff] [blame] | 351 | const bluetooth::Uuid& app_uuid) { |
| 352 | LOG_INFO(LOG_TAG, "%s: status:%d client_if:%d uuid[0]:%s", __func__, status, |
| 353 | client_if, app_uuid.ToString().c_str()); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 354 | g_internal->client_if = client_if; |
| 355 | |
| 356 | // Setup our advertisement. This has no callback. |
Jakub Pawlowski | d964cf9 | 2016-11-03 15:41:50 -0700 | [diff] [blame] | 357 | g_internal->gatt->advertiser->SetData(0 /* std_inst */, false, |
| 358 | {/*TODO: put inverval 2,2 here*/}, |
Jakub Pawlowski | 67f5f37 | 2018-07-23 10:00:25 -0700 | [diff] [blame] | 359 | base::DoNothing()); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 360 | |
Jakub Pawlowski | d964cf9 | 2016-11-03 15:41:50 -0700 | [diff] [blame] | 361 | g_internal->gatt->advertiser->Enable( |
| 362 | 0 /* std_inst */, true, base::Bind(&EnableAdvertisingCallback), |
Jakub Pawlowski | 67f5f37 | 2018-07-23 10:00:25 -0700 | [diff] [blame] | 363 | 0 /* no duration */, 0 /* no maxExtAdvEvent*/, base::DoNothing()); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 364 | } |
| 365 | |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 366 | void ServiceStoppedCallback(int status, int server_if, int srvc_handle) { |
| 367 | LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d srvc_handle:%d", __func__, |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 368 | status, server_if, srvc_handle); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 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 | |
Jakub Pawlowski | 7de0f9b | 2017-01-27 08:06:20 -0800 | [diff] [blame] | 375 | void ScanResultCallback(uint16_t ble_evt_type, uint8_t addr_type, |
Jakub Pawlowski | a484a88 | 2017-06-24 17:30:18 -0700 | [diff] [blame] | 376 | RawAddress* bda, uint8_t ble_primary_phy, |
Jakub Pawlowski | 7de0f9b | 2017-01-27 08:06:20 -0800 | [diff] [blame] | 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, |
Pavlin Radoslavov | b324a8d | 2016-12-09 17:50:59 -0800 | [diff] [blame] | 380 | std::vector<uint8_t> adv_data) { |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 381 | std::string addr(BtAddrString(bda)); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 382 | std::lock_guard<std::mutex> lock(g_internal->lock); |
| 383 | g_internal->scan_results[addr] = rssi; |
| 384 | } |
| 385 | |
| 386 | void ClientConnectCallback(int conn_id, int status, int client_if, |
Jakub Pawlowski | a484a88 | 2017-06-24 17:30:18 -0700 | [diff] [blame] | 387 | const RawAddress& bda) { |
Jakub Pawlowski | 96ac0a3 | 2017-06-21 00:00:18 -0700 | [diff] [blame] | 388 | std::string addr(BtAddrString(&bda)); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 389 | LOG_INFO(LOG_TAG, "%s: conn_id:%d status:%d client_if:%d %s", __func__, |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 390 | conn_id, status, client_if, addr.c_str()); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 391 | } |
| 392 | |
| 393 | void ClientDisconnectCallback(int conn_id, int status, int client_if, |
Jakub Pawlowski | a484a88 | 2017-06-24 17:30:18 -0700 | [diff] [blame] | 394 | const RawAddress& bda) { |
Jakub Pawlowski | 96ac0a3 | 2017-06-21 00:00:18 -0700 | [diff] [blame] | 395 | std::string addr(BtAddrString(&bda)); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 396 | LOG_INFO(LOG_TAG, "%s: conn_id:%d status:%d client_if:%d %s", __func__, |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 397 | conn_id, status, client_if, addr.c_str()); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 398 | } |
| 399 | |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 400 | void IndicationSentCallback(UNUSED_ATTR int conn_id, UNUSED_ATTR int status) { |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 401 | // TODO(icoolidge): what to do |
| 402 | } |
| 403 | |
| 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, |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 413 | ServiceStoppedCallback, |
| 414 | nullptr, /* service_deleted_cb */ |
| 415 | RequestReadCallback, |
Jakub Pawlowski | a641b6f | 2016-03-26 00:47:23 -0700 | [diff] [blame] | 416 | RequestReadCallback, |
| 417 | RequestWriteCallback, |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 418 | RequestWriteCallback, |
| 419 | RequestExecWriteCallback, |
| 420 | ResponseConfirmationCallback, |
| 421 | IndicationSentCallback, |
| 422 | nullptr, /* congestion_cb*/ |
| 423 | nullptr, /* mtu_changed_cb */ |
Jakub Pawlowski | eafd45d | 2017-03-22 19:00:47 -0700 | [diff] [blame] | 424 | nullptr, /* phy_update_cb */ |
Jakub Pawlowski | b5ba4fd | 2017-03-23 18:11:04 -0700 | [diff] [blame] | 425 | nullptr, /* conn_update_cb */ |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 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, |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 432 | ClientConnectCallback, |
| 433 | ClientDisconnectCallback, |
| 434 | nullptr, /* search_complete_cb; */ |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 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; */ |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 443 | nullptr, /* configure_mtu_cb; */ |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 444 | nullptr, /* congestion_cb; */ |
Jakub Pawlowski | c3f6a51 | 2016-10-27 11:49:40 -0700 | [diff] [blame] | 445 | nullptr, /* get_gatt_db_cb; */ |
| 446 | nullptr, /* services_removed_cb */ |
| 447 | nullptr, /* services_added_cb */ |
Jakub Pawlowski | eafd45d | 2017-03-22 19:00:47 -0700 | [diff] [blame] | 448 | nullptr, /* phy_update_cb */ |
Jakub Pawlowski | b5ba4fd | 2017-03-23 18:11:04 -0700 | [diff] [blame] | 449 | nullptr, /* conn_update_cb */ |
Jakub Pawlowski | c3f6a51 | 2016-10-27 11:49:40 -0700 | [diff] [blame] | 450 | }; |
| 451 | |
| 452 | const btgatt_scanner_callbacks_t gatt_scanner_callbacks = { |
Jakub Pawlowski | c3f6a51 | 2016-10-27 11:49:40 -0700 | [diff] [blame] | 453 | ScanResultCallback, |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 454 | nullptr, /* batchscan_reports_cb; */ |
| 455 | nullptr, /* batchscan_threshold_cb; */ |
| 456 | nullptr, /* track_adv_event_cb; */ |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 457 | }; |
| 458 | |
| 459 | const btgatt_callbacks_t gatt_callbacks = { |
| 460 | /** Set to sizeof(btgatt_callbacks_t) */ |
| 461 | sizeof(btgatt_callbacks_t), |
| 462 | |
| 463 | /** GATT Client callbacks */ |
| 464 | &gatt_client_callbacks, |
| 465 | |
| 466 | /** GATT Server callbacks */ |
Jakub Pawlowski | 67d5a25 | 2016-07-13 11:55:16 -0700 | [diff] [blame] | 467 | &gatt_server_callbacks, |
Jakub Pawlowski | c3f6a51 | 2016-10-27 11:49:40 -0700 | [diff] [blame] | 468 | |
| 469 | /** GATT Server callbacks */ |
| 470 | &gatt_scanner_callbacks, |
Jakub Pawlowski | 67d5a25 | 2016-07-13 11:55:16 -0700 | [diff] [blame] | 471 | }; |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 472 | |
| 473 | } // namespace |
| 474 | |
| 475 | namespace bluetooth { |
| 476 | namespace gatt { |
| 477 | |
| 478 | int ServerInternals::Initialize() { |
| 479 | // Get the interface to the GATT profile. |
| 480 | const bt_interface_t* bt_iface = |
| 481 | hal::BluetoothInterface::Get()->GetHALInterface(); |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 482 | gatt = reinterpret_cast<const btgatt_interface_t*>( |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 483 | bt_iface->get_profile_interface(BT_PROFILE_GATT_ID)); |
| 484 | if (!gatt) { |
| 485 | LOG_ERROR(LOG_TAG, "Error getting GATT interface"); |
| 486 | return -1; |
| 487 | } |
| 488 | |
| 489 | bt_status_t btstat = gatt->init(&gatt_callbacks); |
| 490 | if (btstat != BT_STATUS_SUCCESS) { |
| 491 | LOG_ERROR(LOG_TAG, "Failed to initialize gatt interface"); |
| 492 | return -1; |
| 493 | } |
| 494 | |
| 495 | int status = pipe(pipefd); |
| 496 | if (status == -1) { |
| 497 | LOG_ERROR(LOG_TAG, "pipe creation failed: %s", strerror(errno)); |
| 498 | return -1; |
| 499 | } |
| 500 | |
| 501 | return 0; |
| 502 | } |
| 503 | |
Jakub Pawlowski | 819e2ec | 2017-07-10 09:56:09 -0700 | [diff] [blame] | 504 | bt_status_t ServerInternals::AddCharacteristic(const Uuid& uuid, |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 505 | uint8_t properties, |
| 506 | uint16_t permissions) { |
Nick Desaulniers | 7ee5835 | 2019-10-09 11:06:55 -0700 | [diff] [blame] | 507 | pending_svc_decl.push_back({.uuid = uuid, |
| 508 | .type = BTGATT_DB_CHARACTERISTIC, |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 509 | .properties = properties, |
| 510 | .permissions = permissions}); |
Jakub Pawlowski | a641b6f | 2016-03-26 00:47:23 -0700 | [diff] [blame] | 511 | return BT_STATUS_SUCCESS; |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 512 | } |
| 513 | |
| 514 | ServerInternals::ServerInternals() |
| 515 | : gatt(nullptr), |
| 516 | server_if(0), |
| 517 | client_if(0), |
| 518 | service_handle(0), |
| 519 | pipefd{INVALID_FD, INVALID_FD} {} |
| 520 | |
| 521 | ServerInternals::~ServerInternals() { |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 522 | if (pipefd[0] != INVALID_FD) close(pipefd[0]); |
| 523 | if (pipefd[1] != INVALID_FD) close(pipefd[1]); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 524 | |
| 525 | gatt->server->delete_service(server_if, service_handle); |
| 526 | gatt->server->unregister_server(server_if); |
| 527 | gatt->client->unregister_client(client_if); |
| 528 | } |
| 529 | |
| 530 | Server::Server() : internal_(nullptr) {} |
| 531 | |
| 532 | Server::~Server() {} |
| 533 | |
Jakub Pawlowski | 819e2ec | 2017-07-10 09:56:09 -0700 | [diff] [blame] | 534 | bool Server::Initialize(const Uuid& service_id, int* gatt_pipe) { |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 535 | internal_.reset(new ServerInternals); |
| 536 | if (!internal_) { |
| 537 | LOG_ERROR(LOG_TAG, "Error creating internals"); |
| 538 | return false; |
| 539 | } |
| 540 | g_internal = internal_.get(); |
| 541 | |
| 542 | std::unique_lock<std::mutex> lock(internal_->lock); |
| 543 | int status = internal_->Initialize(); |
| 544 | if (status) { |
| 545 | LOG_ERROR(LOG_TAG, "Error initializing internals"); |
| 546 | return false; |
| 547 | } |
| 548 | |
Jakub Pawlowski | 819e2ec | 2017-07-10 09:56:09 -0700 | [diff] [blame] | 549 | bt_status_t btstat = internal_->gatt->server->register_server(service_id); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 550 | if (btstat != BT_STATUS_SUCCESS) { |
| 551 | LOG_ERROR(LOG_TAG, "Failed to register server"); |
| 552 | return false; |
| 553 | } |
| 554 | |
| 555 | internal_->api_synchronize.wait(lock); |
| 556 | // TODO(icoolidge): Better error handling. |
| 557 | if (internal_->server_if == 0) { |
| 558 | LOG_ERROR(LOG_TAG, "Initialization of server failed"); |
| 559 | return false; |
| 560 | } |
| 561 | |
| 562 | *gatt_pipe = internal_->pipefd[kPipeReadEnd]; |
| 563 | LOG_INFO(LOG_TAG, "Server Initialize succeeded"); |
| 564 | return true; |
| 565 | } |
| 566 | |
Jakub Pawlowski | 819e2ec | 2017-07-10 09:56:09 -0700 | [diff] [blame] | 567 | bool Server::SetAdvertisement(const std::vector<Uuid>& ids, |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 568 | const std::vector<uint8_t>& service_data, |
| 569 | const std::vector<uint8_t>& manufacturer_data, |
| 570 | bool transmit_name) { |
Jakub Pawlowski | 0ecddf3 | 2016-10-19 14:46:09 -0700 | [diff] [blame] | 571 | // std::vector<uint8_t> id_data; |
| 572 | // const auto& mutable_manufacturer_data = manufacturer_data; |
| 573 | // const auto& mutable_service_data = service_data; |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 574 | |
Jakub Pawlowski | 819e2ec | 2017-07-10 09:56:09 -0700 | [diff] [blame] | 575 | // for (const Uuid &id : ids) { |
| 576 | // const auto le_id = id.To128BitLE(); |
Jakub Pawlowski | 0ecddf3 | 2016-10-19 14:46:09 -0700 | [diff] [blame] | 577 | // id_data.insert(id_data.end(), le_id.begin(), le_id.end()); |
| 578 | // } |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 579 | |
| 580 | std::lock_guard<std::mutex> lock(internal_->lock); |
| 581 | |
| 582 | // Setup our advertisement. This has no callback. |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 583 | internal_->gatt->advertiser->SetData(0, false, /* beacon, not scan response */ |
Jakub Pawlowski | 67f5f37 | 2018-07-23 10:00:25 -0700 | [diff] [blame] | 584 | {}, base::DoNothing()); |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 585 | // transmit_name, /* name */ |
| 586 | // 2, 2, interval |
| 587 | // mutable_manufacturer_data, |
| 588 | // mutable_service_data, |
| 589 | // id_data); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 590 | return true; |
| 591 | } |
| 592 | |
Jakub Pawlowski | 819e2ec | 2017-07-10 09:56:09 -0700 | [diff] [blame] | 593 | bool Server::SetScanResponse(const std::vector<Uuid>& ids, |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 594 | const std::vector<uint8_t>& service_data, |
| 595 | const std::vector<uint8_t>& manufacturer_data, |
| 596 | bool transmit_name) { |
Jakub Pawlowski | 0ecddf3 | 2016-10-19 14:46:09 -0700 | [diff] [blame] | 597 | // std::vector<uint8_t> id_data; |
| 598 | // const auto& mutable_manufacturer_data = manufacturer_data; |
| 599 | // const auto& mutable_service_data = service_data; |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 600 | |
Jakub Pawlowski | 819e2ec | 2017-07-10 09:56:09 -0700 | [diff] [blame] | 601 | // for (const Uuid &id : ids) { |
| 602 | // const auto le_id = id.To128BitLE(); |
Jakub Pawlowski | 0ecddf3 | 2016-10-19 14:46:09 -0700 | [diff] [blame] | 603 | // id_data.insert(id_data.end(), le_id.begin(), le_id.end()); |
| 604 | // } |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 605 | |
| 606 | std::lock_guard<std::mutex> lock(internal_->lock); |
| 607 | |
| 608 | // Setup our advertisement. This has no callback. |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 609 | internal_->gatt->advertiser->SetData(0, true, /* scan response */ |
Jakub Pawlowski | 67f5f37 | 2018-07-23 10:00:25 -0700 | [diff] [blame] | 610 | {}, base::DoNothing()); |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 611 | // transmit_name, /* name */ |
| 612 | // false, /* no txpower */ |
| 613 | // 2, 2, interval |
| 614 | // 0, /* appearance */ |
| 615 | // mutable_manufacturer_data, |
| 616 | // mutable_service_data, |
| 617 | // id_data); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 618 | return true; |
| 619 | } |
| 620 | |
Jakub Pawlowski | 819e2ec | 2017-07-10 09:56:09 -0700 | [diff] [blame] | 621 | bool Server::AddCharacteristic(const Uuid& id, int properties, |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 622 | int permissions) { |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 623 | std::unique_lock<std::mutex> lock(internal_->lock); |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 624 | bt_status_t btstat = |
| 625 | internal_->AddCharacteristic(id, properties, permissions); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 626 | if (btstat != BT_STATUS_SUCCESS) { |
| 627 | LOG_ERROR(LOG_TAG, "Failed to add characteristic to service: 0x%04x", |
| 628 | internal_->service_handle); |
| 629 | return false; |
| 630 | } |
| 631 | internal_->api_synchronize.wait(lock); |
| 632 | const int handle = internal_->uuid_to_attribute[id]; |
| 633 | internal_->characteristics[handle].notify = properties & kPropertyNotify; |
| 634 | return true; |
| 635 | } |
| 636 | |
Jakub Pawlowski | 819e2ec | 2017-07-10 09:56:09 -0700 | [diff] [blame] | 637 | bool Server::AddBlob(const Uuid& id, const Uuid& control_id, int properties, |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 638 | int permissions) { |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 639 | std::unique_lock<std::mutex> lock(internal_->lock); |
| 640 | |
| 641 | // First, add the primary attribute (characteristic value) |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 642 | bt_status_t btstat = |
| 643 | internal_->AddCharacteristic(id, properties, permissions); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 644 | if (btstat != BT_STATUS_SUCCESS) { |
| 645 | LOG_ERROR(LOG_TAG, "Failed to set scan response data"); |
| 646 | return false; |
| 647 | } |
| 648 | |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 649 | // Next, add the secondary attribute (blob control). |
| 650 | // Control attributes have fixed permissions/properties. |
Jakub Pawlowski | a641b6f | 2016-03-26 00:47:23 -0700 | [diff] [blame] | 651 | // Remember position at which blob was added. |
| 652 | blob_index.insert(pending_svc_decl.size()); |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 653 | btstat = |
| 654 | internal_->AddCharacteristic(control_id, kPropertyRead | kPropertyWrite, |
| 655 | kPermissionRead | kPermissionWrite); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 656 | |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 657 | return true; |
| 658 | } |
| 659 | |
| 660 | bool Server::Start() { |
| 661 | std::unique_lock<std::mutex> lock(internal_->lock); |
Jakub Pawlowski | a641b6f | 2016-03-26 00:47:23 -0700 | [diff] [blame] | 662 | bt_status_t btstat = internal_->gatt->server->add_service( |
| 663 | internal_->server_if, pending_svc_decl); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 664 | if (btstat != BT_STATUS_SUCCESS) { |
| 665 | LOG_ERROR(LOG_TAG, "Failed to start service with handle: 0x%04x", |
| 666 | internal_->service_handle); |
| 667 | return false; |
| 668 | } |
| 669 | internal_->api_synchronize.wait(lock); |
| 670 | return true; |
| 671 | } |
| 672 | |
| 673 | bool Server::Stop() { |
| 674 | std::unique_lock<std::mutex> lock(internal_->lock); |
| 675 | bt_status_t btstat = internal_->gatt->server->stop_service( |
| 676 | internal_->server_if, internal_->service_handle); |
| 677 | if (btstat != BT_STATUS_SUCCESS) { |
| 678 | LOG_ERROR(LOG_TAG, "Failed to stop service with handle: 0x%04x", |
| 679 | internal_->service_handle); |
| 680 | return false; |
| 681 | } |
| 682 | internal_->api_synchronize.wait(lock); |
| 683 | return true; |
| 684 | } |
| 685 | |
| 686 | bool Server::ScanEnable() { |
Jakub Pawlowski | 83f1d96 | 2016-12-14 09:49:38 -0800 | [diff] [blame] | 687 | internal_->gatt->scanner->Scan(true); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 688 | return true; |
| 689 | } |
| 690 | |
| 691 | bool Server::ScanDisable() { |
Jakub Pawlowski | 83f1d96 | 2016-12-14 09:49:38 -0800 | [diff] [blame] | 692 | internal_->gatt->scanner->Scan(false); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 693 | return true; |
| 694 | } |
| 695 | |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 696 | bool Server::GetScanResults(ScanResults* results) { |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 697 | std::lock_guard<std::mutex> lock(internal_->lock); |
| 698 | *results = internal_->scan_results; |
| 699 | return true; |
| 700 | } |
| 701 | |
Jakub Pawlowski | 819e2ec | 2017-07-10 09:56:09 -0700 | [diff] [blame] | 702 | bool Server::SetCharacteristicValue(const Uuid& id, |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 703 | const std::vector<uint8_t>& value) { |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 704 | std::lock_guard<std::mutex> lock(internal_->lock); |
| 705 | const int attribute_id = internal_->uuid_to_attribute[id]; |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 706 | Characteristic& ch = internal_->characteristics[attribute_id]; |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 707 | ch.next_blob = value; |
| 708 | ch.next_blob_pending = true; |
| 709 | |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 710 | if (!ch.notify) return true; |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 711 | |
| 712 | for (auto connection : internal_->connections) { |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 713 | internal_->gatt->server->send_indication(internal_->server_if, attribute_id, |
| 714 | connection, true, {0}); |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 715 | } |
| 716 | return true; |
| 717 | } |
| 718 | |
Jakub Pawlowski | 819e2ec | 2017-07-10 09:56:09 -0700 | [diff] [blame] | 719 | bool Server::GetCharacteristicValue(const Uuid& id, |
Myles Watson | 911d1ae | 2016-11-28 16:44:40 -0800 | [diff] [blame] | 720 | std::vector<uint8_t>* value) { |
Arman Uguray | 0f2d489 | 2015-09-22 14:20:42 -0700 | [diff] [blame] | 721 | std::lock_guard<std::mutex> lock(internal_->lock); |
| 722 | const int attribute_id = internal_->uuid_to_attribute[id]; |
| 723 | *value = internal_->characteristics[attribute_id].blob; |
| 724 | return true; |
| 725 | } |
| 726 | |
| 727 | } // namespace gatt |
| 728 | } // namespace bluetooth |