Home | History | Annotate | Download | only in ipc
      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