Chromium Code Reviews| 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) | |
|
achuithb
2014/08/26 19:41:06
Nit:
Might just read better to do
if (device) {
Zachary Kuznia
2014/08/26 19:47:35
Done.
| |
| 141 return; | |
| 142 | |
| 143 device->ConnectToService( | |
| 144 device::BluetoothUUID(kPairingServiceUUID), | |
| 145 base::Bind(&BluetoothControllerPairingController::OnConnectToService, | |
| 146 ptr_factory_.GetWeakPtr()), | |
| 147 base::Bind(&BluetoothControllerPairingController::OnErrorWithMessage, | |
| 148 ptr_factory_.GetWeakPtr())); | |
| 149 } | |
| 150 | |
| 151 void BluetoothControllerPairingController::OnConnectToService( | |
| 152 scoped_refptr<device::BluetoothSocket> socket) { | |
| 153 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 154 socket_ = socket; | |
| 155 | |
| 156 socket_->Receive( | |
| 157 kReceiveSize, | |
| 158 base::Bind(&BluetoothControllerPairingController::OnReceiveComplete, | |
| 159 ptr_factory_.GetWeakPtr()), | |
| 160 base::Bind(&BluetoothControllerPairingController::OnReceiveError, | |
| 161 ptr_factory_.GetWeakPtr())); | |
| 162 } | |
| 163 | |
| 164 void BluetoothControllerPairingController::OnSendComplete(int bytes_sent) {} | |
| 165 | |
| 166 void BluetoothControllerPairingController::OnReceiveComplete( | |
| 167 int bytes, scoped_refptr<net::IOBuffer> io_buffer) { | |
| 168 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 169 proto_decoder_->DecodeIOBuffer(bytes, io_buffer); | |
| 170 | |
| 171 socket_->Receive( | |
| 172 kReceiveSize, | |
| 173 base::Bind(&BluetoothControllerPairingController::OnReceiveComplete, | |
| 174 ptr_factory_.GetWeakPtr()), | |
| 175 base::Bind(&BluetoothControllerPairingController::OnReceiveError, | |
| 176 ptr_factory_.GetWeakPtr())); | |
| 177 } | |
| 178 | |
| 179 void BluetoothControllerPairingController::OnError() { | |
| 180 // TODO(zork): Add a stage for initialization error. (http://crbug.com/405744) | |
| 181 LOG(ERROR) << "Pairing initialization failed"; | |
| 182 Reset(); | |
| 183 } | |
| 184 | |
| 185 void BluetoothControllerPairingController::OnErrorWithMessage( | |
| 186 const std::string& message) { | |
| 187 // TODO(zork): Add a stage for initialization error. (http://crbug.com/405744) | |
| 188 LOG(ERROR) << message; | |
| 189 Reset(); | |
| 190 } | |
| 191 | |
| 192 void BluetoothControllerPairingController::OnConnectError( | |
| 193 device::BluetoothDevice::ConnectErrorCode error_code) { | |
| 194 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 195 device::BluetoothDevice* device = GetController(); | |
| 196 | |
| 197 if (device && device->IsPaired()) { | |
| 198 // The connection attempt is only used to start the pairing between the | |
| 199 // devices. If the connection fails, it's not a problem as long as pairing | |
| 200 // was successful. | |
| 201 OnConnect(); | |
| 202 } | |
| 203 } | |
| 204 | |
| 205 void BluetoothControllerPairingController::OnReceiveError( | |
| 206 device::BluetoothSocket::ErrorReason reason, | |
| 207 const std::string& error_message) { | |
| 208 LOG(ERROR) << reason << ", " << error_message; | |
| 209 Reset(); | |
| 210 } | |
| 211 | |
| 212 void BluetoothControllerPairingController::AddObserver( | |
| 213 ControllerPairingController::Observer* observer) { | |
| 214 observers_.AddObserver(observer); | |
| 215 } | |
| 216 | |
| 217 void BluetoothControllerPairingController::RemoveObserver( | |
| 218 ControllerPairingController::Observer* observer) { | |
| 219 observers_.RemoveObserver(observer); | |
| 220 } | |
| 221 | |
| 222 ControllerPairingController::Stage | |
| 223 BluetoothControllerPairingController::GetCurrentStage() { | |
| 224 return current_stage_; | |
| 225 } | |
| 226 | |
| 227 void BluetoothControllerPairingController::StartPairing() { | |
| 228 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 229 DCHECK(current_stage_ == STAGE_NONE || | |
| 230 current_stage_ == STAGE_DEVICE_NOT_FOUND || | |
| 231 current_stage_ == STAGE_ESTABLISHING_CONNECTION_ERROR || | |
| 232 current_stage_ == STAGE_HOST_ENROLLMENT_ERROR); | |
| 233 // TODO(zork): Add a stage for no bluetooth. (http://crbug.com/405744) | |
| 234 if (!device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) { | |
| 235 ChangeStage(STAGE_DEVICE_NOT_FOUND); | |
| 236 return; | |
| 237 } | |
| 238 | |
| 239 device::BluetoothAdapterFactory::GetAdapter( | |
| 240 base::Bind(&BluetoothControllerPairingController::OnGetAdapter, | |
| 241 ptr_factory_.GetWeakPtr())); | |
| 242 | |
| 243 } | |
| 244 | |
| 245 ControllerPairingController::DeviceIdList | |
| 246 BluetoothControllerPairingController::GetDiscoveredDevices() { | |
| 247 DCHECK_EQ(current_stage_, STAGE_DEVICES_DISCOVERY); | |
| 248 return DeviceIdList(discovered_devices_.begin(), discovered_devices_.end()); | |
| 249 } | |
| 250 | |
| 251 void BluetoothControllerPairingController::ChooseDeviceForPairing( | |
| 252 const std::string& device_id) { | |
| 253 DCHECK_EQ(current_stage_, STAGE_DEVICES_DISCOVERY); | |
| 254 DCHECK(discovered_devices_.count(device_id)); | |
| 255 discovery_session_.reset(); | |
| 256 controller_device_id_ = device_id; | |
| 257 | |
| 258 device::BluetoothDevice* device = GetController(); | |
| 259 | |
| 260 if (device) { | |
| 261 ChangeStage(STAGE_ESTABLISHING_CONNECTION); | |
| 262 if (device->IsPaired()) { | |
| 263 OnConnect(); | |
| 264 } else { | |
| 265 device->Connect( | |
| 266 this, | |
| 267 base::Bind(&BluetoothControllerPairingController::OnConnect, | |
| 268 ptr_factory_.GetWeakPtr()), | |
| 269 base::Bind(&BluetoothControllerPairingController::OnConnectError, | |
| 270 ptr_factory_.GetWeakPtr())); | |
| 271 } | |
| 272 } | |
| 273 } | |
| 274 | |
| 275 void BluetoothControllerPairingController::RepeatDiscovery() { | |
| 276 DCHECK(current_stage_ == STAGE_DEVICE_NOT_FOUND || | |
| 277 current_stage_ == STAGE_ESTABLISHING_CONNECTION_ERROR || | |
| 278 current_stage_ == STAGE_HOST_ENROLLMENT_ERROR); | |
| 279 Reset(); | |
| 280 StartPairing(); | |
| 281 } | |
| 282 | |
| 283 std::string BluetoothControllerPairingController::GetConfirmationCode() { | |
| 284 DCHECK_EQ(current_stage_, STAGE_WAITING_FOR_CODE_CONFIRMATION); | |
| 285 DCHECK(!confirmation_code_.empty()); | |
| 286 return confirmation_code_; | |
| 287 } | |
| 288 | |
| 289 void BluetoothControllerPairingController::SetConfirmationCodeIsCorrect( | |
| 290 bool correct) { | |
| 291 DCHECK_EQ(current_stage_, STAGE_WAITING_FOR_CODE_CONFIRMATION); | |
| 292 | |
| 293 device::BluetoothDevice* device = GetController(); | |
| 294 if (!device) | |
| 295 return; | |
| 296 | |
| 297 if (correct) { | |
| 298 device->ConfirmPairing(); | |
| 299 // Once pairing is confirmed, the connection will either be successful, or | |
| 300 // fail. Either case is acceptable as long as the devices are paired. | |
| 301 } else { | |
| 302 device->RejectPairing(); | |
| 303 controller_device_id_.clear(); | |
| 304 RepeatDiscovery(); | |
| 305 } | |
| 306 } | |
| 307 | |
| 308 void BluetoothControllerPairingController::OnAuthenticationDone( | |
| 309 const chromeos::UserContext& user_context, | |
| 310 content::BrowserContext* browser_context) { | |
| 311 DCHECK_EQ(current_stage_, STAGE_WAITING_FOR_CREDENTIALS); | |
| 312 | |
| 313 // TODO(zork): Get configuration from UI and send to Host. | |
| 314 // (http://crbug.com/405744) | |
| 315 | |
| 316 // TODO(zork): Get proper credentials. (http://crbug.com/405744) | |
| 317 // For now, send a fake domain. | |
| 318 pairing_api::PairDevices pair_devices; | |
| 319 pair_devices.set_api_version(kPairingAPIVersion); | |
| 320 pair_devices.mutable_parameters()->set_admin_access_token( | |
| 321 kFakeEnrollmentDomain); | |
| 322 | |
| 323 int size = 0; | |
| 324 scoped_refptr<net::IOBuffer> io_buffer( | |
| 325 ProtoDecoder::SendPairDevices(pair_devices, &size)); | |
| 326 | |
| 327 socket_->Send( | |
| 328 io_buffer, size, | |
| 329 base::Bind(&BluetoothControllerPairingController::OnSendComplete, | |
| 330 ptr_factory_.GetWeakPtr()), | |
| 331 base::Bind(&BluetoothControllerPairingController::OnErrorWithMessage, | |
| 332 ptr_factory_.GetWeakPtr())); | |
| 333 ChangeStage(STAGE_HOST_ENROLLMENT_IN_PROGRESS); | |
| 334 } | |
| 335 | |
| 336 void BluetoothControllerPairingController::StartSession() { | |
| 337 DCHECK_EQ(current_stage_, STAGE_PAIRING_DONE); | |
| 338 ChangeStage(STAGE_FINISHED); | |
| 339 } | |
| 340 | |
| 341 // ProtoDecoder::Observer: | |
| 342 void BluetoothControllerPairingController::OnHostStatusMessage( | |
| 343 const pairing_api::HostStatus& message) { | |
| 344 if (got_initial_status_) { | |
| 345 if (message.parameters().has_domain()) { | |
| 346 // TODO(zork): Remove this if we don't actually need the domain for UI. | |
| 347 // (http://crbug.com/405761) | |
| 348 if (message.parameters().domain() == kFakeEnrollmentDomain) { | |
| 349 pairing_api::CompleteSetup complete_setup; | |
| 350 complete_setup.set_api_version(kPairingAPIVersion); | |
| 351 // TODO(zork): Get AddAnother from UI (http://crbug.com/405757) | |
| 352 complete_setup.mutable_parameters()->set_add_another(false); | |
| 353 | |
| 354 int size = 0; | |
| 355 scoped_refptr<net::IOBuffer> io_buffer( | |
| 356 ProtoDecoder::SendCompleteSetup(complete_setup, &size)); | |
| 357 | |
| 358 socket_->Send( | |
| 359 io_buffer, size, | |
| 360 base::Bind(&BluetoothControllerPairingController::OnSendComplete, | |
| 361 ptr_factory_.GetWeakPtr()), | |
| 362 base::Bind( | |
| 363 &BluetoothControllerPairingController::OnErrorWithMessage, | |
| 364 ptr_factory_.GetWeakPtr())); | |
| 365 ChangeStage(STAGE_PAIRING_DONE); | |
| 366 } else { | |
| 367 ChangeStage(STAGE_HOST_ENROLLMENT_ERROR); | |
| 368 } | |
| 369 } else { | |
| 370 ChangeStage(STAGE_HOST_ENROLLMENT_ERROR); | |
| 371 } | |
| 372 } else { | |
| 373 got_initial_status_ = true; | |
| 374 | |
| 375 // TODO(zork): Check domain. (http://crbug.com/405761) | |
| 376 | |
| 377 // TODO(zork): Handling updating stages (http://crbug.com/405754). | |
| 378 ChangeStage(STAGE_WAITING_FOR_CREDENTIALS); | |
| 379 } | |
| 380 } | |
| 381 | |
| 382 void BluetoothControllerPairingController::OnConfigureHostMessage( | |
| 383 const pairing_api::ConfigureHost& message) { | |
| 384 NOTREACHED(); | |
| 385 } | |
| 386 | |
| 387 void BluetoothControllerPairingController::OnPairDevicesMessage( | |
| 388 const pairing_api::PairDevices& message) { | |
| 389 NOTREACHED(); | |
| 390 } | |
| 391 | |
| 392 void BluetoothControllerPairingController::OnCompleteSetupMessage( | |
| 393 const pairing_api::CompleteSetup& message) { | |
| 394 NOTREACHED(); | |
| 395 } | |
| 396 | |
| 397 void BluetoothControllerPairingController::OnErrorMessage( | |
| 398 const pairing_api::Error& message) { | |
| 399 LOG(ERROR) << message.parameters().code() << ", " << | |
| 400 message.parameters().description(); | |
| 401 ChangeStage(STAGE_HOST_ENROLLMENT_ERROR); | |
| 402 } | |
| 403 | |
| 404 void BluetoothControllerPairingController::DeviceAdded( | |
| 405 device::BluetoothAdapter* adapter, | |
| 406 device::BluetoothDevice* device) { | |
| 407 DCHECK_EQ(adapter, adapter_.get()); | |
| 408 DeviceFound(device); | |
| 409 } | |
| 410 | |
| 411 void BluetoothControllerPairingController::DeviceRemoved( | |
| 412 device::BluetoothAdapter* adapter, | |
| 413 device::BluetoothDevice* device) { | |
| 414 DCHECK_EQ(adapter, adapter_.get()); | |
| 415 DeviceLost(device); | |
| 416 } | |
| 417 | |
| 418 void BluetoothControllerPairingController::RequestPinCode( | |
| 419 device::BluetoothDevice* device) { | |
| 420 // Disallow unknown device. | |
| 421 device->RejectPairing(); | |
| 422 } | |
| 423 | |
| 424 void BluetoothControllerPairingController::RequestPasskey( | |
| 425 device::BluetoothDevice* device) { | |
| 426 // Disallow unknown device. | |
| 427 device->RejectPairing(); | |
| 428 } | |
| 429 | |
| 430 void BluetoothControllerPairingController::DisplayPinCode( | |
| 431 device::BluetoothDevice* device, | |
| 432 const std::string& pincode) { | |
| 433 // Disallow unknown device. | |
| 434 device->RejectPairing(); | |
| 435 } | |
| 436 | |
| 437 void BluetoothControllerPairingController::DisplayPasskey( | |
| 438 device::BluetoothDevice* device, | |
| 439 uint32 passkey) { | |
| 440 // Disallow unknown device. | |
| 441 device->RejectPairing(); | |
| 442 } | |
| 443 | |
| 444 void BluetoothControllerPairingController::KeysEntered( | |
| 445 device::BluetoothDevice* device, | |
| 446 uint32 entered) { | |
| 447 // Disallow unknown device. | |
| 448 device->RejectPairing(); | |
| 449 } | |
| 450 | |
| 451 void BluetoothControllerPairingController::ConfirmPasskey( | |
| 452 device::BluetoothDevice* device, | |
| 453 uint32 passkey) { | |
| 454 confirmation_code_ = base::StringPrintf("%06d", passkey); | |
| 455 ChangeStage(STAGE_WAITING_FOR_CODE_CONFIRMATION); | |
| 456 } | |
| 457 | |
| 458 void BluetoothControllerPairingController::AuthorizePairing( | |
| 459 device::BluetoothDevice* device) { | |
| 460 // Disallow unknown device. | |
| 461 device->RejectPairing(); | |
| 462 } | |
| 463 | |
| 464 } // namespace pairing_chromeos | |
| OLD | NEW |