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"
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/remote_device.h"
13 #include "components/proximity_auth/wire_message.h"
14 #include "device/bluetooth/bluetooth_adapter_factory.h"
15 #include "device/bluetooth/bluetooth_device.h"
16 #include "net/base/io_buffer.h"
18 namespace proximity_auth
{
20 const int kReceiveBufferSizeBytes
= 1024;
23 BluetoothConnection::BluetoothConnection(const RemoteDevice
& remote_device
,
24 const device::BluetoothUUID
& uuid
)
25 : Connection(remote_device
), uuid_(uuid
), weak_ptr_factory_(this) {
28 BluetoothConnection::~BluetoothConnection() {
32 void BluetoothConnection::Connect() {
33 if (status() != DISCONNECTED
) {
35 << "[BC] Ignoring attempt to connect a non-disconnected connection.";
39 if (!device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) {
41 << "[BC] Connection failed: Bluetooth is unsupported on this platform.";
45 SetStatus(IN_PROGRESS
);
46 device::BluetoothAdapterFactory::GetAdapter(
47 base::Bind(&BluetoothConnection::OnAdapterInitialized
,
48 weak_ptr_factory_
.GetWeakPtr()));
51 void BluetoothConnection::Disconnect() {
52 if (status() == DISCONNECTED
) {
54 << "[BC] Ignoring attempt to disconnect a non-connected connection.";
58 // Set status as disconnected now, rather than after the socket closes, so
59 // this connection is not reused.
60 SetStatus(DISCONNECTED
);
62 socket_
->Disconnect(base::Bind(&base::DoNothing
));
66 adapter_
->RemoveObserver(this);
71 void BluetoothConnection::SendMessageImpl(scoped_ptr
<WireMessage
> message
) {
72 DCHECK_EQ(status(), CONNECTED
);
74 // Serialize the message.
75 std::string serialized_message
= message
->Serialize();
76 int message_length
= base::checked_cast
<int>(serialized_message
.size());
77 scoped_refptr
<net::IOBuffer
> buffer
= new net::IOBuffer(message_length
);
78 memcpy(buffer
->data(), serialized_message
.c_str(), message_length
);
81 pending_message_
= message
.Pass();
82 base::WeakPtr
<BluetoothConnection
> weak_this
= weak_ptr_factory_
.GetWeakPtr();
85 base::Bind(&BluetoothConnection::OnSend
, weak_this
),
86 base::Bind(&BluetoothConnection::OnSendError
, weak_this
));
89 void BluetoothConnection::DeviceRemoved(device::BluetoothAdapter
* adapter
,
90 device::BluetoothDevice
* device
) {
91 DCHECK_EQ(adapter
, adapter_
.get());
92 if (device
->GetAddress() != remote_device().bluetooth_address
)
95 DCHECK_NE(status(), DISCONNECTED
);
96 VLOG(1) << "[BC] Device disconnected...";
100 void BluetoothConnection::StartReceive() {
101 base::WeakPtr
<BluetoothConnection
> weak_this
= weak_ptr_factory_
.GetWeakPtr();
102 socket_
->Receive(kReceiveBufferSizeBytes
,
103 base::Bind(&BluetoothConnection::OnReceive
, weak_this
),
104 base::Bind(&BluetoothConnection::OnReceiveError
, weak_this
));
107 void BluetoothConnection::OnAdapterInitialized(
108 scoped_refptr
<device::BluetoothAdapter
> adapter
) {
109 const std::string address
= remote_device().bluetooth_address
;
110 device::BluetoothDevice
* bluetooth_device
= adapter
->GetDevice(address
);
111 if (!bluetooth_device
) {
112 VLOG(1) << "[BC] Device with address " << address
113 << " is not known to the system Bluetooth daemon.";
114 // TOOD(isherman): Optimistically attempt to seek the device and connect
115 // anyway, as was previously implemented in BluetoothConnectionFinder.
121 adapter_
->AddObserver(this);
123 base::WeakPtr
<BluetoothConnection
> weak_this
= weak_ptr_factory_
.GetWeakPtr();
124 bluetooth_device
->ConnectToServiceInsecurely(
126 base::Bind(&BluetoothConnection::OnConnected
, weak_this
),
127 base::Bind(&BluetoothConnection::OnConnectionError
, weak_this
));
130 void BluetoothConnection::OnConnected(
131 scoped_refptr
<device::BluetoothSocket
> socket
) {
132 if (status() != IN_PROGRESS
) {
133 // This case is reachable if the client of |this| connection called
134 // |Disconnect()| while the backing Bluetooth connection was pending.
135 DCHECK_EQ(status(), DISCONNECTED
);
136 VLOG(1) << "[BC] Ignoring successful backend Bluetooth connection to an "
137 << "already disconnected logical connection.";
141 VLOG(1) << "[BC] Connection established with "
142 << remote_device().bluetooth_address
;
144 SetStatus(CONNECTED
);
148 void BluetoothConnection::OnConnectionError(const std::string
& error_message
) {
149 VLOG(1) << "[BC] Connection failed: " << error_message
;
153 void BluetoothConnection::OnSend(int bytes_sent
) {
154 VLOG(1) << "[BC] Successfully sent " << bytes_sent
<< " bytes.";
155 OnDidSendMessage(*pending_message_
, true);
156 pending_message_
.reset();
159 void BluetoothConnection::OnSendError(const std::string
& error_message
) {
160 VLOG(1) << "[BC] Error when sending bytes: " << error_message
;
161 OnDidSendMessage(*pending_message_
, false);
162 pending_message_
.reset();
167 void BluetoothConnection::OnReceive(int bytes_received
,
168 scoped_refptr
<net::IOBuffer
> buffer
) {
169 VLOG(1) << "[BC] Received " << bytes_received
<< " bytes.";
170 OnBytesReceived(std::string(buffer
->data(), bytes_received
));
172 // Post a task to delay the read until the socket is available, as
173 // calling StartReceive at this point would error with ERR_IO_PENDING.
174 base::ThreadTaskRunnerHandle::Get()->PostTask(
175 FROM_HERE
, base::Bind(&BluetoothConnection::StartReceive
,
176 weak_ptr_factory_
.GetWeakPtr()));
179 void BluetoothConnection::OnReceiveError(
180 device::BluetoothSocket::ErrorReason error_reason
,
181 const std::string
& error_message
) {
182 VLOG(1) << "[BC] Error receiving bytes: " << error_message
;
184 // Post a task to delay the read until the socket is available, as
185 // calling StartReceive at this point would error with ERR_IO_PENDING.
186 base::ThreadTaskRunnerHandle::Get()->PostTask(
187 FROM_HERE
, base::Bind(&BluetoothConnection::StartReceive
,
188 weak_ptr_factory_
.GetWeakPtr()));
191 } // namespace proximity_auth