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