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 22 BluetoothConnection::BluetoothConnection(const RemoteDevice& remote_device, 23 const device::BluetoothUUID& uuid) 24 : Connection(remote_device), uuid_(uuid), weak_ptr_factory_(this) { 25 } 26 27 BluetoothConnection::~BluetoothConnection() { 28 Disconnect(); 29 } 30 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 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 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 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 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 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 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 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 156 void BluetoothConnection::OnConnectionError(const std::string& error_message) { 157 VLOG(1) << "[BC] Connection failed: " << error_message; 158 Disconnect(); 159 } 160 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 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 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 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