OLD | NEW |
(Empty) | |
| 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_controller_pairing_controller.h" |
| 6 |
| 7 #include "base/bind.h" |
| 8 #include "base/logging.h" |
| 9 #include "base/strings/string_util.h" |
| 10 #include "base/strings/stringprintf.h" |
| 11 #include "base/strings/utf_string_conversions.h" |
| 12 #include "components/pairing/bluetooth_pairing_constants.h" |
| 13 #include "components/pairing/pairing_api.pb.h" |
| 14 #include "device/bluetooth/bluetooth_adapter_factory.h" |
| 15 #include "device/bluetooth/bluetooth_discovery_session.h" |
| 16 #include "net/base/io_buffer.h" |
| 17 |
| 18 namespace { |
| 19 const char* kFakeEnrollmentDomain = "http://fake.com"; |
| 20 const int kReceiveSize = 16384; |
| 21 } |
| 22 |
| 23 namespace pairing_chromeos { |
| 24 |
| 25 BluetoothControllerPairingController::BluetoothControllerPairingController() |
| 26 : current_stage_(STAGE_NONE), |
| 27 got_initial_status_(false), |
| 28 proto_decoder_(new ProtoDecoder(this)), |
| 29 ptr_factory_(this) { |
| 30 } |
| 31 |
| 32 BluetoothControllerPairingController::~BluetoothControllerPairingController() { |
| 33 Reset(); |
| 34 } |
| 35 |
| 36 device::BluetoothDevice* BluetoothControllerPairingController::GetController() { |
| 37 DCHECK(!controller_device_id_.empty()); |
| 38 device::BluetoothDevice* device = adapter_->GetDevice(controller_device_id_); |
| 39 if (!device) { |
| 40 LOG(ERROR) << "Lost connection to controller."; |
| 41 ChangeStage(STAGE_ESTABLISHING_CONNECTION_ERROR); |
| 42 } |
| 43 |
| 44 return device; |
| 45 } |
| 46 |
| 47 void BluetoothControllerPairingController::ChangeStage(Stage new_stage) { |
| 48 if (current_stage_ == new_stage) |
| 49 return; |
| 50 current_stage_ = new_stage; |
| 51 FOR_EACH_OBSERVER(ControllerPairingController::Observer, observers_, |
| 52 PairingStageChanged(new_stage)); |
| 53 } |
| 54 |
| 55 void BluetoothControllerPairingController::Reset() { |
| 56 got_initial_status_ = false; |
| 57 controller_device_id_.clear(); |
| 58 discovery_session_.reset(); |
| 59 |
| 60 if (socket_) { |
| 61 socket_->Close(); |
| 62 socket_ = NULL; |
| 63 } |
| 64 |
| 65 if (adapter_) { |
| 66 adapter_->RemoveObserver(this); |
| 67 adapter_ = NULL; |
| 68 } |
| 69 } |
| 70 |
| 71 void BluetoothControllerPairingController::DeviceFound( |
| 72 device::BluetoothDevice* device) { |
| 73 DCHECK_EQ(current_stage_, STAGE_DEVICES_DISCOVERY); |
| 74 DCHECK(thread_checker_.CalledOnValidThread()); |
| 75 if (StartsWith(device->GetName(), base::ASCIIToUTF16(kDeviceNamePrefix), |
| 76 false)) { |
| 77 discovered_devices_.insert(device->GetAddress()); |
| 78 FOR_EACH_OBSERVER(ControllerPairingController::Observer, observers_, |
| 79 DiscoveredDevicesListChanged()); |
| 80 } |
| 81 } |
| 82 |
| 83 void BluetoothControllerPairingController::DeviceLost( |
| 84 device::BluetoothDevice* device) { |
| 85 DCHECK_EQ(current_stage_, STAGE_DEVICES_DISCOVERY); |
| 86 DCHECK(thread_checker_.CalledOnValidThread()); |
| 87 std::set<std::string>::iterator ix = |
| 88 discovered_devices_.find(device->GetAddress()); |
| 89 if (ix != discovered_devices_.end()) { |
| 90 discovered_devices_.erase(ix); |
| 91 FOR_EACH_OBSERVER(ControllerPairingController::Observer, observers_, |
| 92 DiscoveredDevicesListChanged()); |
| 93 } |
| 94 } |
| 95 |
| 96 void BluetoothControllerPairingController::OnSetPowered() { |
| 97 DCHECK(thread_checker_.CalledOnValidThread()); |
| 98 adapter_->StartDiscoverySession( |
| 99 base::Bind(&BluetoothControllerPairingController::OnStartDiscoverySession, |
| 100 ptr_factory_.GetWeakPtr()), |
| 101 base::Bind(&BluetoothControllerPairingController::OnError, |
| 102 ptr_factory_.GetWeakPtr())); |
| 103 } |
| 104 |
| 105 void BluetoothControllerPairingController::OnGetAdapter( |
| 106 scoped_refptr<device::BluetoothAdapter> adapter) { |
| 107 DCHECK(thread_checker_.CalledOnValidThread()); |
| 108 DCHECK(!adapter_); |
| 109 adapter_ = adapter; |
| 110 adapter_->AddObserver(this); |
| 111 |
| 112 if (adapter_->IsPowered()) { |
| 113 OnSetPowered(); |
| 114 } else { |
| 115 adapter_->SetPowered( |
| 116 true, |
| 117 base::Bind(&BluetoothControllerPairingController::OnSetPowered, |
| 118 ptr_factory_.GetWeakPtr()), |
| 119 base::Bind(&BluetoothControllerPairingController::OnError, |
| 120 ptr_factory_.GetWeakPtr())); |
| 121 } |
| 122 } |
| 123 |
| 124 void BluetoothControllerPairingController::OnStartDiscoverySession( |
| 125 scoped_ptr<device::BluetoothDiscoverySession> discovery_session) { |
| 126 DCHECK(thread_checker_.CalledOnValidThread()); |
| 127 discovery_session_ = discovery_session.Pass(); |
| 128 ChangeStage(STAGE_DEVICES_DISCOVERY); |
| 129 |
| 130 device::BluetoothAdapter::DeviceList device_list = adapter_->GetDevices(); |
| 131 for (device::BluetoothAdapter::DeviceList::iterator ix = device_list.begin(); |
| 132 ix != device_list.end(); ++ix) { |
| 133 DeviceFound(*ix); |
| 134 } |
| 135 } |
| 136 |
| 137 void BluetoothControllerPairingController::OnConnect() { |
| 138 DCHECK(thread_checker_.CalledOnValidThread()); |
| 139 device::BluetoothDevice* device = GetController(); |
| 140 if (device) { |
| 141 device->ConnectToService( |
| 142 device::BluetoothUUID(kPairingServiceUUID), |
| 143 base::Bind(&BluetoothControllerPairingController::OnConnectToService, |
| 144 ptr_factory_.GetWeakPtr()), |
| 145 base::Bind(&BluetoothControllerPairingController::OnErrorWithMessage, |
| 146 ptr_factory_.GetWeakPtr())); |
| 147 } |
| 148 } |
| 149 |
| 150 void BluetoothControllerPairingController::OnConnectToService( |
| 151 scoped_refptr<device::BluetoothSocket> socket) { |
| 152 DCHECK(thread_checker_.CalledOnValidThread()); |
| 153 socket_ = socket; |
| 154 |
| 155 socket_->Receive( |
| 156 kReceiveSize, |
| 157 base::Bind(&BluetoothControllerPairingController::OnReceiveComplete, |
| 158 ptr_factory_.GetWeakPtr()), |
| 159 base::Bind(&BluetoothControllerPairingController::OnReceiveError, |
| 160 ptr_factory_.GetWeakPtr())); |
| 161 } |
| 162 |
| 163 void BluetoothControllerPairingController::OnSendComplete(int bytes_sent) {} |
| 164 |
| 165 void BluetoothControllerPairingController::OnReceiveComplete( |
| 166 int bytes, scoped_refptr<net::IOBuffer> io_buffer) { |
| 167 DCHECK(thread_checker_.CalledOnValidThread()); |
| 168 proto_decoder_->DecodeIOBuffer(bytes, io_buffer); |
| 169 |
| 170 socket_->Receive( |
| 171 kReceiveSize, |
| 172 base::Bind(&BluetoothControllerPairingController::OnReceiveComplete, |
| 173 ptr_factory_.GetWeakPtr()), |
| 174 base::Bind(&BluetoothControllerPairingController::OnReceiveError, |
| 175 ptr_factory_.GetWeakPtr())); |
| 176 } |
| 177 |
| 178 void BluetoothControllerPairingController::OnError() { |
| 179 // TODO(zork): Add a stage for initialization error. (http://crbug.com/405744) |
| 180 LOG(ERROR) << "Pairing initialization failed"; |
| 181 Reset(); |
| 182 } |
| 183 |
| 184 void BluetoothControllerPairingController::OnErrorWithMessage( |
| 185 const std::string& message) { |
| 186 // TODO(zork): Add a stage for initialization error. (http://crbug.com/405744) |
| 187 LOG(ERROR) << message; |
| 188 Reset(); |
| 189 } |
| 190 |
| 191 void BluetoothControllerPairingController::OnConnectError( |
| 192 device::BluetoothDevice::ConnectErrorCode error_code) { |
| 193 DCHECK(thread_checker_.CalledOnValidThread()); |
| 194 device::BluetoothDevice* device = GetController(); |
| 195 |
| 196 if (device && device->IsPaired()) { |
| 197 // The connection attempt is only used to start the pairing between the |
| 198 // devices. If the connection fails, it's not a problem as long as pairing |
| 199 // was successful. |
| 200 OnConnect(); |
| 201 } |
| 202 } |
| 203 |
| 204 void BluetoothControllerPairingController::OnReceiveError( |
| 205 device::BluetoothSocket::ErrorReason reason, |
| 206 const std::string& error_message) { |
| 207 LOG(ERROR) << reason << ", " << error_message; |
| 208 Reset(); |
| 209 } |
| 210 |
| 211 void BluetoothControllerPairingController::AddObserver( |
| 212 ControllerPairingController::Observer* observer) { |
| 213 observers_.AddObserver(observer); |
| 214 } |
| 215 |
| 216 void BluetoothControllerPairingController::RemoveObserver( |
| 217 ControllerPairingController::Observer* observer) { |
| 218 observers_.RemoveObserver(observer); |
| 219 } |
| 220 |
| 221 ControllerPairingController::Stage |
| 222 BluetoothControllerPairingController::GetCurrentStage() { |
| 223 return current_stage_; |
| 224 } |
| 225 |
| 226 void BluetoothControllerPairingController::StartPairing() { |
| 227 DCHECK(thread_checker_.CalledOnValidThread()); |
| 228 DCHECK(current_stage_ == STAGE_NONE || |
| 229 current_stage_ == STAGE_DEVICE_NOT_FOUND || |
| 230 current_stage_ == STAGE_ESTABLISHING_CONNECTION_ERROR || |
| 231 current_stage_ == STAGE_HOST_ENROLLMENT_ERROR); |
| 232 // TODO(zork): Add a stage for no bluetooth. (http://crbug.com/405744) |
| 233 if (!device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) { |
| 234 ChangeStage(STAGE_DEVICE_NOT_FOUND); |
| 235 return; |
| 236 } |
| 237 |
| 238 device::BluetoothAdapterFactory::GetAdapter( |
| 239 base::Bind(&BluetoothControllerPairingController::OnGetAdapter, |
| 240 ptr_factory_.GetWeakPtr())); |
| 241 |
| 242 } |
| 243 |
| 244 ControllerPairingController::DeviceIdList |
| 245 BluetoothControllerPairingController::GetDiscoveredDevices() { |
| 246 DCHECK_EQ(current_stage_, STAGE_DEVICES_DISCOVERY); |
| 247 return DeviceIdList(discovered_devices_.begin(), discovered_devices_.end()); |
| 248 } |
| 249 |
| 250 void BluetoothControllerPairingController::ChooseDeviceForPairing( |
| 251 const std::string& device_id) { |
| 252 DCHECK_EQ(current_stage_, STAGE_DEVICES_DISCOVERY); |
| 253 DCHECK(discovered_devices_.count(device_id)); |
| 254 discovery_session_.reset(); |
| 255 controller_device_id_ = device_id; |
| 256 |
| 257 device::BluetoothDevice* device = GetController(); |
| 258 |
| 259 if (device) { |
| 260 ChangeStage(STAGE_ESTABLISHING_CONNECTION); |
| 261 if (device->IsPaired()) { |
| 262 OnConnect(); |
| 263 } else { |
| 264 device->Connect( |
| 265 this, |
| 266 base::Bind(&BluetoothControllerPairingController::OnConnect, |
| 267 ptr_factory_.GetWeakPtr()), |
| 268 base::Bind(&BluetoothControllerPairingController::OnConnectError, |
| 269 ptr_factory_.GetWeakPtr())); |
| 270 } |
| 271 } |
| 272 } |
| 273 |
| 274 void BluetoothControllerPairingController::RepeatDiscovery() { |
| 275 DCHECK(current_stage_ == STAGE_DEVICE_NOT_FOUND || |
| 276 current_stage_ == STAGE_ESTABLISHING_CONNECTION_ERROR || |
| 277 current_stage_ == STAGE_HOST_ENROLLMENT_ERROR); |
| 278 Reset(); |
| 279 StartPairing(); |
| 280 } |
| 281 |
| 282 std::string BluetoothControllerPairingController::GetConfirmationCode() { |
| 283 DCHECK_EQ(current_stage_, STAGE_WAITING_FOR_CODE_CONFIRMATION); |
| 284 DCHECK(!confirmation_code_.empty()); |
| 285 return confirmation_code_; |
| 286 } |
| 287 |
| 288 void BluetoothControllerPairingController::SetConfirmationCodeIsCorrect( |
| 289 bool correct) { |
| 290 DCHECK_EQ(current_stage_, STAGE_WAITING_FOR_CODE_CONFIRMATION); |
| 291 |
| 292 device::BluetoothDevice* device = GetController(); |
| 293 if (!device) |
| 294 return; |
| 295 |
| 296 if (correct) { |
| 297 device->ConfirmPairing(); |
| 298 // Once pairing is confirmed, the connection will either be successful, or |
| 299 // fail. Either case is acceptable as long as the devices are paired. |
| 300 } else { |
| 301 device->RejectPairing(); |
| 302 controller_device_id_.clear(); |
| 303 RepeatDiscovery(); |
| 304 } |
| 305 } |
| 306 |
| 307 void BluetoothControllerPairingController::OnAuthenticationDone( |
| 308 const chromeos::UserContext& user_context, |
| 309 content::BrowserContext* browser_context) { |
| 310 DCHECK_EQ(current_stage_, STAGE_WAITING_FOR_CREDENTIALS); |
| 311 |
| 312 // TODO(zork): Get configuration from UI and send to Host. |
| 313 // (http://crbug.com/405744) |
| 314 |
| 315 // TODO(zork): Get proper credentials. (http://crbug.com/405744) |
| 316 // For now, send a fake domain. |
| 317 pairing_api::PairDevices pair_devices; |
| 318 pair_devices.set_api_version(kPairingAPIVersion); |
| 319 pair_devices.mutable_parameters()->set_admin_access_token( |
| 320 kFakeEnrollmentDomain); |
| 321 |
| 322 int size = 0; |
| 323 scoped_refptr<net::IOBuffer> io_buffer( |
| 324 ProtoDecoder::SendPairDevices(pair_devices, &size)); |
| 325 |
| 326 socket_->Send( |
| 327 io_buffer, size, |
| 328 base::Bind(&BluetoothControllerPairingController::OnSendComplete, |
| 329 ptr_factory_.GetWeakPtr()), |
| 330 base::Bind(&BluetoothControllerPairingController::OnErrorWithMessage, |
| 331 ptr_factory_.GetWeakPtr())); |
| 332 ChangeStage(STAGE_HOST_ENROLLMENT_IN_PROGRESS); |
| 333 } |
| 334 |
| 335 void BluetoothControllerPairingController::StartSession() { |
| 336 DCHECK_EQ(current_stage_, STAGE_PAIRING_DONE); |
| 337 ChangeStage(STAGE_FINISHED); |
| 338 } |
| 339 |
| 340 // ProtoDecoder::Observer: |
| 341 void BluetoothControllerPairingController::OnHostStatusMessage( |
| 342 const pairing_api::HostStatus& message) { |
| 343 if (got_initial_status_) { |
| 344 if (message.parameters().has_domain()) { |
| 345 // TODO(zork): Remove this if we don't actually need the domain for UI. |
| 346 // (http://crbug.com/405761) |
| 347 if (message.parameters().domain() == kFakeEnrollmentDomain) { |
| 348 pairing_api::CompleteSetup complete_setup; |
| 349 complete_setup.set_api_version(kPairingAPIVersion); |
| 350 // TODO(zork): Get AddAnother from UI (http://crbug.com/405757) |
| 351 complete_setup.mutable_parameters()->set_add_another(false); |
| 352 |
| 353 int size = 0; |
| 354 scoped_refptr<net::IOBuffer> io_buffer( |
| 355 ProtoDecoder::SendCompleteSetup(complete_setup, &size)); |
| 356 |
| 357 socket_->Send( |
| 358 io_buffer, size, |
| 359 base::Bind(&BluetoothControllerPairingController::OnSendComplete, |
| 360 ptr_factory_.GetWeakPtr()), |
| 361 base::Bind( |
| 362 &BluetoothControllerPairingController::OnErrorWithMessage, |
| 363 ptr_factory_.GetWeakPtr())); |
| 364 ChangeStage(STAGE_PAIRING_DONE); |
| 365 } else { |
| 366 ChangeStage(STAGE_HOST_ENROLLMENT_ERROR); |
| 367 } |
| 368 } else { |
| 369 ChangeStage(STAGE_HOST_ENROLLMENT_ERROR); |
| 370 } |
| 371 } else { |
| 372 got_initial_status_ = true; |
| 373 |
| 374 // TODO(zork): Check domain. (http://crbug.com/405761) |
| 375 |
| 376 // TODO(zork): Handling updating stages (http://crbug.com/405754). |
| 377 ChangeStage(STAGE_WAITING_FOR_CREDENTIALS); |
| 378 } |
| 379 } |
| 380 |
| 381 void BluetoothControllerPairingController::OnConfigureHostMessage( |
| 382 const pairing_api::ConfigureHost& message) { |
| 383 NOTREACHED(); |
| 384 } |
| 385 |
| 386 void BluetoothControllerPairingController::OnPairDevicesMessage( |
| 387 const pairing_api::PairDevices& message) { |
| 388 NOTREACHED(); |
| 389 } |
| 390 |
| 391 void BluetoothControllerPairingController::OnCompleteSetupMessage( |
| 392 const pairing_api::CompleteSetup& message) { |
| 393 NOTREACHED(); |
| 394 } |
| 395 |
| 396 void BluetoothControllerPairingController::OnErrorMessage( |
| 397 const pairing_api::Error& message) { |
| 398 LOG(ERROR) << message.parameters().code() << ", " << |
| 399 message.parameters().description(); |
| 400 ChangeStage(STAGE_HOST_ENROLLMENT_ERROR); |
| 401 } |
| 402 |
| 403 void BluetoothControllerPairingController::DeviceAdded( |
| 404 device::BluetoothAdapter* adapter, |
| 405 device::BluetoothDevice* device) { |
| 406 DCHECK_EQ(adapter, adapter_.get()); |
| 407 DeviceFound(device); |
| 408 } |
| 409 |
| 410 void BluetoothControllerPairingController::DeviceRemoved( |
| 411 device::BluetoothAdapter* adapter, |
| 412 device::BluetoothDevice* device) { |
| 413 DCHECK_EQ(adapter, adapter_.get()); |
| 414 DeviceLost(device); |
| 415 } |
| 416 |
| 417 void BluetoothControllerPairingController::RequestPinCode( |
| 418 device::BluetoothDevice* device) { |
| 419 // Disallow unknown device. |
| 420 device->RejectPairing(); |
| 421 } |
| 422 |
| 423 void BluetoothControllerPairingController::RequestPasskey( |
| 424 device::BluetoothDevice* device) { |
| 425 // Disallow unknown device. |
| 426 device->RejectPairing(); |
| 427 } |
| 428 |
| 429 void BluetoothControllerPairingController::DisplayPinCode( |
| 430 device::BluetoothDevice* device, |
| 431 const std::string& pincode) { |
| 432 // Disallow unknown device. |
| 433 device->RejectPairing(); |
| 434 } |
| 435 |
| 436 void BluetoothControllerPairingController::DisplayPasskey( |
| 437 device::BluetoothDevice* device, |
| 438 uint32 passkey) { |
| 439 // Disallow unknown device. |
| 440 device->RejectPairing(); |
| 441 } |
| 442 |
| 443 void BluetoothControllerPairingController::KeysEntered( |
| 444 device::BluetoothDevice* device, |
| 445 uint32 entered) { |
| 446 // Disallow unknown device. |
| 447 device->RejectPairing(); |
| 448 } |
| 449 |
| 450 void BluetoothControllerPairingController::ConfirmPasskey( |
| 451 device::BluetoothDevice* device, |
| 452 uint32 passkey) { |
| 453 confirmation_code_ = base::StringPrintf("%06d", passkey); |
| 454 ChangeStage(STAGE_WAITING_FOR_CODE_CONFIRMATION); |
| 455 } |
| 456 |
| 457 void BluetoothControllerPairingController::AuthorizePairing( |
| 458 device::BluetoothDevice* device) { |
| 459 // Disallow unknown device. |
| 460 device->RejectPairing(); |
| 461 } |
| 462 |
| 463 } // namespace pairing_chromeos |
OLD | NEW |