Home | History | Annotate | Download | only in bluetooth
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "device/bluetooth/bluetooth_socket_chromeos.h"
      6 
      7 #include <queue>
      8 #include <string>
      9 
     10 #include "base/basictypes.h"
     11 #include "base/bind.h"
     12 #include "base/callback.h"
     13 #include "base/logging.h"
     14 #include "base/memory/linked_ptr.h"
     15 #include "base/memory/ref_counted.h"
     16 #include "base/memory/scoped_ptr.h"
     17 #include "base/sequenced_task_runner.h"
     18 #include "base/strings/string_util.h"
     19 #include "base/task_runner_util.h"
     20 #include "base/threading/thread_restrictions.h"
     21 #include "base/threading/worker_pool.h"
     22 #include "chromeos/dbus/bluetooth_device_client.h"
     23 #include "chromeos/dbus/bluetooth_profile_manager_client.h"
     24 #include "chromeos/dbus/bluetooth_profile_service_provider.h"
     25 #include "chromeos/dbus/dbus_thread_manager.h"
     26 #include "dbus/bus.h"
     27 #include "dbus/file_descriptor.h"
     28 #include "dbus/object_path.h"
     29 #include "device/bluetooth/bluetooth_adapter.h"
     30 #include "device/bluetooth/bluetooth_adapter_chromeos.h"
     31 #include "device/bluetooth/bluetooth_device.h"
     32 #include "device/bluetooth/bluetooth_device_chromeos.h"
     33 #include "device/bluetooth/bluetooth_socket.h"
     34 #include "device/bluetooth/bluetooth_socket_net.h"
     35 #include "device/bluetooth/bluetooth_socket_thread.h"
     36 #include "net/base/ip_endpoint.h"
     37 #include "net/base/net_errors.h"
     38 #include "third_party/cros_system_api/dbus/service_constants.h"
     39 
     40 using device::BluetoothAdapter;
     41 using device::BluetoothDevice;
     42 using device::BluetoothSocketThread;
     43 using device::BluetoothUUID;
     44 
     45 namespace {
     46 
     47 const char kAcceptFailed[] = "Failed to accept connection.";
     48 const char kInvalidUUID[] = "Invalid UUID";
     49 const char kSocketNotListening[] = "Socket is not listening.";
     50 
     51 }  // namespace
     52 
     53 namespace chromeos {
     54 
     55 // static
     56 scoped_refptr<BluetoothSocketChromeOS>
     57 BluetoothSocketChromeOS::CreateBluetoothSocket(
     58     scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
     59     scoped_refptr<BluetoothSocketThread> socket_thread,
     60     net::NetLog* net_log,
     61     const net::NetLog::Source& source) {
     62   DCHECK(ui_task_runner->RunsTasksOnCurrentThread());
     63 
     64   return make_scoped_refptr(
     65       new BluetoothSocketChromeOS(
     66           ui_task_runner, socket_thread, net_log, source));
     67 }
     68 
     69 BluetoothSocketChromeOS::AcceptRequest::AcceptRequest() {}
     70 
     71 BluetoothSocketChromeOS::AcceptRequest::~AcceptRequest() {}
     72 
     73 BluetoothSocketChromeOS::ConnectionRequest::ConnectionRequest()
     74     : accepting(false),
     75       cancelled(false) {}
     76 
     77 BluetoothSocketChromeOS::ConnectionRequest::~ConnectionRequest() {}
     78 
     79 BluetoothSocketChromeOS::BluetoothSocketChromeOS(
     80     scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
     81     scoped_refptr<BluetoothSocketThread> socket_thread,
     82     net::NetLog* net_log,
     83     const net::NetLog::Source& source)
     84     : BluetoothSocketNet(ui_task_runner, socket_thread, net_log, source) {
     85 }
     86 
     87 BluetoothSocketChromeOS::~BluetoothSocketChromeOS() {
     88   DCHECK(object_path_.value().empty());
     89   DCHECK(profile_.get() == NULL);
     90 
     91   if (adapter_.get()) {
     92     adapter_->RemoveObserver(this);
     93     adapter_ = NULL;
     94   }
     95 }
     96 
     97 void BluetoothSocketChromeOS::Connect(
     98     const BluetoothDeviceChromeOS* device,
     99     const BluetoothUUID& uuid,
    100     const base::Closure& success_callback,
    101     const ErrorCompletionCallback& error_callback) {
    102   DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
    103   DCHECK(object_path_.value().empty());
    104   DCHECK(!profile_.get());
    105 
    106   if (!uuid.IsValid()) {
    107     error_callback.Run(kInvalidUUID);
    108     return;
    109   }
    110 
    111   device_address_ = device->GetAddress();
    112   device_path_ = device->object_path();
    113   uuid_ = uuid;
    114   options_.reset(new BluetoothProfileManagerClient::Options());
    115 
    116   RegisterProfile(success_callback, error_callback);
    117 }
    118 
    119 void BluetoothSocketChromeOS::Listen(
    120     scoped_refptr<BluetoothAdapter> adapter,
    121     SocketType socket_type,
    122     const BluetoothUUID& uuid,
    123     int psm_or_channel,
    124     const base::Closure& success_callback,
    125     const ErrorCompletionCallback& error_callback) {
    126   DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
    127   DCHECK(object_path_.value().empty());
    128   DCHECK(!profile_.get());
    129 
    130   if (!uuid.IsValid()) {
    131     error_callback.Run(kInvalidUUID);
    132     return;
    133   }
    134 
    135   adapter_ = adapter;
    136   adapter_->AddObserver(this);
    137 
    138   uuid_ = uuid;
    139   options_.reset(new BluetoothProfileManagerClient::Options());
    140 
    141   switch (socket_type) {
    142     case kRfcomm:
    143       options_->channel.reset(new uint16(
    144           psm_or_channel == BluetoothAdapter::kChannelAuto
    145               ? 0 : psm_or_channel));
    146       break;
    147     case kL2cap:
    148       options_->psm.reset(new uint16(
    149           psm_or_channel == BluetoothAdapter::kPsmAuto
    150               ? 0 : psm_or_channel));
    151       break;
    152     default:
    153       NOTREACHED();
    154   }
    155 
    156   RegisterProfile(success_callback, error_callback);
    157 }
    158 
    159 void BluetoothSocketChromeOS::Close() {
    160   DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
    161 
    162   if (profile_)
    163     UnregisterProfile();
    164 
    165   if (!device_path_.value().empty()) {
    166     BluetoothSocketNet::Close();
    167   } else {
    168     DoCloseListening();
    169   }
    170 }
    171 
    172 void BluetoothSocketChromeOS::Disconnect(const base::Closure& callback) {
    173   DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
    174 
    175   if (profile_)
    176    UnregisterProfile();
    177 
    178   if (!device_path_.value().empty()) {
    179     BluetoothSocketNet::Disconnect(callback);
    180   } else {
    181     DoCloseListening();
    182     callback.Run();
    183   }
    184 }
    185 
    186 void BluetoothSocketChromeOS::Accept(
    187     const AcceptCompletionCallback& success_callback,
    188     const ErrorCompletionCallback& error_callback) {
    189   DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
    190 
    191   if (!device_path_.value().empty()) {
    192     error_callback.Run(kSocketNotListening);
    193     return;
    194   }
    195 
    196   // Only one pending accept at a time
    197   if (accept_request_.get()) {
    198     error_callback.Run(net::ErrorToString(net::ERR_IO_PENDING));
    199     return;
    200   }
    201 
    202   accept_request_.reset(new AcceptRequest);
    203   accept_request_->success_callback = success_callback;
    204   accept_request_->error_callback = error_callback;
    205 
    206   if (connection_request_queue_.size() >= 1) {
    207     AcceptConnectionRequest();
    208   }
    209 }
    210 
    211 void BluetoothSocketChromeOS::RegisterProfile(
    212     const base::Closure& success_callback,
    213     const ErrorCompletionCallback& error_callback) {
    214   DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
    215   DCHECK(object_path_.value().empty());
    216   DCHECK(!profile_.get());
    217 
    218   // The object path is relatively meaningless, but has to be unique, so for
    219   // connecting profiles use a combination of the device address and profile
    220   // UUID.
    221   std::string device_address_path, uuid_path;
    222   base::ReplaceChars(device_address_, ":-", "_", &device_address_path);
    223   base::ReplaceChars(uuid_.canonical_value(), ":-", "_", &uuid_path);
    224   if (!device_address_path.empty()) {
    225     object_path_ = dbus::ObjectPath("/org/chromium/bluetooth_profile/" +
    226                                     device_address_path + "/" + uuid_path);
    227   } else {
    228     object_path_ = dbus::ObjectPath("/org/chromium/bluetooth_profile/" +
    229                                     uuid_path);
    230   }
    231 
    232   // Create the service provider for the profile object.
    233   dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus();
    234   profile_.reset(BluetoothProfileServiceProvider::Create(
    235       system_bus, object_path_, this));
    236   DCHECK(profile_.get());
    237 
    238   // Before reaching out to the Bluetooth Daemon to register a listening socket,
    239   // make sure it's actually running. If not, report success and carry on;
    240   // the profile will be registered when the daemon becomes available.
    241   if (adapter_ && !adapter_->IsPresent()) {
    242     VLOG(1) << object_path_.value() << ": Delaying profile registration.";
    243     success_callback.Run();
    244     return;
    245   }
    246 
    247   VLOG(1) << object_path_.value() << ": Registering profile.";
    248   DBusThreadManager::Get()->GetBluetoothProfileManagerClient()->
    249       RegisterProfile(
    250           object_path_,
    251           uuid_.canonical_value(),
    252           *options_,
    253           base::Bind(&BluetoothSocketChromeOS::OnRegisterProfile,
    254                      this,
    255                      success_callback,
    256                      error_callback),
    257           base::Bind(&BluetoothSocketChromeOS::OnRegisterProfileError,
    258                      this,
    259                      error_callback));
    260 }
    261 
    262 void BluetoothSocketChromeOS::OnRegisterProfile(
    263     const base::Closure& success_callback,
    264     const ErrorCompletionCallback& error_callback) {
    265   DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
    266   if (!device_path_.value().empty()) {
    267     VLOG(1) << object_path_.value() << ": Profile registered, connecting to "
    268             << device_path_.value();
    269 
    270     DBusThreadManager::Get()->GetBluetoothDeviceClient()->
    271         ConnectProfile(
    272             device_path_,
    273             uuid_.canonical_value(),
    274             base::Bind(
    275                 &BluetoothSocketChromeOS::OnConnectProfile,
    276                 this,
    277                 success_callback),
    278             base::Bind(
    279                 &BluetoothSocketChromeOS::OnConnectProfileError,
    280                 this,
    281                 error_callback));
    282   } else {
    283     VLOG(1) << object_path_.value() << ": Profile registered.";
    284     success_callback.Run();
    285   }
    286 }
    287 
    288 void BluetoothSocketChromeOS::OnRegisterProfileError(
    289     const ErrorCompletionCallback& error_callback,
    290     const std::string& error_name,
    291     const std::string& error_message) {
    292   DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
    293   LOG(WARNING) << object_path_.value() << ": Failed to register profile: "
    294                << error_name << ": " << error_message;
    295   error_callback.Run(error_message);
    296 }
    297 
    298 void BluetoothSocketChromeOS::OnConnectProfile(
    299     const base::Closure& success_callback) {
    300   DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
    301   VLOG(1) << object_path_.value() << ": Profile connected.";
    302   UnregisterProfile();
    303   success_callback.Run();
    304 }
    305 
    306 void BluetoothSocketChromeOS::OnConnectProfileError(
    307     const ErrorCompletionCallback& error_callback,
    308     const std::string& error_name,
    309     const std::string& error_message) {
    310   DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
    311   LOG(WARNING) << object_path_.value() << ": Failed to connect profile: "
    312                << error_name << ": " << error_message;
    313   UnregisterProfile();
    314   error_callback.Run(error_message);
    315 }
    316 
    317 void BluetoothSocketChromeOS::AdapterPresentChanged(BluetoothAdapter* adapter,
    318                                                     bool present) {
    319   DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
    320   DCHECK(!object_path_.value().empty());
    321   DCHECK(profile_.get());
    322 
    323   if (!present)
    324     return;
    325 
    326   VLOG(1) << object_path_.value() << ": Re-register profile.";
    327   DBusThreadManager::Get()->GetBluetoothProfileManagerClient()->
    328       RegisterProfile(
    329           object_path_,
    330           uuid_.canonical_value(),
    331           *options_,
    332           base::Bind(&BluetoothSocketChromeOS::OnInternalRegisterProfile,
    333                      this),
    334           base::Bind(&BluetoothSocketChromeOS::OnInternalRegisterProfileError,
    335                      this));
    336 }
    337 
    338 void BluetoothSocketChromeOS::OnInternalRegisterProfile() {
    339   DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
    340 
    341   VLOG(1) << object_path_.value() << ": Profile re-registered";
    342 }
    343 
    344 void BluetoothSocketChromeOS::OnInternalRegisterProfileError(
    345     const std::string& error_name,
    346     const std::string& error_message) {
    347   DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
    348 
    349   // It's okay if the profile already exists, it means we registered it on
    350   // initialization.
    351   if (error_name == bluetooth_profile_manager::kErrorAlreadyExists)
    352     return;
    353 
    354   LOG(WARNING) << object_path_.value() << ": Failed to re-register profile: "
    355                << error_name << ": " << error_message;
    356 }
    357 
    358 void BluetoothSocketChromeOS::Released() {
    359   DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
    360   VLOG(1) << object_path_.value() << ": Release";
    361 }
    362 
    363 void BluetoothSocketChromeOS::NewConnection(
    364     const dbus::ObjectPath& device_path,
    365     scoped_ptr<dbus::FileDescriptor> fd,
    366     const BluetoothProfileServiceProvider::Delegate::Options& options,
    367     const ConfirmationCallback& callback) {
    368   DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
    369   VLOG(1) << object_path_.value() << ": New connection from device: "
    370           << device_path.value();
    371 
    372   if (!device_path_.value().empty()) {
    373     DCHECK(device_path_ == device_path);
    374 
    375     socket_thread()->task_runner()->PostTask(
    376         FROM_HERE,
    377         base::Bind(
    378             &BluetoothSocketChromeOS::DoNewConnection,
    379             this,
    380             device_path_,
    381             base::Passed(&fd),
    382             options,
    383             callback));
    384   } else {
    385     linked_ptr<ConnectionRequest> request(new ConnectionRequest());
    386     request->device_path = device_path;
    387     request->fd = fd.Pass();
    388     request->options = options;
    389     request->callback = callback;
    390 
    391     connection_request_queue_.push(request);
    392     VLOG(1) << object_path_.value() << ": Connection is now pending.";
    393     if (accept_request_) {
    394       AcceptConnectionRequest();
    395     }
    396   }
    397 }
    398 
    399 void BluetoothSocketChromeOS::RequestDisconnection(
    400     const dbus::ObjectPath& device_path,
    401     const ConfirmationCallback& callback) {
    402   DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
    403   VLOG(1) << object_path_.value() << ": Request disconnection";
    404   callback.Run(SUCCESS);
    405 }
    406 
    407 void BluetoothSocketChromeOS::Cancel() {
    408   DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
    409   VLOG(1) << object_path_.value() << ": Cancel";
    410 
    411   if (!connection_request_queue_.size())
    412     return;
    413 
    414   // If the front request is being accepted mark it as cancelled, otherwise
    415   // just pop it from the queue.
    416   linked_ptr<ConnectionRequest> request = connection_request_queue_.front();
    417   if (!request->accepting) {
    418     request->cancelled = true;
    419   } else {
    420     connection_request_queue_.pop();
    421   }
    422 }
    423 
    424 void BluetoothSocketChromeOS::AcceptConnectionRequest() {
    425   DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
    426   DCHECK(accept_request_.get());
    427   DCHECK(connection_request_queue_.size() >= 1);
    428 
    429   VLOG(1) << object_path_.value() << ": Accepting pending connection.";
    430 
    431   linked_ptr<ConnectionRequest> request = connection_request_queue_.front();
    432   request->accepting = true;
    433 
    434   BluetoothDeviceChromeOS* device =
    435       static_cast<BluetoothAdapterChromeOS*>(adapter_.get())->
    436           GetDeviceWithPath(request->device_path);
    437   DCHECK(device);
    438 
    439   scoped_refptr<BluetoothSocketChromeOS> client_socket =
    440       BluetoothSocketChromeOS::CreateBluetoothSocket(
    441           ui_task_runner(),
    442           socket_thread(),
    443           net_log(),
    444           source());
    445 
    446   client_socket->device_address_ = device->GetAddress();
    447   client_socket->device_path_ = request->device_path;
    448   client_socket->uuid_ = uuid_;
    449 
    450   socket_thread()->task_runner()->PostTask(
    451       FROM_HERE,
    452       base::Bind(
    453           &BluetoothSocketChromeOS::DoNewConnection,
    454           client_socket,
    455           request->device_path,
    456           base::Passed(&request->fd),
    457           request->options,
    458           base::Bind(&BluetoothSocketChromeOS::OnNewConnection,
    459                      this,
    460                      client_socket,
    461                      request->callback)));
    462 }
    463 
    464 void BluetoothSocketChromeOS::DoNewConnection(
    465     const dbus::ObjectPath& device_path,
    466     scoped_ptr<dbus::FileDescriptor> fd,
    467     const BluetoothProfileServiceProvider::Delegate::Options& options,
    468     const ConfirmationCallback& callback) {
    469   DCHECK(socket_thread()->task_runner()->RunsTasksOnCurrentThread());
    470   base::ThreadRestrictions::AssertIOAllowed();
    471   fd->CheckValidity();
    472 
    473   VLOG(1) << object_path_.value() << ": Validity check complete.";
    474   if (!fd->is_valid()) {
    475     LOG(WARNING) << object_path_.value() << " :" << fd->value()
    476                  << ": Invalid file descriptor received from Bluetooth Daemon.";
    477     ui_task_runner()->PostTask(FROM_HERE,
    478                                base::Bind(callback, REJECTED));;
    479     return;
    480   }
    481 
    482   if (tcp_socket()) {
    483     LOG(WARNING) << object_path_.value() << ": Already connected";
    484     ui_task_runner()->PostTask(FROM_HERE,
    485                                base::Bind(callback, REJECTED));;
    486     return;
    487   }
    488 
    489   ResetTCPSocket();
    490 
    491   // Note: We don't have a meaningful |IPEndPoint|, but that is ok since the
    492   // TCPSocket implementation does not actually require one.
    493   int net_result = tcp_socket()->AdoptConnectedSocket(fd->value(),
    494                                                       net::IPEndPoint());
    495   if (net_result != net::OK) {
    496     LOG(WARNING) << object_path_.value() << ": Error adopting socket: "
    497                  << std::string(net::ErrorToString(net_result));
    498     ui_task_runner()->PostTask(FROM_HERE,
    499                                base::Bind(callback, REJECTED));;
    500     return;
    501   }
    502 
    503   VLOG(2) << object_path_.value() << ": Taking descriptor, confirming success.";
    504   fd->TakeValue();
    505   ui_task_runner()->PostTask(FROM_HERE,
    506                              base::Bind(callback, SUCCESS));;
    507 }
    508 
    509 void BluetoothSocketChromeOS::OnNewConnection(
    510     scoped_refptr<BluetoothSocket> socket,
    511     const ConfirmationCallback& callback,
    512     Status status) {
    513   DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
    514   DCHECK(accept_request_.get());
    515   DCHECK(connection_request_queue_.size() >= 1);
    516 
    517   linked_ptr<ConnectionRequest> request = connection_request_queue_.front();
    518   if (status == SUCCESS && !request->cancelled) {
    519     BluetoothDeviceChromeOS* device =
    520         static_cast<BluetoothAdapterChromeOS*>(adapter_.get())->
    521             GetDeviceWithPath(request->device_path);
    522     DCHECK(device);
    523 
    524     accept_request_->success_callback.Run(device, socket);
    525   } else {
    526     accept_request_->error_callback.Run(kAcceptFailed);
    527   }
    528 
    529   accept_request_.reset(NULL);
    530   connection_request_queue_.pop();
    531 
    532   callback.Run(status);
    533 }
    534 
    535 void BluetoothSocketChromeOS::DoCloseListening() {
    536   DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
    537 
    538   if (accept_request_) {
    539     accept_request_->error_callback.Run(
    540         net::ErrorToString(net::ERR_CONNECTION_CLOSED));
    541     accept_request_.reset(NULL);
    542   }
    543 
    544   while (connection_request_queue_.size() > 0) {
    545     linked_ptr<ConnectionRequest> request = connection_request_queue_.front();
    546     request->callback.Run(REJECTED);
    547     connection_request_queue_.pop();
    548   }
    549 }
    550 
    551 void BluetoothSocketChromeOS::UnregisterProfile() {
    552   DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
    553   DCHECK(!object_path_.value().empty());
    554   DCHECK(profile_.get());
    555 
    556   VLOG(1) << object_path_.value() << ": Unregister profile";
    557   DBusThreadManager::Get()->GetBluetoothProfileManagerClient()->
    558       UnregisterProfile(
    559           object_path_,
    560           base::Bind(&BluetoothSocketChromeOS::OnUnregisterProfile,
    561                      this,
    562                      object_path_),
    563           base::Bind(&BluetoothSocketChromeOS::OnUnregisterProfileError,
    564                      this,
    565                      object_path_));
    566 
    567   profile_.reset();
    568   object_path_ = dbus::ObjectPath("");
    569 }
    570 
    571 void BluetoothSocketChromeOS::OnUnregisterProfile(
    572     const dbus::ObjectPath& object_path) {
    573   VLOG(1) << object_path.value() << ": Profile unregistered";
    574 }
    575 
    576 void BluetoothSocketChromeOS::OnUnregisterProfileError(
    577     const dbus::ObjectPath& object_path,
    578     const std::string& error_name,
    579     const std::string& error_message) {
    580   // It's okay if the profile doesn't exist, it means we haven't registered it
    581   // yet.
    582   if (error_name == bluetooth_profile_manager::kErrorDoesNotExist)
    583     return;
    584 
    585   LOG(WARNING) << object_path_.value() << ": Failed to unregister profile: "
    586                << error_name << ": " << error_message;
    587 }
    588 
    589 }  // namespace chromeos
    590