11320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Copyright 2014 The Chromium Authors. All rights reserved.
21320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Use of this source code is governed by a BSD-style license that can be
31320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// found in the LICENSE file.
41320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "components/proximity_auth/bluetooth_connection.h"
61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/bind.h"
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/message_loop/message_loop.h"
91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/numerics/safe_conversions.h"
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "components/proximity_auth/bluetooth_util.h"
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "components/proximity_auth/remote_device.h"
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "components/proximity_auth/wire_message.h"
131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "device/bluetooth/bluetooth_adapter_factory.h"
141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "device/bluetooth/bluetooth_device.h"
151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "net/base/io_buffer.h"
161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace proximity_auth {
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace {
191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst int kReceiveBufferSizeBytes = 1024;
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciBluetoothConnection::BluetoothConnection(const RemoteDevice& remote_device,
231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                         const device::BluetoothUUID& uuid)
241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    : Connection(remote_device), uuid_(uuid), weak_ptr_factory_(this) {
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciBluetoothConnection::~BluetoothConnection() {
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Disconnect();
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid BluetoothConnection::Connect() {
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (status() != DISCONNECTED) {
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    VLOG(1)
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        << "[BC] Ignoring attempt to connect a non-disconnected connection.";
351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) {
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    VLOG(1)
401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        << "[BC] Connection failed: Bluetooth is unsupported on this platform.";
411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  SetStatus(IN_PROGRESS);
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  device::BluetoothAdapterFactory::GetAdapter(
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&BluetoothConnection::OnAdapterInitialized,
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 weak_ptr_factory_.GetWeakPtr()));
481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid BluetoothConnection::Disconnect() {
511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (status() == DISCONNECTED) {
521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    VLOG(1)
531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        << "[BC] Ignoring attempt to disconnect a non-connected connection.";
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Set status as disconnected now, rather than after the socket closes, so
581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // this connection is not reused.
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  SetStatus(DISCONNECTED);
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (socket_.get()) {
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    socket_->Disconnect(base::Bind(&base::DoNothing));
621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    socket_ = NULL;
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (adapter_.get()) {
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    adapter_->RemoveObserver(this);
661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    adapter_ = NULL;
671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid BluetoothConnection::SendMessageImpl(scoped_ptr<WireMessage> message) {
711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK_EQ(status(), CONNECTED);
721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Serialize the message.
741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::string serialized_message = message->Serialize();
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  int message_length = base::checked_cast<int>(serialized_message.size());
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(message_length);
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  memcpy(buffer->data(), serialized_message.c_str(), message_length);
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Send it.
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  pending_message_ = message.Pass();
811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  base::WeakPtr<BluetoothConnection> weak_this = weak_ptr_factory_.GetWeakPtr();
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  socket_->Send(buffer,
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                message_length,
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                base::Bind(&BluetoothConnection::OnSend, weak_this),
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                base::Bind(&BluetoothConnection::OnSendError, weak_this));
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid BluetoothConnection::DeviceRemoved(device::BluetoothAdapter* adapter,
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                        device::BluetoothDevice* device) {
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK_EQ(adapter, adapter_.get());
911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (device->GetAddress() != remote_device().bluetooth_address)
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK_NE(status(), DISCONNECTED);
951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  VLOG(1) << "[BC] Device disconnected...";
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Disconnect();
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid BluetoothConnection::ConnectToService(
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    device::BluetoothDevice* device,
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const device::BluetoothUUID& uuid,
1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const device::BluetoothDevice::ConnectToServiceCallback& callback,
1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const device::BluetoothDevice::ConnectToServiceErrorCallback&
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        error_callback) {
1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  bluetooth_util::ConnectToServiceInsecurely(
1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      device, uuid, callback, error_callback);
1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid BluetoothConnection::StartReceive() {
1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  base::WeakPtr<BluetoothConnection> weak_this = weak_ptr_factory_.GetWeakPtr();
1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  socket_->Receive(kReceiveBufferSizeBytes,
1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                   base::Bind(&BluetoothConnection::OnReceive, weak_this),
1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                   base::Bind(&BluetoothConnection::OnReceiveError, weak_this));
1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid BluetoothConnection::OnAdapterInitialized(
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    scoped_refptr<device::BluetoothAdapter> adapter) {
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const std::string address = remote_device().bluetooth_address;
1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  device::BluetoothDevice* bluetooth_device = adapter->GetDevice(address);
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!bluetooth_device) {
1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    VLOG(1) << "[BC] Device with address " << address
1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            << " is not known to the system Bluetooth daemon.";
1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    Disconnect();
1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  adapter_ = adapter;
1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  adapter_->AddObserver(this);
1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  base::WeakPtr<BluetoothConnection> weak_this = weak_ptr_factory_.GetWeakPtr();
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ConnectToService(
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      bluetooth_device,
1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      uuid_,
1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&BluetoothConnection::OnConnected, weak_this),
1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&BluetoothConnection::OnConnectionError, weak_this));
1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid BluetoothConnection::OnConnected(
1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    scoped_refptr<device::BluetoothSocket> socket) {
1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (status() != IN_PROGRESS) {
1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // This case is reachable if the client of |this| connection called
1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // |Disconnect()| while the backing Bluetooth connection was pending.
1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DCHECK_EQ(status(), DISCONNECTED);
1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    VLOG(1) << "[BC] Ignoring successful backend Bluetooth connection to an "
1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            << "already disconnected logical connection.";
1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  VLOG(1) << "[BC] Connection established with "
1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          << remote_device().bluetooth_address;
1511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  socket_ = socket;
1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  SetStatus(CONNECTED);
1531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  StartReceive();
1541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid BluetoothConnection::OnConnectionError(const std::string& error_message) {
1571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  VLOG(1) << "[BC] Connection failed: " << error_message;
1581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Disconnect();
1591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid BluetoothConnection::OnSend(int bytes_sent) {
1621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  VLOG(1) << "[BC] Successfully sent " << bytes_sent << " bytes.";
1631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  OnDidSendMessage(*pending_message_, true);
1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  pending_message_.reset();
1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid BluetoothConnection::OnSendError(const std::string& error_message) {
1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  VLOG(1) << "[BC] Error when sending bytes: " << error_message;
1691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  OnDidSendMessage(*pending_message_, false);
1701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  pending_message_.reset();
1711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Disconnect();
1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid BluetoothConnection::OnReceive(int bytes_received,
1761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                    scoped_refptr<net::IOBuffer> buffer) {
1771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  VLOG(1) << "[BC] Received " << bytes_received << " bytes.";
1781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  OnBytesReceived(std::string(buffer->data(), bytes_received));
1791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Post a task to delay the read until the socket is available, as
1811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // calling StartReceive at this point would error with ERR_IO_PENDING.
1821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  base::MessageLoop::current()->PostTask(
1831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      FROM_HERE,
1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&BluetoothConnection::StartReceive,
1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 weak_ptr_factory_.GetWeakPtr()));
1861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid BluetoothConnection::OnReceiveError(
1891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    device::BluetoothSocket::ErrorReason error_reason,
1901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::string& error_message) {
1911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  VLOG(1) << "[BC] Error receiving bytes: " << error_message;
1921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Post a task to delay the read until the socket is available, as
1941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // calling StartReceive at this point would error with ERR_IO_PENDING.
1951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  base::MessageLoop::current()->PostTask(
1961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      FROM_HERE,
1971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&BluetoothConnection::StartReceive,
1981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 weak_ptr_factory_.GetWeakPtr()));
1991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}  // namespace proximity_auth
202