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
BluetoothConnection(const RemoteDevice & remote_device,const device::BluetoothUUID & uuid)22 BluetoothConnection::BluetoothConnection(const RemoteDevice& remote_device,
23 const device::BluetoothUUID& uuid)
24 : Connection(remote_device), uuid_(uuid), weak_ptr_factory_(this) {
25 }
26
~BluetoothConnection()27 BluetoothConnection::~BluetoothConnection() {
28 Disconnect();
29 }
30
Connect()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
Disconnect()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
SendMessageImpl(scoped_ptr<WireMessage> message)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
DeviceRemoved(device::BluetoothAdapter * adapter,device::BluetoothDevice * device)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
ConnectToService(device::BluetoothDevice * device,const device::BluetoothUUID & uuid,const device::BluetoothDevice::ConnectToServiceCallback & callback,const device::BluetoothDevice::ConnectToServiceErrorCallback & error_callback)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
StartReceive()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
OnAdapterInitialized(scoped_refptr<device::BluetoothAdapter> adapter)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
OnConnected(scoped_refptr<device::BluetoothSocket> socket)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
OnConnectionError(const std::string & error_message)156 void BluetoothConnection::OnConnectionError(const std::string& error_message) {
157 VLOG(1) << "[BC] Connection failed: " << error_message;
158 Disconnect();
159 }
160
OnSend(int bytes_sent)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
OnSendError(const std::string & error_message)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
OnReceive(int bytes_received,scoped_refptr<net::IOBuffer> buffer)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
OnReceiveError(device::BluetoothSocket::ErrorReason error_reason,const std::string & error_message)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