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