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/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
{
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
)
34 void BluetoothConnection::Connect() {
35 if (status() != DISCONNECTED
) {
37 << "Ignoring attempt to connect a non-disconnected connection.";
41 if (!device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) {
43 << "Connection failed: Bluetooth is unsupported on this platform.";
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
) {
56 << "Ignoring attempt to disconnect a non-connected connection.";
60 // Set status as disconnected now, rather than after the socket closes, so
61 // this connection is not reused.
62 SetStatus(DISCONNECTED
);
64 socket_
->Disconnect(base::Bind(&base::DoNothing
));
68 adapter_
->RemoveObserver(this);
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
);
83 pending_message_
= message
.Pass();
84 base::WeakPtr
<BluetoothConnection
> weak_this
= weak_ptr_factory_
.GetWeakPtr();
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
)
97 DCHECK_NE(status(), DISCONNECTED
);
98 PA_LOG(INFO
) << "Device disconnected...";
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.
123 adapter_
->AddObserver(this);
125 base::WeakPtr
<BluetoothConnection
> weak_this
= weak_ptr_factory_
.GetWeakPtr();
126 bluetooth_device
->ConnectToServiceInsecurely(
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.";
143 PA_LOG(INFO
) << "Connection established with "
144 << remote_device().bluetooth_address
;
146 SetStatus(CONNECTED
);
150 void BluetoothConnection::OnConnectionError(const std::string
& error_message
) {
151 PA_LOG(WARNING
) << "Connection failed: " << error_message
;
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();
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