Home | History | Annotate | Download | only in proximity_auth
      1 // Copyright 2014 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 "components/proximity_auth/bluetooth_connection.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/message_loop/message_loop.h"
      9 #include "base/numerics/safe_conversions.h"
     10 #include "components/proximity_auth/bluetooth_util.h"
     11 #include "components/proximity_auth/remote_device.h"
     12 #include "components/proximity_auth/wire_message.h"
     13 #include "device/bluetooth/bluetooth_adapter_factory.h"
     14 #include "device/bluetooth/bluetooth_device.h"
     15 #include "net/base/io_buffer.h"
     16 
     17 namespace proximity_auth {
     18 namespace {
     19 const int kReceiveBufferSizeBytes = 1024;
     20 }
     21 
     22 BluetoothConnection::BluetoothConnection(const RemoteDevice& remote_device,
     23                                          const device::BluetoothUUID& uuid)
     24     : Connection(remote_device), uuid_(uuid), weak_ptr_factory_(this) {
     25 }
     26 
     27 BluetoothConnection::~BluetoothConnection() {
     28   Disconnect();
     29 }
     30 
     31 void BluetoothConnection::Connect() {
     32   if (status() != DISCONNECTED) {
     33     VLOG(1)
     34         << "[BC] Ignoring attempt to connect a non-disconnected connection.";
     35     return;
     36   }
     37 
     38   if (!device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) {
     39     VLOG(1)
     40         << "[BC] Connection failed: Bluetooth is unsupported on this platform.";
     41     return;
     42   }
     43 
     44   SetStatus(IN_PROGRESS);
     45   device::BluetoothAdapterFactory::GetAdapter(
     46       base::Bind(&BluetoothConnection::OnAdapterInitialized,
     47                  weak_ptr_factory_.GetWeakPtr()));
     48 }
     49 
     50 void BluetoothConnection::Disconnect() {
     51   if (status() == DISCONNECTED) {
     52     VLOG(1)
     53         << "[BC] Ignoring attempt to disconnect a non-connected connection.";
     54     return;
     55   }
     56 
     57   // Set status as disconnected now, rather than after the socket closes, so
     58   // this connection is not reused.
     59   SetStatus(DISCONNECTED);
     60   if (socket_.get()) {
     61     socket_->Disconnect(base::Bind(&base::DoNothing));
     62     socket_ = NULL;
     63   }
     64   if (adapter_.get()) {
     65     adapter_->RemoveObserver(this);
     66     adapter_ = NULL;
     67   }
     68 }
     69 
     70 void BluetoothConnection::SendMessageImpl(scoped_ptr<WireMessage> message) {
     71   DCHECK_EQ(status(), CONNECTED);
     72 
     73   // Serialize the message.
     74   std::string serialized_message = message->Serialize();
     75   int message_length = base::checked_cast<int>(serialized_message.size());
     76   scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(message_length);
     77   memcpy(buffer->data(), serialized_message.c_str(), message_length);
     78 
     79   // Send it.
     80   pending_message_ = message.Pass();
     81   base::WeakPtr<BluetoothConnection> weak_this = weak_ptr_factory_.GetWeakPtr();
     82   socket_->Send(buffer,
     83                 message_length,
     84                 base::Bind(&BluetoothConnection::OnSend, weak_this),
     85                 base::Bind(&BluetoothConnection::OnSendError, weak_this));
     86 }
     87 
     88 void BluetoothConnection::DeviceRemoved(device::BluetoothAdapter* adapter,
     89                                         device::BluetoothDevice* device) {
     90   DCHECK_EQ(adapter, adapter_.get());
     91   if (device->GetAddress() != remote_device().bluetooth_address)
     92     return;
     93 
     94   DCHECK_NE(status(), DISCONNECTED);
     95   VLOG(1) << "[BC] Device disconnected...";
     96   Disconnect();
     97 }
     98 
     99 void BluetoothConnection::ConnectToService(
    100     device::BluetoothDevice* device,
    101     const device::BluetoothUUID& uuid,
    102     const device::BluetoothDevice::ConnectToServiceCallback& callback,
    103     const device::BluetoothDevice::ConnectToServiceErrorCallback&
    104         error_callback) {
    105   bluetooth_util::ConnectToServiceInsecurely(
    106       device, uuid, callback, error_callback);
    107 }
    108 
    109 void BluetoothConnection::StartReceive() {
    110   base::WeakPtr<BluetoothConnection> weak_this = weak_ptr_factory_.GetWeakPtr();
    111   socket_->Receive(kReceiveBufferSizeBytes,
    112                    base::Bind(&BluetoothConnection::OnReceive, weak_this),
    113                    base::Bind(&BluetoothConnection::OnReceiveError, weak_this));
    114 }
    115 
    116 void BluetoothConnection::OnAdapterInitialized(
    117     scoped_refptr<device::BluetoothAdapter> adapter) {
    118   const std::string address = remote_device().bluetooth_address;
    119   device::BluetoothDevice* bluetooth_device = adapter->GetDevice(address);
    120   if (!bluetooth_device) {
    121     VLOG(1) << "[BC] Device with address " << address
    122             << " is not known to the system Bluetooth daemon.";
    123     Disconnect();
    124     return;
    125   }
    126 
    127   adapter_ = adapter;
    128   adapter_->AddObserver(this);
    129 
    130   base::WeakPtr<BluetoothConnection> weak_this = weak_ptr_factory_.GetWeakPtr();
    131   ConnectToService(
    132       bluetooth_device,
    133       uuid_,
    134       base::Bind(&BluetoothConnection::OnConnected, weak_this),
    135       base::Bind(&BluetoothConnection::OnConnectionError, weak_this));
    136 }
    137 
    138 void BluetoothConnection::OnConnected(
    139     scoped_refptr<device::BluetoothSocket> socket) {
    140   if (status() != IN_PROGRESS) {
    141     // This case is reachable if the client of |this| connection called
    142     // |Disconnect()| while the backing Bluetooth connection was pending.
    143     DCHECK_EQ(status(), DISCONNECTED);
    144     VLOG(1) << "[BC] Ignoring successful backend Bluetooth connection to an "
    145             << "already disconnected logical connection.";
    146     return;
    147   }
    148 
    149   VLOG(1) << "[BC] Connection established with "
    150           << remote_device().bluetooth_address;
    151   socket_ = socket;
    152   SetStatus(CONNECTED);
    153   StartReceive();
    154 }
    155 
    156 void BluetoothConnection::OnConnectionError(const std::string& error_message) {
    157   VLOG(1) << "[BC] Connection failed: " << error_message;
    158   Disconnect();
    159 }
    160 
    161 void BluetoothConnection::OnSend(int bytes_sent) {
    162   VLOG(1) << "[BC] Successfully sent " << bytes_sent << " bytes.";
    163   OnDidSendMessage(*pending_message_, true);
    164   pending_message_.reset();
    165 }
    166 
    167 void BluetoothConnection::OnSendError(const std::string& error_message) {
    168   VLOG(1) << "[BC] Error when sending bytes: " << error_message;
    169   OnDidSendMessage(*pending_message_, false);
    170   pending_message_.reset();
    171 
    172   Disconnect();
    173 }
    174 
    175 void BluetoothConnection::OnReceive(int bytes_received,
    176                                     scoped_refptr<net::IOBuffer> buffer) {
    177   VLOG(1) << "[BC] Received " << bytes_received << " bytes.";
    178   OnBytesReceived(std::string(buffer->data(), bytes_received));
    179 
    180   // Post a task to delay the read until the socket is available, as
    181   // calling StartReceive at this point would error with ERR_IO_PENDING.
    182   base::MessageLoop::current()->PostTask(
    183       FROM_HERE,
    184       base::Bind(&BluetoothConnection::StartReceive,
    185                  weak_ptr_factory_.GetWeakPtr()));
    186 }
    187 
    188 void BluetoothConnection::OnReceiveError(
    189     device::BluetoothSocket::ErrorReason error_reason,
    190     const std::string& error_message) {
    191   VLOG(1) << "[BC] Error receiving bytes: " << error_message;
    192 
    193   // Post a task to delay the read until the socket is available, as
    194   // calling StartReceive at this point would error with ERR_IO_PENDING.
    195   base::MessageLoop::current()->PostTask(
    196       FROM_HERE,
    197       base::Bind(&BluetoothConnection::StartReceive,
    198                  weak_ptr_factory_.GetWeakPtr()));
    199 }
    200 
    201 }  // namespace proximity_auth
    202