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