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/pairing/bluetooth_host_pairing_controller.h" 6 7#include "base/bind.h" 8#include "base/hash.h" 9#include "base/logging.h" 10#include "base/strings/stringprintf.h" 11#include "components/pairing/bluetooth_pairing_constants.h" 12#include "components/pairing/pairing_api.pb.h" 13#include "components/pairing/proto_decoder.h" 14#include "device/bluetooth/bluetooth_adapter_factory.h" 15#include "net/base/io_buffer.h" 16 17namespace { 18const int kReceiveSize = 16384; 19} 20 21namespace pairing_chromeos { 22 23BluetoothHostPairingController::BluetoothHostPairingController() 24 : current_stage_(STAGE_NONE), 25 device_(NULL), 26 proto_decoder_(new ProtoDecoder(this)), 27 ptr_factory_(this) { 28} 29 30BluetoothHostPairingController::~BluetoothHostPairingController() { 31 if (adapter_.get()) { 32 if (adapter_->IsDiscoverable()) { 33 adapter_->SetDiscoverable(false, base::Closure(), base::Closure()); 34 } 35 adapter_->RemoveObserver(this); 36 adapter_ = NULL; 37 } 38} 39 40void BluetoothHostPairingController::ChangeStage(Stage new_stage) { 41 if (current_stage_ == new_stage) 42 return; 43 current_stage_ = new_stage; 44 FOR_EACH_OBSERVER(Observer, observers_, PairingStageChanged(new_stage)); 45} 46 47void BluetoothHostPairingController::SendHostStatus() { 48 pairing_api::HostStatus host_status; 49 50 host_status.set_api_version(kPairingAPIVersion); 51 if (!enrollment_domain_.empty()) 52 host_status.mutable_parameters()->set_domain(enrollment_domain_); 53 54 // TODO(zork): Get these values from the UI. (http://crbug.com/405744) 55 host_status.mutable_parameters()->set_connectivity( 56 pairing_api::HostStatusParameters::CONNECTIVITY_CONNECTED); 57 host_status.mutable_parameters()->set_update_status( 58 pairing_api::HostStatusParameters::UPDATE_STATUS_UPDATED); 59 60 // TODO(zork): Get a list of other paired controllers. 61 // (http://crbug.com/405757) 62 63 int size = 0; 64 scoped_refptr<net::IOBuffer> io_buffer( 65 ProtoDecoder::SendHostStatus(host_status, &size)); 66 67 controller_socket_->Send( 68 io_buffer, size, 69 base::Bind(&BluetoothHostPairingController::OnSendComplete, 70 ptr_factory_.GetWeakPtr()), 71 base::Bind(&BluetoothHostPairingController::OnSendError, 72 ptr_factory_.GetWeakPtr())); 73} 74 75void BluetoothHostPairingController::AbortWithError( 76 int code, 77 const std::string& message) { 78 if (controller_socket_.get()) { 79 pairing_api::Error error; 80 81 error.set_api_version(kPairingAPIVersion); 82 error.mutable_parameters()->set_code(PAIRING_ERROR_PAIRING_OR_ENROLLMENT); 83 error.mutable_parameters()->set_description(message); 84 85 int size = 0; 86 scoped_refptr<net::IOBuffer> io_buffer( 87 ProtoDecoder::SendError(error, &size)); 88 89 controller_socket_->Send( 90 io_buffer, size, 91 base::Bind(&BluetoothHostPairingController::OnSendComplete, 92 ptr_factory_.GetWeakPtr()), 93 base::Bind(&BluetoothHostPairingController::OnSendError, 94 ptr_factory_.GetWeakPtr())); 95 } 96 Reset(); 97} 98 99void BluetoothHostPairingController::Reset() { 100 if (controller_socket_.get()) { 101 controller_socket_->Close(); 102 controller_socket_ = NULL; 103 } 104 105 if (service_socket_.get()) { 106 service_socket_->Close(); 107 service_socket_ = NULL; 108 } 109 ChangeStage(STAGE_NONE); 110} 111 112void BluetoothHostPairingController::OnGetAdapter( 113 scoped_refptr<device::BluetoothAdapter> adapter) { 114 DCHECK(thread_checker_.CalledOnValidThread()); 115 DCHECK(!adapter_.get()); 116 adapter_ = adapter; 117 118 if (adapter_->IsPresent()) { 119 SetName(); 120 } else { 121 // Set the name once the adapter is present. 122 adapter_->AddObserver(this); 123 } 124} 125 126void BluetoothHostPairingController::SetName() { 127 // Hash the bluetooth address and take the lower 2 bytes to create a human 128 // readable device name. 129 const uint32 device_id = base::Hash(adapter_->GetAddress()) & 0xFFFF; 130 device_name_ = base::StringPrintf("%s%04X", kDeviceNamePrefix, device_id); 131 132 adapter_->SetName( 133 device_name_, 134 base::Bind(&BluetoothHostPairingController::OnSetName, 135 ptr_factory_.GetWeakPtr()), 136 base::Bind(&BluetoothHostPairingController::OnSetError, 137 ptr_factory_.GetWeakPtr())); 138} 139 140void BluetoothHostPairingController::OnSetName() { 141 DCHECK(thread_checker_.CalledOnValidThread()); 142 if (adapter_->IsPowered()) { 143 OnSetPowered(); 144 } else { 145 adapter_->SetPowered( 146 true, 147 base::Bind(&BluetoothHostPairingController::OnSetPowered, 148 ptr_factory_.GetWeakPtr()), 149 base::Bind(&BluetoothHostPairingController::OnSetError, 150 ptr_factory_.GetWeakPtr())); 151 } 152} 153 154void BluetoothHostPairingController::OnSetPowered() { 155 DCHECK(thread_checker_.CalledOnValidThread()); 156 adapter_->AddPairingDelegate( 157 this, device::BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH); 158 159 device::BluetoothAdapter::ServiceOptions options; 160 options.name.reset(new std::string(kPairingServiceName)); 161 162 adapter_->CreateRfcommService( 163 device::BluetoothUUID(kPairingServiceUUID), options, 164 base::Bind(&BluetoothHostPairingController::OnCreateService, 165 ptr_factory_.GetWeakPtr()), 166 base::Bind(&BluetoothHostPairingController::OnCreateServiceError, 167 ptr_factory_.GetWeakPtr())); 168} 169 170void BluetoothHostPairingController::OnCreateService( 171 scoped_refptr<device::BluetoothSocket> socket) { 172 DCHECK(thread_checker_.CalledOnValidThread()); 173 service_socket_ = socket; 174 175 service_socket_->Accept( 176 base::Bind(&BluetoothHostPairingController::OnAccept, 177 ptr_factory_.GetWeakPtr()), 178 base::Bind(&BluetoothHostPairingController::OnAcceptError, 179 ptr_factory_.GetWeakPtr())); 180 181 adapter_->SetDiscoverable( 182 true, 183 base::Bind(&BluetoothHostPairingController::OnSetDiscoverable, 184 ptr_factory_.GetWeakPtr(), true), 185 base::Bind(&BluetoothHostPairingController::OnSetError, 186 ptr_factory_.GetWeakPtr())); 187} 188 189void BluetoothHostPairingController::OnAccept( 190 const device::BluetoothDevice* device, 191 scoped_refptr<device::BluetoothSocket> socket) { 192 DCHECK(thread_checker_.CalledOnValidThread()); 193 adapter_->SetDiscoverable( 194 false, 195 base::Bind(&BluetoothHostPairingController::OnSetDiscoverable, 196 ptr_factory_.GetWeakPtr(), false), 197 base::Bind(&BluetoothHostPairingController::OnSetError, 198 ptr_factory_.GetWeakPtr())); 199 200 controller_socket_ = socket; 201 service_socket_ = NULL; 202 203 // TODO: Update Host. (http://crbug.com/405754) 204 SendHostStatus(); 205 206 controller_socket_->Receive( 207 kReceiveSize, 208 base::Bind(&BluetoothHostPairingController::OnReceiveComplete, 209 ptr_factory_.GetWeakPtr()), 210 base::Bind(&BluetoothHostPairingController::OnReceiveError, 211 ptr_factory_.GetWeakPtr())); 212 213 ChangeStage(STAGE_WAITING_FOR_CREDENTIALS); 214} 215 216void BluetoothHostPairingController::OnSetDiscoverable(bool change_stage) { 217 DCHECK(thread_checker_.CalledOnValidThread()); 218 if (change_stage) { 219 DCHECK_EQ(current_stage_, STAGE_NONE); 220 ChangeStage(STAGE_WAITING_FOR_CONTROLLER); 221 } 222} 223 224void BluetoothHostPairingController::OnSendComplete(int bytes_sent) {} 225 226void BluetoothHostPairingController::OnReceiveComplete( 227 int bytes, scoped_refptr<net::IOBuffer> io_buffer) { 228 DCHECK(thread_checker_.CalledOnValidThread()); 229 proto_decoder_->DecodeIOBuffer(bytes, io_buffer); 230 231 controller_socket_->Receive( 232 kReceiveSize, 233 base::Bind(&BluetoothHostPairingController::OnReceiveComplete, 234 ptr_factory_.GetWeakPtr()), 235 base::Bind(&BluetoothHostPairingController::OnReceiveError, 236 ptr_factory_.GetWeakPtr())); 237} 238 239void BluetoothHostPairingController::OnCreateServiceError( 240 const std::string& message) { 241 LOG(ERROR) << message; 242 ChangeStage(STAGE_INITIALIZATION_ERROR); 243} 244 245void BluetoothHostPairingController::OnSetError() { 246 adapter_->RemovePairingDelegate(this); 247 ChangeStage(STAGE_INITIALIZATION_ERROR); 248} 249 250void BluetoothHostPairingController::OnAcceptError( 251 const std::string& error_message) { 252 LOG(ERROR) << error_message; 253} 254 255void BluetoothHostPairingController::OnSendError( 256 const std::string& error_message) { 257 LOG(ERROR) << error_message; 258} 259 260void BluetoothHostPairingController::OnReceiveError( 261 device::BluetoothSocket::ErrorReason reason, 262 const std::string& error_message) { 263 LOG(ERROR) << reason << ", " << error_message; 264} 265 266void BluetoothHostPairingController::OnHostStatusMessage( 267 const pairing_api::HostStatus& message) { 268 NOTREACHED(); 269} 270 271void BluetoothHostPairingController::OnConfigureHostMessage( 272 const pairing_api::ConfigureHost& message) { 273 FOR_EACH_OBSERVER(Observer, observers_, 274 ConfigureHost(message.parameters().accepted_eula(), 275 message.parameters().lang(), 276 message.parameters().timezone(), 277 message.parameters().send_reports(), 278 message.parameters().keyboard_layout())); 279} 280 281void BluetoothHostPairingController::OnPairDevicesMessage( 282 const pairing_api::PairDevices& message) { 283 DCHECK(thread_checker_.CalledOnValidThread()); 284 if (current_stage_ != STAGE_WAITING_FOR_CREDENTIALS) { 285 AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT, kErrorInvalidProtocol); 286 return; 287 } 288 289 ChangeStage(STAGE_ENROLLING); 290 FOR_EACH_OBSERVER(Observer, observers_, 291 EnrollHost(message.parameters().admin_access_token())); 292} 293 294void BluetoothHostPairingController::SetEnrollmentComplete(bool success) { 295 DCHECK_EQ(current_stage_, STAGE_ENROLLING); 296 DCHECK(thread_checker_.CalledOnValidThread()); 297 if (success) { 298 ChangeStage(STAGE_PAIRING_DONE); 299 SendHostStatus(); 300 } else { 301 AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT, kErrorEnrollmentFailed); 302 } 303} 304 305void BluetoothHostPairingController::OnCompleteSetupMessage( 306 const pairing_api::CompleteSetup& message) { 307 DCHECK(thread_checker_.CalledOnValidThread()); 308 if (current_stage_ != STAGE_PAIRING_DONE) { 309 AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT, kErrorInvalidProtocol); 310 return; 311 } 312 313 // TODO(zork): Handle adding another controller. (http://crbug.com/405757) 314 ChangeStage(STAGE_FINISHED); 315} 316 317void BluetoothHostPairingController::OnErrorMessage( 318 const pairing_api::Error& message) { 319 NOTREACHED(); 320} 321 322void BluetoothHostPairingController::AdapterPresentChanged( 323 device::BluetoothAdapter* adapter, 324 bool present) { 325 DCHECK_EQ(adapter, adapter_.get()); 326 if (present) { 327 adapter_->RemoveObserver(this); 328 SetName(); 329 } 330} 331 332void BluetoothHostPairingController::AddObserver(Observer* observer) { 333 observers_.AddObserver(observer); 334} 335 336void BluetoothHostPairingController::RemoveObserver(Observer* observer) { 337 observers_.RemoveObserver(observer); 338} 339 340HostPairingController::Stage BluetoothHostPairingController::GetCurrentStage() { 341 return current_stage_; 342} 343 344void BluetoothHostPairingController::StartPairing() { 345 DCHECK_EQ(current_stage_, STAGE_NONE); 346 bool bluetooth_available = 347 device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable(); 348 if (!bluetooth_available) { 349 ChangeStage(STAGE_INITIALIZATION_ERROR); 350 return; 351 } 352 353 device::BluetoothAdapterFactory::GetAdapter( 354 base::Bind(&BluetoothHostPairingController::OnGetAdapter, 355 ptr_factory_.GetWeakPtr())); 356} 357 358std::string BluetoothHostPairingController::GetDeviceName() { 359 return device_name_; 360} 361 362std::string BluetoothHostPairingController::GetConfirmationCode() { 363 DCHECK_EQ(current_stage_, STAGE_WAITING_FOR_CODE_CONFIRMATION); 364 return confirmation_code_; 365} 366 367std::string BluetoothHostPairingController::GetEnrollmentDomain() { 368 return enrollment_domain_; 369} 370 371void BluetoothHostPairingController::OnUpdateStatusChanged( 372 UpdateStatus update_status) { 373 // TODO(zork): Handling updating stages (http://crbug.com/405754). 374} 375 376void BluetoothHostPairingController::RequestPinCode( 377 device::BluetoothDevice* device) { 378 // Disallow unknown device. 379 device->RejectPairing(); 380} 381 382void BluetoothHostPairingController::RequestPasskey( 383 device::BluetoothDevice* device) { 384 // Disallow unknown device. 385 device->RejectPairing(); 386} 387 388void BluetoothHostPairingController::DisplayPinCode( 389 device::BluetoothDevice* device, 390 const std::string& pincode) { 391 // Disallow unknown device. 392 device->RejectPairing(); 393} 394 395void BluetoothHostPairingController::DisplayPasskey( 396 device::BluetoothDevice* device, 397 uint32 passkey) { 398 // Disallow unknown device. 399 device->RejectPairing(); 400} 401 402void BluetoothHostPairingController::KeysEntered( 403 device::BluetoothDevice* device, 404 uint32 entered) { 405 // Disallow unknown device. 406 device->RejectPairing(); 407} 408 409void BluetoothHostPairingController::ConfirmPasskey( 410 device::BluetoothDevice* device, 411 uint32 passkey) { 412 confirmation_code_ = base::StringPrintf("%06d", passkey); 413 device->ConfirmPairing(); 414 ChangeStage(STAGE_WAITING_FOR_CODE_CONFIRMATION); 415} 416 417void BluetoothHostPairingController::AuthorizePairing( 418 device::BluetoothDevice* device) { 419 // Disallow unknown device. 420 device->RejectPairing(); 421} 422 423} // namespace pairing_chromeos 424