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/message_loop/message_loop.h"
9 #include "base/numerics/safe_conversions.h"
10 #include "components/proximity_auth/remote_device.h"
11 #include "components/proximity_auth/wire_message.h"
12 #include "device/bluetooth/bluetooth_adapter_factory.h"
13 #include "device/bluetooth/bluetooth_device.h"
14 #include "net/base/io_buffer.h"
16 namespace proximity_auth
{
18 const int kReceiveBufferSizeBytes
= 1024;
21 BluetoothConnection::BluetoothConnection(const RemoteDevice
& remote_device
,
22 const device::BluetoothUUID
& uuid
)
23 : Connection(remote_device
), uuid_(uuid
), weak_ptr_factory_(this) {
26 BluetoothConnection::~BluetoothConnection() {
30 void BluetoothConnection::Connect() {
31 if (status() != DISCONNECTED
) {
33 << "[BC] Ignoring attempt to connect a non-disconnected connection.";
37 if (!device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) {
39 << "[BC] Connection failed: Bluetooth is unsupported on this platform.";
43 SetStatus(IN_PROGRESS
);
44 device::BluetoothAdapterFactory::GetAdapter(
45 base::Bind(&BluetoothConnection::OnAdapterInitialized
,
46 weak_ptr_factory_
.GetWeakPtr()));
49 void BluetoothConnection::Disconnect() {
50 if (status() == DISCONNECTED
) {
52 << "[BC] Ignoring attempt to disconnect a non-connected connection.";
56 // Set status as disconnected now, rather than after the socket closes, so
57 // this connection is not reused.
58 SetStatus(DISCONNECTED
);
60 socket_
->Disconnect(base::Bind(&base::DoNothing
));
64 adapter_
->RemoveObserver(this);
69 void BluetoothConnection::SendMessageImpl(scoped_ptr
<WireMessage
> message
) {
70 DCHECK_EQ(status(), CONNECTED
);
72 // Serialize the message.
73 std::string serialized_message
= message
->Serialize();
74 int message_length
= base::checked_cast
<int>(serialized_message
.size());
75 scoped_refptr
<net::IOBuffer
> buffer
= new net::IOBuffer(message_length
);
76 memcpy(buffer
->data(), serialized_message
.c_str(), message_length
);
79 pending_message_
= message
.Pass();
80 base::WeakPtr
<BluetoothConnection
> weak_this
= weak_ptr_factory_
.GetWeakPtr();
83 base::Bind(&BluetoothConnection::OnSend
, weak_this
),
84 base::Bind(&BluetoothConnection::OnSendError
, weak_this
));
87 void BluetoothConnection::DeviceRemoved(device::BluetoothAdapter
* adapter
,
88 device::BluetoothDevice
* device
) {
89 DCHECK_EQ(adapter
, adapter_
.get());
90 if (device
->GetAddress() != remote_device().bluetooth_address
)
93 DCHECK_NE(status(), DISCONNECTED
);
94 VLOG(1) << "[BC] Device disconnected...";
98 void BluetoothConnection::StartReceive() {
99 base::WeakPtr
<BluetoothConnection
> weak_this
= weak_ptr_factory_
.GetWeakPtr();
100 socket_
->Receive(kReceiveBufferSizeBytes
,
101 base::Bind(&BluetoothConnection::OnReceive
, weak_this
),
102 base::Bind(&BluetoothConnection::OnReceiveError
, weak_this
));
105 void BluetoothConnection::OnAdapterInitialized(
106 scoped_refptr
<device::BluetoothAdapter
> adapter
) {
107 const std::string address
= remote_device().bluetooth_address
;
108 device::BluetoothDevice
* bluetooth_device
= adapter
->GetDevice(address
);
109 if (!bluetooth_device
) {
110 VLOG(1) << "[BC] Device with address " << address
111 << " is not known to the system Bluetooth daemon.";
112 // TOOD(isherman): Optimistically attempt to seek the device and connect
113 // anyway, as was previously implemented in BluetoothConnectionFinder.
119 adapter_
->AddObserver(this);
121 base::WeakPtr
<BluetoothConnection
> weak_this
= weak_ptr_factory_
.GetWeakPtr();
122 bluetooth_device
->ConnectToServiceInsecurely(
124 base::Bind(&BluetoothConnection::OnConnected
, weak_this
),
125 base::Bind(&BluetoothConnection::OnConnectionError
, weak_this
));
128 void BluetoothConnection::OnConnected(
129 scoped_refptr
<device::BluetoothSocket
> socket
) {
130 if (status() != IN_PROGRESS
) {
131 // This case is reachable if the client of |this| connection called
132 // |Disconnect()| while the backing Bluetooth connection was pending.
133 DCHECK_EQ(status(), DISCONNECTED
);
134 VLOG(1) << "[BC] Ignoring successful backend Bluetooth connection to an "
135 << "already disconnected logical connection.";
139 VLOG(1) << "[BC] Connection established with "
140 << remote_device().bluetooth_address
;
142 SetStatus(CONNECTED
);
146 void BluetoothConnection::OnConnectionError(const std::string
& error_message
) {
147 VLOG(1) << "[BC] Connection failed: " << error_message
;
151 void BluetoothConnection::OnSend(int bytes_sent
) {
152 VLOG(1) << "[BC] Successfully sent " << bytes_sent
<< " bytes.";
153 OnDidSendMessage(*pending_message_
, true);
154 pending_message_
.reset();
157 void BluetoothConnection::OnSendError(const std::string
& error_message
) {
158 VLOG(1) << "[BC] Error when sending bytes: " << error_message
;
159 OnDidSendMessage(*pending_message_
, false);
160 pending_message_
.reset();
165 void BluetoothConnection::OnReceive(int bytes_received
,
166 scoped_refptr
<net::IOBuffer
> buffer
) {
167 VLOG(1) << "[BC] Received " << bytes_received
<< " bytes.";
168 OnBytesReceived(std::string(buffer
->data(), bytes_received
));
170 // Post a task to delay the read until the socket is available, as
171 // calling StartReceive at this point would error with ERR_IO_PENDING.
172 base::MessageLoop::current()->PostTask(
174 base::Bind(&BluetoothConnection::StartReceive
,
175 weak_ptr_factory_
.GetWeakPtr()));
178 void BluetoothConnection::OnReceiveError(
179 device::BluetoothSocket::ErrorReason error_reason
,
180 const std::string
& error_message
) {
181 VLOG(1) << "[BC] Error receiving bytes: " << error_message
;
183 // Post a task to delay the read until the socket is available, as
184 // calling StartReceive at this point would error with ERR_IO_PENDING.
185 base::MessageLoop::current()->PostTask(
187 base::Bind(&BluetoothConnection::StartReceive
,
188 weak_ptr_factory_
.GetWeakPtr()));
191 } // namespace proximity_auth