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 17 namespace { 18 const int kReceiveSize = 16384; 19 } 20 21 namespace pairing_chromeos { 22 23 BluetoothHostPairingController::BluetoothHostPairingController() 24 : current_stage_(STAGE_NONE), 25 device_(NULL), 26 proto_decoder_(new ProtoDecoder(this)), 27 ptr_factory_(this) { 28 } 29 30 BluetoothHostPairingController::~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 40 void 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 47 void 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 75 void 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 99 void 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 112 void 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 126 void 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 140 void 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 154 void 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 170 void 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 189 void 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 216 void 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 224 void BluetoothHostPairingController::OnSendComplete(int bytes_sent) {} 225 226 void 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 239 void BluetoothHostPairingController::OnCreateServiceError( 240 const std::string& message) { 241 LOG(ERROR) << message; 242 ChangeStage(STAGE_INITIALIZATION_ERROR); 243 } 244 245 void BluetoothHostPairingController::OnSetError() { 246 adapter_->RemovePairingDelegate(this); 247 ChangeStage(STAGE_INITIALIZATION_ERROR); 248 } 249 250 void BluetoothHostPairingController::OnAcceptError( 251 const std::string& error_message) { 252 LOG(ERROR) << error_message; 253 } 254 255 void BluetoothHostPairingController::OnSendError( 256 const std::string& error_message) { 257 LOG(ERROR) << error_message; 258 } 259 260 void BluetoothHostPairingController::OnReceiveError( 261 device::BluetoothSocket::ErrorReason reason, 262 const std::string& error_message) { 263 LOG(ERROR) << reason << ", " << error_message; 264 } 265 266 void BluetoothHostPairingController::OnHostStatusMessage( 267 const pairing_api::HostStatus& message) { 268 NOTREACHED(); 269 } 270 271 void 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 281 void 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 294 void 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 305 void 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 317 void BluetoothHostPairingController::OnErrorMessage( 318 const pairing_api::Error& message) { 319 NOTREACHED(); 320 } 321 322 void 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 332 void BluetoothHostPairingController::AddObserver(Observer* observer) { 333 observers_.AddObserver(observer); 334 } 335 336 void BluetoothHostPairingController::RemoveObserver(Observer* observer) { 337 observers_.RemoveObserver(observer); 338 } 339 340 HostPairingController::Stage BluetoothHostPairingController::GetCurrentStage() { 341 return current_stage_; 342 } 343 344 void 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 358 std::string BluetoothHostPairingController::GetDeviceName() { 359 return device_name_; 360 } 361 362 std::string BluetoothHostPairingController::GetConfirmationCode() { 363 DCHECK_EQ(current_stage_, STAGE_WAITING_FOR_CODE_CONFIRMATION); 364 return confirmation_code_; 365 } 366 367 std::string BluetoothHostPairingController::GetEnrollmentDomain() { 368 return enrollment_domain_; 369 } 370 371 void BluetoothHostPairingController::OnUpdateStatusChanged( 372 UpdateStatus update_status) { 373 // TODO(zork): Handling updating stages (http://crbug.com/405754). 374 } 375 376 void BluetoothHostPairingController::RequestPinCode( 377 device::BluetoothDevice* device) { 378 // Disallow unknown device. 379 device->RejectPairing(); 380 } 381 382 void BluetoothHostPairingController::RequestPasskey( 383 device::BluetoothDevice* device) { 384 // Disallow unknown device. 385 device->RejectPairing(); 386 } 387 388 void BluetoothHostPairingController::DisplayPinCode( 389 device::BluetoothDevice* device, 390 const std::string& pincode) { 391 // Disallow unknown device. 392 device->RejectPairing(); 393 } 394 395 void BluetoothHostPairingController::DisplayPasskey( 396 device::BluetoothDevice* device, 397 uint32 passkey) { 398 // Disallow unknown device. 399 device->RejectPairing(); 400 } 401 402 void BluetoothHostPairingController::KeysEntered( 403 device::BluetoothDevice* device, 404 uint32 entered) { 405 // Disallow unknown device. 406 device->RejectPairing(); 407 } 408 409 void 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 417 void BluetoothHostPairingController::AuthorizePairing( 418 device::BluetoothDevice* device) { 419 // Disallow unknown device. 420 device->RejectPairing(); 421 } 422 423 } // namespace pairing_chromeos 424