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_bluetooth_host" 18 19 #include "service/ipc/linux_ipc_host.h" 20 21 #include <errno.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <sys/ioctl.h> 25 #include <sys/socket.h> 26 #include <sys/types.h> 27 #include <sys/un.h> 28 #include <unistd.h> 29 30 #include <algorithm> 31 32 #include <base/base64.h> 33 #include <base/strings/string_number_conversions.h> 34 #include <base/strings/string_split.h> 35 36 #include "osi/include/osi.h" 37 #include "osi/include/log.h" 38 #include "service/adapter.h" 39 40 using bluetooth::Adapter; 41 using bluetooth::UUID; 42 43 using namespace bluetooth::gatt; 44 45 namespace { 46 47 // IPC API is according to: 48 // https://docs.google.com/document/d/1eRnku-jAyVU1wGJsLT2CzWi0-8bs2g49s1b3FR_GApM 49 const char kSetAdapterNameCommand[] = "set-device-name"; 50 const char kCreateServiceCommand[] = "create-service"; 51 const char kDestroyServiceCommand[] = "destroy-service"; 52 const char kAddCharacteristicCommand[] = "add-characteristic"; 53 const char kSetCharacteristicValueCommand[] = "set-characteristic-value"; 54 const char kSetAdvertisementCommand[] = "set-advertisement"; 55 const char kSetScanResponseCommand[] = "set-scan-response"; 56 const char kStartServiceCommand[] = "start-service"; 57 const char kStopServiceCommand[] = "stop-service"; 58 const char kWriteCharacteristicCommand[] = "write-characteristic"; 59 60 // Useful values for indexing LinuxIPCHost::pfds_ 61 // Not super general considering that we should be able to support 62 // many GATT FDs owned by one LinuxIPCHost. 63 enum { 64 kFdIpc = 0, 65 kFdGatt = 1, 66 kPossibleFds = 2, 67 }; 68 69 bool TokenBool(const std::string& text) { 70 return text == "true"; 71 } 72 73 } // namespace 74 75 namespace ipc { 76 77 LinuxIPCHost::LinuxIPCHost(int sockfd, Adapter* adapter) 78 : adapter_(adapter), pfds_(1, {sockfd, POLLIN, 0}) {} 79 80 LinuxIPCHost::~LinuxIPCHost() { 81 close(pfds_[0].fd); 82 } 83 84 bool LinuxIPCHost::EventLoop() { 85 while (true) { 86 int status = 87 TEMP_FAILURE_RETRY(ppoll(pfds_.data(), pfds_.size(), nullptr, nullptr)); 88 if (status < 1) { 89 LOG_ERROR(LOG_TAG, "ppoll error"); 90 return false; 91 } 92 93 if (pfds_[kFdIpc].revents && !OnMessage()) { 94 return false; 95 } 96 97 if (pfds_.size() == kPossibleFds && 98 pfds_[kFdGatt].revents && 99 !OnGattWrite()) { 100 return false; 101 } 102 } 103 return true; 104 } 105 106 bool LinuxIPCHost::OnSetAdapterName(const std::string& name) { 107 std::string decoded_data; 108 base::Base64Decode(name, &decoded_data); 109 return adapter_->SetName(decoded_data); 110 } 111 112 bool LinuxIPCHost::OnCreateService(const std::string& service_uuid) { 113 gatt_servers_[service_uuid] = std::unique_ptr<Server>(new Server); 114 115 int gattfd; 116 bool status = gatt_servers_[service_uuid]->Initialize( 117 UUID(service_uuid), &gattfd); 118 if (!status) { 119 LOG_ERROR(LOG_TAG, "Failed to initialize bluetooth"); 120 return false; 121 } 122 pfds_.resize(kPossibleFds); 123 pfds_[kFdGatt] = {gattfd, POLLIN, 0}; 124 return true; 125 } 126 127 bool LinuxIPCHost::OnDestroyService(const std::string& service_uuid) { 128 gatt_servers_.erase(service_uuid); 129 close(pfds_[1].fd); 130 pfds_.resize(1); 131 return true; 132 } 133 134 bool LinuxIPCHost::OnAddCharacteristic(const std::string& service_uuid, 135 const std::string& characteristic_uuid, 136 const std::string& control_uuid, 137 const std::string& options) { 138 std::vector<std::string> option_tokens = base::SplitString( 139 options, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); 140 141 int properties_mask = 0; 142 int permissions_mask = 0; 143 144 if (std::find(option_tokens.begin(), option_tokens.end(), "notify") != 145 option_tokens.end()) { 146 permissions_mask |= kPermissionRead; 147 properties_mask |= kPropertyRead; 148 properties_mask |= kPropertyNotify; 149 } 150 if (std::find(option_tokens.begin(), option_tokens.end(), "read") != 151 option_tokens.end()) { 152 permissions_mask |= kPermissionRead; 153 properties_mask |= kPropertyRead; 154 } 155 if (std::find(option_tokens.begin(), option_tokens.end(), "write") != 156 option_tokens.end()) { 157 permissions_mask |= kPermissionWrite; 158 properties_mask |= kPropertyWrite; 159 } 160 161 if (control_uuid.empty()) { 162 gatt_servers_[service_uuid]->AddCharacteristic( 163 UUID(characteristic_uuid), properties_mask, permissions_mask); 164 } else { 165 gatt_servers_[service_uuid]->AddBlob(UUID(characteristic_uuid), 166 UUID(control_uuid), properties_mask, 167 permissions_mask); 168 } 169 return true; 170 } 171 172 bool LinuxIPCHost::OnSetCharacteristicValue(const std::string& service_uuid, 173 const std::string& characteristic_uuid, 174 const std::string& value) { 175 std::string decoded_data; 176 base::Base64Decode(value, &decoded_data); 177 std::vector<uint8_t> blob_data(decoded_data.begin(), decoded_data.end()); 178 gatt_servers_[service_uuid]->SetCharacteristicValue(UUID(characteristic_uuid), 179 blob_data); 180 return true; 181 } 182 183 bool LinuxIPCHost::OnSetAdvertisement(const std::string& service_uuid, 184 const std::string& advertise_uuids, 185 const std::string& advertise_data, 186 const std::string& manufacturer_data, 187 const std::string& transmit_name) { 188 LOG_INFO(LOG_TAG, "%s: service:%s uuids:%s data:%s", __func__, service_uuid.c_str(), 189 advertise_uuids.c_str(), advertise_data.c_str()); 190 191 std::vector<std::string> advertise_uuid_tokens = base::SplitString( 192 advertise_uuids, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); 193 194 // string -> vector<UUID> 195 std::vector<UUID> ids; 196 for (const auto& uuid_token : advertise_uuid_tokens) 197 ids.emplace_back(uuid_token); 198 199 std::string decoded_data; 200 base::Base64Decode(advertise_data, &decoded_data); 201 std::vector<uint8_t> decoded_advertise_data(decoded_data.begin(), 202 decoded_data.end()); 203 204 base::Base64Decode(manufacturer_data, &decoded_data); 205 std::vector<uint8_t> decoded_manufacturer_data(decoded_data.begin(), 206 decoded_data.end()); 207 208 gatt_servers_[service_uuid]->SetAdvertisement(ids, decoded_advertise_data, 209 decoded_manufacturer_data, 210 TokenBool(transmit_name)); 211 return true; 212 } 213 214 bool LinuxIPCHost::OnSetScanResponse(const std::string& service_uuid, 215 const std::string& scan_response_uuids, 216 const std::string& scan_response_data, 217 const std::string& manufacturer_data, 218 const std::string& transmit_name) { 219 std::vector<std::string> scan_response_uuid_tokens = base::SplitString( 220 scan_response_uuids, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); 221 222 // string -> vector<UUID> 223 std::vector<UUID> ids; 224 for (const auto& uuid_token : scan_response_uuid_tokens) 225 ids.emplace_back(uuid_token); 226 227 std::string decoded_data; 228 base::Base64Decode(scan_response_data, &decoded_data); 229 std::vector<uint8_t> decoded_advertise_data(decoded_data.begin(), 230 decoded_data.end()); 231 232 base::Base64Decode(manufacturer_data, &decoded_data); 233 std::vector<uint8_t> decoded_manufacturer_data(decoded_data.begin(), 234 decoded_data.end()); 235 236 gatt_servers_[service_uuid]->SetScanResponse(ids, decoded_advertise_data, 237 decoded_manufacturer_data, 238 TokenBool(transmit_name)); 239 return true; 240 } 241 242 bool LinuxIPCHost::OnStartService(const std::string& service_uuid) { 243 return gatt_servers_[service_uuid]->Start(); 244 } 245 246 bool LinuxIPCHost::OnStopService(const std::string& service_uuid) { 247 return gatt_servers_[service_uuid]->Stop(); 248 } 249 250 bool LinuxIPCHost::OnMessage() { 251 std::string ipc_msg; 252 ssize_t size; 253 254 OSI_NO_INTR(size = recv(pfds_[kFdIpc].fd, &ipc_msg[0], 0, 255 MSG_PEEK | MSG_TRUNC)); 256 if (-1 == size) { 257 LOG_ERROR(LOG_TAG, "Error reading datagram size: %s", strerror(errno)); 258 return false; 259 } else if (0 == size) { 260 LOG_INFO(LOG_TAG, "%s:%d: Connection closed", __func__, __LINE__); 261 return false; 262 } 263 264 ipc_msg.resize(size); 265 OSI_NO_INTR(size = read(pfds_[kFdIpc].fd, &ipc_msg[0], ipc_msg.size())); 266 if (-1 == size) { 267 LOG_ERROR(LOG_TAG, "Error reading IPC: %s", strerror(errno)); 268 return false; 269 } else if (0 == size) { 270 LOG_INFO(LOG_TAG, "%s:%d: Connection closed", __func__, __LINE__); 271 return false; 272 } 273 274 std::vector<std::string> tokens = base::SplitString( 275 ipc_msg, "|", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); 276 switch (tokens.size()) { 277 case 2: 278 if (tokens[0] == kSetAdapterNameCommand) 279 return OnSetAdapterName(tokens[1]); 280 if (tokens[0] == kCreateServiceCommand) 281 return OnCreateService(tokens[1]); 282 if (tokens[0] == kDestroyServiceCommand) 283 return OnDestroyService(tokens[1]); 284 if (tokens[0] == kStartServiceCommand) 285 return OnStartService(tokens[1]); 286 if (tokens[0] == kStopServiceCommand) 287 return OnStopService(tokens[1]); 288 break; 289 case 4: 290 if (tokens[0] == kSetCharacteristicValueCommand) 291 return OnSetCharacteristicValue(tokens[1], tokens[2], tokens[3]); 292 break; 293 case 5: 294 if (tokens[0] == kAddCharacteristicCommand) 295 return OnAddCharacteristic(tokens[1], tokens[2], tokens[3], tokens[4]); 296 break; 297 case 6: 298 if (tokens[0] == kSetAdvertisementCommand) 299 return OnSetAdvertisement(tokens[1], tokens[2], tokens[3], tokens[4], tokens[5]); 300 if (tokens[0] == kSetScanResponseCommand) 301 return OnSetScanResponse(tokens[1], tokens[2], tokens[3], tokens[4], tokens[5]); 302 break; 303 default: 304 break; 305 } 306 307 LOG_ERROR(LOG_TAG, "Malformed IPC message: %s", ipc_msg.c_str()); 308 return false; 309 } 310 311 bool LinuxIPCHost::OnGattWrite() { 312 UUID::UUID128Bit id; 313 ssize_t r; 314 315 OSI_NO_INTR(r = read(pfds_[kFdGatt].fd, id.data(), id.size())); 316 if (r != id.size()) { 317 LOG_ERROR(LOG_TAG, "Error reading GATT attribute ID"); 318 return false; 319 } 320 321 std::vector<uint8_t> value; 322 // TODO(icoolidge): Generalize this for multiple clients. 323 auto server = gatt_servers_.begin(); 324 server->second->GetCharacteristicValue(UUID(id), &value); 325 const std::string value_string(value.begin(), value.end()); 326 std::string encoded_value; 327 base::Base64Encode(value_string, &encoded_value); 328 329 std::string transmit(kWriteCharacteristicCommand); 330 transmit += "|" + server->first; 331 transmit += "|" + base::HexEncode(id.data(), id.size()); 332 transmit += "|" + encoded_value; 333 334 OSI_NO_INTR(r = write(pfds_[kFdIpc].fd, transmit.data(), transmit.size())); 335 if (-1 == r) { 336 LOG_ERROR(LOG_TAG, "Error replying to IPC: %s", strerror(errno)); 337 return false; 338 } 339 340 return true; 341 } 342 343 } // namespace ipc 344