Update mojo sdk to rev c02a28868825edfa57ab77947b8cb15e741c5598
[chromium-blink-merge.git] / components / proximity_auth / bluetooth_connection.cc
blobf06d52f6d260d05e435a8ebc3a091ecfe8425271
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.
5 #include "components/proximity_auth/bluetooth_connection.h"
7 #include "base/bind.h"
8 #include "base/location.h"
9 #include "base/numerics/safe_conversions.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/thread_task_runner_handle.h"
12 #include "components/proximity_auth/logging/logging.h"
13 #include "components/proximity_auth/remote_device.h"
14 #include "components/proximity_auth/wire_message.h"
15 #include "device/bluetooth/bluetooth_adapter_factory.h"
16 #include "device/bluetooth/bluetooth_device.h"
17 #include "net/base/io_buffer.h"
19 namespace proximity_auth {
20 namespace {
21 const int kReceiveBufferSizeBytes = 1024;
24 BluetoothConnection::BluetoothConnection(const RemoteDevice& remote_device,
25 const device::BluetoothUUID& uuid)
26 : Connection(remote_device), uuid_(uuid), weak_ptr_factory_(this) {
29 BluetoothConnection::~BluetoothConnection() {
30 if (status() != DISCONNECTED)
31 Disconnect();
34 void BluetoothConnection::Connect() {
35 if (status() != DISCONNECTED) {
36 PA_LOG(WARNING)
37 << "Ignoring attempt to connect a non-disconnected connection.";
38 return;
41 if (!device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) {
42 PA_LOG(WARNING)
43 << "Connection failed: Bluetooth is unsupported on this platform.";
44 return;
47 SetStatus(IN_PROGRESS);
48 device::BluetoothAdapterFactory::GetAdapter(
49 base::Bind(&BluetoothConnection::OnAdapterInitialized,
50 weak_ptr_factory_.GetWeakPtr()));
53 void BluetoothConnection::Disconnect() {
54 if (status() == DISCONNECTED) {
55 PA_LOG(WARNING)
56 << "Ignoring attempt to disconnect a non-connected connection.";
57 return;
60 // Set status as disconnected now, rather than after the socket closes, so
61 // this connection is not reused.
62 SetStatus(DISCONNECTED);
63 if (socket_.get()) {
64 socket_->Disconnect(base::Bind(&base::DoNothing));
65 socket_ = NULL;
67 if (adapter_.get()) {
68 adapter_->RemoveObserver(this);
69 adapter_ = NULL;
73 void BluetoothConnection::SendMessageImpl(scoped_ptr<WireMessage> message) {
74 DCHECK_EQ(status(), CONNECTED);
76 // Serialize the message.
77 std::string serialized_message = message->Serialize();
78 int message_length = base::checked_cast<int>(serialized_message.size());
79 scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(message_length);
80 memcpy(buffer->data(), serialized_message.c_str(), message_length);
82 // Send it.
83 pending_message_ = message.Pass();
84 base::WeakPtr<BluetoothConnection> weak_this = weak_ptr_factory_.GetWeakPtr();
85 socket_->Send(buffer,
86 message_length,
87 base::Bind(&BluetoothConnection::OnSend, weak_this),
88 base::Bind(&BluetoothConnection::OnSendError, weak_this));
91 void BluetoothConnection::DeviceRemoved(device::BluetoothAdapter* adapter,
92 device::BluetoothDevice* device) {
93 DCHECK_EQ(adapter, adapter_.get());
94 if (device->GetAddress() != remote_device().bluetooth_address)
95 return;
97 DCHECK_NE(status(), DISCONNECTED);
98 PA_LOG(INFO) << "Device disconnected...";
99 Disconnect();
102 void BluetoothConnection::StartReceive() {
103 base::WeakPtr<BluetoothConnection> weak_this = weak_ptr_factory_.GetWeakPtr();
104 socket_->Receive(kReceiveBufferSizeBytes,
105 base::Bind(&BluetoothConnection::OnReceive, weak_this),
106 base::Bind(&BluetoothConnection::OnReceiveError, weak_this));
109 void BluetoothConnection::OnAdapterInitialized(
110 scoped_refptr<device::BluetoothAdapter> adapter) {
111 const std::string address = remote_device().bluetooth_address;
112 device::BluetoothDevice* bluetooth_device = adapter->GetDevice(address);
113 if (!bluetooth_device) {
114 PA_LOG(WARNING) << "Device with address " << address
115 << " is not known to the system Bluetooth daemon.";
116 // TOOD(isherman): Optimistically attempt to seek the device and connect
117 // anyway, as was previously implemented in BluetoothConnectionFinder.
118 Disconnect();
119 return;
122 adapter_ = adapter;
123 adapter_->AddObserver(this);
125 base::WeakPtr<BluetoothConnection> weak_this = weak_ptr_factory_.GetWeakPtr();
126 bluetooth_device->ConnectToServiceInsecurely(
127 uuid_,
128 base::Bind(&BluetoothConnection::OnConnected, weak_this),
129 base::Bind(&BluetoothConnection::OnConnectionError, weak_this));
132 void BluetoothConnection::OnConnected(
133 scoped_refptr<device::BluetoothSocket> socket) {
134 if (status() != IN_PROGRESS) {
135 // This case is reachable if the client of |this| connection called
136 // |Disconnect()| while the backing Bluetooth connection was pending.
137 DCHECK_EQ(status(), DISCONNECTED);
138 PA_LOG(WARNING) << "Ignoring successful backend Bluetooth connection to an "
139 << "already disconnected logical connection.";
140 return;
143 PA_LOG(INFO) << "Connection established with "
144 << remote_device().bluetooth_address;
145 socket_ = socket;
146 SetStatus(CONNECTED);
147 StartReceive();
150 void BluetoothConnection::OnConnectionError(const std::string& error_message) {
151 PA_LOG(WARNING) << "Connection failed: " << error_message;
152 Disconnect();
155 void BluetoothConnection::OnSend(int bytes_sent) {
156 PA_LOG(INFO) << "Successfully sent " << bytes_sent << " bytes.";
157 OnDidSendMessage(*pending_message_, true);
158 pending_message_.reset();
161 void BluetoothConnection::OnSendError(const std::string& error_message) {
162 PA_LOG(WARNING) << "Error when sending bytes: " << error_message;
163 OnDidSendMessage(*pending_message_, false);
164 pending_message_.reset();
166 Disconnect();
169 void BluetoothConnection::OnReceive(int bytes_received,
170 scoped_refptr<net::IOBuffer> buffer) {
171 PA_LOG(INFO) << "Received " << bytes_received << " bytes.";
172 OnBytesReceived(std::string(buffer->data(), bytes_received));
174 // Post a task to delay the read until the socket is available, as
175 // calling StartReceive at this point would error with ERR_IO_PENDING.
176 base::ThreadTaskRunnerHandle::Get()->PostTask(
177 FROM_HERE, base::Bind(&BluetoothConnection::StartReceive,
178 weak_ptr_factory_.GetWeakPtr()));
181 void BluetoothConnection::OnReceiveError(
182 device::BluetoothSocket::ErrorReason error_reason,
183 const std::string& error_message) {
184 PA_LOG(WARNING) << "Error receiving bytes: " << error_message;
186 // Post a task to delay the read until the socket is available, as
187 // calling StartReceive at this point would error with ERR_IO_PENDING.
188 base::ThreadTaskRunnerHandle::Get()->PostTask(
189 FROM_HERE, base::Bind(&BluetoothConnection::StartReceive,
190 weak_ptr_factory_.GetWeakPtr()));
193 } // namespace proximity_auth