Chromium Code Reviews| Index: components/pairing/bluetooth_host_pairing_controller.cc |
| diff --git a/components/pairing/bluetooth_host_pairing_controller.cc b/components/pairing/bluetooth_host_pairing_controller.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..4052fe5332ea21aeac07074ced4f734169fd8a65 |
| --- /dev/null |
| +++ b/components/pairing/bluetooth_host_pairing_controller.cc |
| @@ -0,0 +1,375 @@ |
| +// Copyright 2014 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "components/pairing/bluetooth_host_pairing_controller.h" |
| + |
| +#include "base/bind.h" |
| +#include "base/logging.h" |
| +#include "base/strings/stringprintf.h" |
| +#include "components/pairing/bluetooth_pairing_constants.h" |
| +#include "components/pairing/pairing_api.pb.h" |
| +#include "components/pairing/proto_decoder.h" |
| +#include "device/bluetooth/bluetooth_adapter_factory.h" |
| +#include "net/base/io_buffer.h" |
| + |
| +namespace { |
| +const int kReceiveSize = 16384; |
| +} |
| + |
| +namespace pairing_chromeos { |
| + |
| +BluetoothHostPairingController::BluetoothHostPairingController() |
| + : ptr_factory_(this), |
| + current_stage_(STAGE_NONE), |
| + device_(NULL), |
| + proto_decoder_(new ProtoDecoder(this)) { |
| +} |
| + |
| +BluetoothHostPairingController::~BluetoothHostPairingController() {} |
| + |
| +void BluetoothHostPairingController::ChangeStage(Stage new_stage) { |
| + if (current_stage_ == new_stage) |
| + return; |
| + current_stage_ = new_stage; |
| + FOR_EACH_OBSERVER(Observer, observers_, PairingStageChanged(new_stage)); |
| +} |
| + |
| +void BluetoothHostPairingController::SendHostStatus() { |
| + pairing_api::HostStatus host_status; |
| + |
| + host_status.set_api_version(kPairingAPIVersion); |
| + if (!enrollment_domain_.empty()) |
| + host_status.mutable_parameters()->set_domain(enrollment_domain_); |
| + |
| + // TODO: Get these values from the UI. |
|
achuithb
2014/08/20 21:52:33
TODO(zork) + bug-id
Zachary Kuznia
2014/08/21 00:42:07
Done.
|
| + host_status.mutable_parameters()->set_connectivity( |
| + pairing_api::HostStatusParameters::CONNECTIVITY_CONNECTED); |
| + host_status.mutable_parameters()->set_update_status( |
| + pairing_api::HostStatusParameters::UPDATE_STATUS_UPDATED); |
| + |
| + // TODO: Get a list of other paired controllers. |
|
achuithb
2014/08/20 21:52:34
TODO(zork) + bug-id
Zachary Kuznia
2014/08/21 00:42:07
Done.
|
| + |
| + int size = 0; |
| + scoped_refptr<net::IOBuffer> io_buffer( |
| + ProtoDecoder::SendHostStatus(host_status, &size)); |
| + |
| + controller_socket_->Send( |
| + io_buffer, size, |
| + base::Bind(&BluetoothHostPairingController::OnSendComplete, |
| + ptr_factory_.GetWeakPtr()), |
| + base::Bind(&BluetoothHostPairingController::OnSendError, |
| + ptr_factory_.GetWeakPtr())); |
| +} |
| + |
| +void BluetoothHostPairingController::AbortWithError( |
| + int code, |
| + const std::string& message) { |
| + if (controller_socket_) { |
| + pairing_api::Error error; |
| + |
| + error.set_api_version(kPairingAPIVersion); |
| + error.mutable_parameters()->set_code(PAIRING_ERROR_PAIRING_OR_ENROLLMENT); |
| + error.mutable_parameters()->set_description(message); |
| + |
| + int size = 0; |
| + scoped_refptr<net::IOBuffer> io_buffer( |
| + ProtoDecoder::SendError(error, &size)); |
| + |
| + controller_socket_->Send( |
| + io_buffer, size, |
| + base::Bind(&BluetoothHostPairingController::OnSendComplete, |
| + ptr_factory_.GetWeakPtr()), |
| + base::Bind(&BluetoothHostPairingController::OnSendError, |
| + ptr_factory_.GetWeakPtr())); |
| + } |
| + Reset(); |
| +} |
| + |
| +void BluetoothHostPairingController::Reset() { |
| + if (controller_socket_) { |
| + controller_socket_->Close(); |
| + controller_socket_ = NULL; |
| + } |
| + |
| + if (service_socket_) { |
| + service_socket_->Close(); |
| + service_socket_ = NULL; |
| + } |
| + ChangeStage(STAGE_NONE); |
| +} |
| + |
| +void BluetoothHostPairingController::OnGetAdapter( |
| + scoped_refptr<device::BluetoothAdapter> adapter) { |
| + CHECK(!adapter_); |
|
achuithb
2014/08/20 21:52:34
Why CHECK?
Zachary Kuznia
2014/08/21 00:42:08
Done.
|
| + adapter_ = adapter; |
| + |
| + // TODO(zork): Make the device name prettier. |
|
achuithb
2014/08/20 21:52:33
bug-id
Zachary Kuznia
2014/08/21 00:42:07
Done.
|
| + device_name_ = base::StringPrintf("%s%s", kDeviceNamePrefix, |
| + adapter_->GetAddress().c_str()); |
| + adapter_->SetName( |
| + device_name_, |
| + base::Bind(&BluetoothHostPairingController::OnSetName, |
| + ptr_factory_.GetWeakPtr()), |
| + base::Bind(&BluetoothHostPairingController::OnSetError, |
| + ptr_factory_.GetWeakPtr())); |
| +} |
| + |
| +void BluetoothHostPairingController::OnSetName() { |
| + if (adapter_->IsPowered()) { |
| + OnSetPowered(); |
| + } else { |
| + adapter_->SetPowered( |
| + true, |
| + base::Bind(&BluetoothHostPairingController::OnSetPowered, |
| + ptr_factory_.GetWeakPtr()), |
| + base::Bind(&BluetoothHostPairingController::OnSetError, |
| + ptr_factory_.GetWeakPtr())); |
| + } |
| +} |
| + |
| +void BluetoothHostPairingController::OnSetPowered() { |
| + adapter_->AddPairingDelegate( |
| + this, device::BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH); |
| + |
| + device::BluetoothAdapter::ServiceOptions options; |
| + options.name.reset(new std::string(kPairingServiceName)); |
| + |
| + adapter_->CreateRfcommService( |
| + device::BluetoothUUID(kPairingServiceUUID), options, |
| + base::Bind(&BluetoothHostPairingController::OnCreateService, |
| + ptr_factory_.GetWeakPtr()), |
| + base::Bind(&BluetoothHostPairingController::OnCreateServiceError, |
| + ptr_factory_.GetWeakPtr())); |
| +} |
| + |
| +void BluetoothHostPairingController::OnCreateService( |
| + scoped_refptr<device::BluetoothSocket> socket) { |
| + service_socket_ = socket; |
| + |
| + service_socket_->Accept( |
| + base::Bind(&BluetoothHostPairingController::OnAccept, |
| + ptr_factory_.GetWeakPtr()), |
| + base::Bind(&BluetoothHostPairingController::OnAcceptError, |
| + ptr_factory_.GetWeakPtr())); |
| + |
| + adapter_->SetDiscoverable( |
| + true, |
| + base::Bind(&BluetoothHostPairingController::OnSetDiscoverable, |
| + ptr_factory_.GetWeakPtr(), true), |
| + base::Bind(&BluetoothHostPairingController::OnSetError, |
| + ptr_factory_.GetWeakPtr())); |
| +} |
| + |
| +void BluetoothHostPairingController::OnAccept( |
| + const device::BluetoothDevice* device, |
| + scoped_refptr<device::BluetoothSocket> socket) { |
| + adapter_->SetDiscoverable( |
| + false, |
| + base::Bind(&BluetoothHostPairingController::OnSetDiscoverable, |
| + ptr_factory_.GetWeakPtr(), false), |
| + base::Bind(&BluetoothHostPairingController::OnSetError, |
| + ptr_factory_.GetWeakPtr())); |
| + |
| + controller_socket_ = socket; |
| + service_socket_ = NULL; |
| + |
| + // TODO: Update Host. |
|
achuithb
2014/08/20 21:52:34
TODO(zork) + bug-id
Zachary Kuznia
2014/08/21 00:42:07
Done.
|
| + SendHostStatus(); |
| + |
| + controller_socket_->Receive( |
| + kReceiveSize, |
| + base::Bind(&BluetoothHostPairingController::OnReceiveComplete, |
| + ptr_factory_.GetWeakPtr()), |
| + base::Bind(&BluetoothHostPairingController::OnReceiveError, |
| + ptr_factory_.GetWeakPtr())); |
| + |
| + ChangeStage(STAGE_WAITING_FOR_CREDENTIALS); |
| +} |
| + |
| +void BluetoothHostPairingController::OnSetDiscoverable(bool change_stage) { |
| + if (change_stage) { |
| + DCHECK_EQ(current_stage_, STAGE_NONE); |
| + ChangeStage(STAGE_WAITING_FOR_CONTROLLER); |
| + } |
| +} |
| + |
| +void BluetoothHostPairingController::OnSendComplete(int bytes_sent) {} |
| + |
| +void BluetoothHostPairingController::OnReceiveComplete( |
| + int bytes, scoped_refptr<net::IOBuffer> io_buffer) { |
| + proto_decoder_->DecodeIOBuffer(bytes, io_buffer); |
| + |
| + controller_socket_->Receive( |
| + kReceiveSize, |
| + base::Bind(&BluetoothHostPairingController::OnReceiveComplete, |
| + ptr_factory_.GetWeakPtr()), |
| + base::Bind(&BluetoothHostPairingController::OnReceiveError, |
| + ptr_factory_.GetWeakPtr())); |
| +} |
| + |
| +void BluetoothHostPairingController::OnCreateServiceError( |
| + const std::string& message) { |
| + LOG(ERROR) << message; |
| + // TODO(zork): Add a stage for bluetooth error. |
|
achuithb
2014/08/20 21:52:34
bug-id
Zachary Kuznia
2014/08/21 00:42:08
Done.
|
| + ChangeStage(STAGE_NONE); |
| +} |
| + |
| +void BluetoothHostPairingController::OnSetError() { |
| + adapter_->RemovePairingDelegate(this); |
| + // TODO(zork): Add a stage for bluetooth error. |
|
achuithb
2014/08/20 21:52:33
bug-id
Zachary Kuznia
2014/08/21 00:42:07
Done.
|
| + ChangeStage(STAGE_NONE); |
| +} |
| + |
| +void BluetoothHostPairingController::OnAcceptError( |
| + const std::string& error_message) { |
| + LOG(ERROR) << error_message; |
| + Reset(); |
| +} |
| + |
| +void BluetoothHostPairingController::OnSendError( |
| + const std::string& error_message) { |
| + LOG(ERROR) << error_message; |
| +} |
| + |
| +void BluetoothHostPairingController::OnReceiveError( |
| + device::BluetoothSocket::ErrorReason reason, |
| + const std::string& error_message) { |
| + LOG(ERROR) << reason << ", " << error_message; |
| + Reset(); |
| +} |
| + |
| +void BluetoothHostPairingController::OnHostStatusMessage( |
| + const pairing_api::HostStatus& message) { |
| + NOTREACHED(); |
| +} |
| + |
| +void BluetoothHostPairingController::OnConfigureHostMessage( |
| + const pairing_api::ConfigureHost& message) { |
| + // TODO(zork): Add event to API to handle this case. |
|
achuithb
2014/08/20 21:52:33
bug-id
Zachary Kuznia
2014/08/21 00:42:07
Done.
|
| +} |
| + |
| +void BluetoothHostPairingController::OnPairDevicesMessage( |
| + const pairing_api::PairDevices& message) { |
| + if (current_stage_ != STAGE_WAITING_FOR_CREDENTIALS) { |
| + AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT, kErrorInvalidProtocol); |
| + return; |
| + } |
| + |
| + if (enrollment_domain_.empty()) { |
| + ChangeStage(STAGE_ENROLLING); |
| + // TODO: Enroll device, send error on error |
|
achuithb
2014/08/20 21:52:33
TODO(zork/achuith) + bug-id
Zachary Kuznia
2014/08/21 00:42:08
Done.
|
| + // For now, test domain is sent in the access token. |
| + enrollment_domain_ = message.parameters().admin_access_token(); |
| + ChangeStage(STAGE_PAIRING_DONE); |
| + SendHostStatus(); |
| + } else { |
| + // TODO: Check that domain matches. If not, send error and abort. |
|
achuithb
2014/08/20 21:52:33
TODO(zork/achuith) + bug-id
Did we decide to do t
Zachary Kuznia
2014/08/21 00:42:08
Done.
|
| + NOTREACHED(); |
| + } |
| +} |
| + |
| +void BluetoothHostPairingController::OnCompleteSetupMessage( |
| + const pairing_api::CompleteSetup& message) { |
| + if (current_stage_ != STAGE_PAIRING_DONE) { |
| + AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT, kErrorInvalidProtocol); |
| + return; |
| + } |
| + |
| + // TODO(zork): Handle adding another controller. |
|
achuithb
2014/08/20 21:52:34
bug-id
Zachary Kuznia
2014/08/21 00:42:08
Done.
|
| + ChangeStage(STAGE_FINISHED); |
| +} |
| + |
| +void BluetoothHostPairingController::OnErrorMessage( |
| + const pairing_api::Error& message) { |
| + NOTREACHED(); |
| +} |
| + |
| +// HostPairingFlow: |
|
achuithb
2014/08/20 21:52:33
REmove comment
Zachary Kuznia
2014/08/21 00:42:07
Done.
|
| +void BluetoothHostPairingController::AddObserver(Observer* observer) { |
| + observers_.AddObserver(observer); |
| +} |
| + |
| +void BluetoothHostPairingController::RemoveObserver(Observer* observer) { |
| + observers_.RemoveObserver(observer); |
| +} |
| + |
| +HostPairingController::Stage BluetoothHostPairingController::GetCurrentStage() { |
|
achuithb
2014/08/20 21:52:34
This should be current_stage() and defined in the
Zachary Kuznia
2014/08/21 00:42:07
Acknowledged.
|
| + return current_stage_; |
| +} |
| + |
| +void BluetoothHostPairingController::StartPairing() { |
| + CHECK(current_stage_ == STAGE_NONE); |
|
achuithb
2014/08/20 21:52:34
Why CHECK?
Zachary Kuznia
2014/08/21 00:42:08
Acknowledged.
|
| + bool bluetooth_available = |
| + device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable(); |
| + // TODO(zork): Add a stage for no bluetooth. |
|
achuithb
2014/08/20 21:52:33
bug-id
Zachary Kuznia
2014/08/21 00:42:07
Done.
|
| + if (!bluetooth_available) |
| + return; |
| + |
| + device::BluetoothAdapterFactory::GetAdapter( |
| + base::Bind(&BluetoothHostPairingController::OnGetAdapter, |
| + ptr_factory_.GetWeakPtr())); |
| +} |
| + |
| +std::string BluetoothHostPairingController::GetDeviceName() { |
|
achuithb
2014/08/20 21:52:33
const std::string& device_name() const
Zachary Kuznia
2014/08/21 00:42:07
Acknowledged.
|
| + return device_name_; |
| +} |
| + |
| +std::string BluetoothHostPairingController::GetConfirmationCode() { |
|
achuithb
2014/08/20 21:52:34
const std::string& GetConfirmationCode() const
Zachary Kuznia
2014/08/21 00:42:08
Acknowledged.
|
| + CHECK(current_stage_ == STAGE_WAITING_FOR_CODE_CONFIRMATION); |
|
achuithb
2014/08/20 21:52:34
Why CHECK?
Zachary Kuznia
2014/08/21 00:42:07
Done.
|
| + return confirmation_code_; |
| +} |
| + |
| +std::string BluetoothHostPairingController::GetEnrollmentDomain() { |
|
achuithb
2014/08/20 21:52:34
const std::string& enrollment_domain() const
Zachary Kuznia
2014/08/21 00:42:07
This is a virtual function, as we discussed.
|
| + return enrollment_domain_; |
| +} |
| + |
| +// device::BluetoothDevice::PairingDelegate: |
| +void BluetoothHostPairingController::RequestPinCode( |
| + device::BluetoothDevice* device) { |
| + // Disallow unknown device. |
| + device->RejectPairing(); |
| +} |
| + |
| +void BluetoothHostPairingController::RequestPasskey( |
| + device::BluetoothDevice* device) { |
| + // Disallow unknown device. |
| + device->RejectPairing(); |
| +} |
| + |
| +void BluetoothHostPairingController::DisplayPinCode( |
| + device::BluetoothDevice* device, |
| + const std::string& pincode) { |
| + // Disallow unknown device. |
| + device->RejectPairing(); |
| +} |
| + |
| +void BluetoothHostPairingController::DisplayPasskey( |
| + device::BluetoothDevice* device, |
| + uint32 passkey) { |
| + // Disallow unknown device. |
| + device->RejectPairing(); |
| +} |
| + |
| +void BluetoothHostPairingController::KeysEntered( |
| + device::BluetoothDevice* device, |
| + uint32 entered) { |
| + // Disallow unknown device. |
| + device->RejectPairing(); |
| +} |
| + |
| +void BluetoothHostPairingController::ConfirmPasskey( |
| + device::BluetoothDevice* device, |
| + uint32 passkey) { |
| + confirmation_code_ = base::StringPrintf("%06d", passkey); |
| + device->ConfirmPairing(); |
| + ChangeStage(STAGE_WAITING_FOR_CODE_CONFIRMATION); |
| +} |
| + |
| +void BluetoothHostPairingController::AuthorizePairing( |
| + device::BluetoothDevice* device) { |
| + // Disallow unknown device. |
| + device->RejectPairing(); |
| +} |
| + |
| +} // namespace pairing_chromeos |