diff options
author | zork <zork@chromium.org> | 2014-08-26 15:34:23 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-08-26 22:46:36 +0000 |
commit | de5908f77c572532a0d76a72b02c49a9165f582e (patch) | |
tree | 802a783f39517c4cde4d33184132ea602116db13 /components/pairing | |
parent | 00bff42f5738f985d04a888d64a64e802b65977d (diff) | |
download | chromium_src-de5908f77c572532a0d76a72b02c49a9165f582e.zip chromium_src-de5908f77c572532a0d76a72b02c49a9165f582e.tar.gz chromium_src-de5908f77c572532a0d76a72b02c49a9165f582e.tar.bz2 |
Add bluetooth host and controller delegates for pairing.
BUG=380961, 380962
Review URL: https://codereview.chromium.org/469613002
Cr-Commit-Position: refs/heads/master@{#292005}
Diffstat (limited to 'components/pairing')
-rw-r--r-- | components/pairing/BUILD.gn | 10 | ||||
-rw-r--r-- | components/pairing/bluetooth_controller_pairing_controller.cc | 463 | ||||
-rw-r--r-- | components/pairing/bluetooth_controller_pairing_controller.h | 125 | ||||
-rw-r--r-- | components/pairing/bluetooth_host_pairing_controller.cc | 379 | ||||
-rw-r--r-- | components/pairing/bluetooth_host_pairing_controller.h | 114 | ||||
-rw-r--r-- | components/pairing/bluetooth_pairing_constants.cc | 15 | ||||
-rw-r--r-- | components/pairing/bluetooth_pairing_constants.h | 23 |
7 files changed, 1127 insertions, 2 deletions
diff --git a/components/pairing/BUILD.gn b/components/pairing/BUILD.gn index d017ec4..02011ef 100644 --- a/components/pairing/BUILD.gn +++ b/components/pairing/BUILD.gn @@ -6,12 +6,18 @@ import("//third_party/protobuf/proto_library.gni") source_set("pairing") { sources = [ + "pairing/bluetooth_controller_pairing_controller.cc", + "pairing/bluetooth_controller_pairing_controller.h", + "pairing/bluetooth_host_pairing_controller.cc", + "pairing/bluetooth_host_pairing_controller.h", + "pairing/bluetooth_pairing_constants.cc", + "pairing/bluetooth_pairing_constants.h", + "pairing/controller_pairing_controller.cc", + "pairing/controller_pairing_controller.h", "pairing/fake_controller_pairing_controller.cc", "pairing/fake_controller_pairing_controller.h", "pairing/fake_host_pairing_controller.cc", "pairing/fake_host_pairing_controller.h", - "pairing/controller_pairing_controller.cc", - "pairing/controller_pairing_controller.h", "pairing/host_pairing_controller.cc", "pairing/host_pairing_controller.h", "pairing/message_buffer.cc", diff --git a/components/pairing/bluetooth_controller_pairing_controller.cc b/components/pairing/bluetooth_controller_pairing_controller.cc new file mode 100644 index 0000000..c90dfb7 --- /dev/null +++ b/components/pairing/bluetooth_controller_pairing_controller.cc @@ -0,0 +1,463 @@ +// 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_controller_pairing_controller.h" + +#include "base/bind.h" +#include "base/logging.h" +#include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" +#include "components/pairing/bluetooth_pairing_constants.h" +#include "components/pairing/pairing_api.pb.h" +#include "device/bluetooth/bluetooth_adapter_factory.h" +#include "device/bluetooth/bluetooth_discovery_session.h" +#include "net/base/io_buffer.h" + +namespace { +const char* kFakeEnrollmentDomain = "http://fake.com"; +const int kReceiveSize = 16384; +} + +namespace pairing_chromeos { + +BluetoothControllerPairingController::BluetoothControllerPairingController() + : current_stage_(STAGE_NONE), + got_initial_status_(false), + proto_decoder_(new ProtoDecoder(this)), + ptr_factory_(this) { +} + +BluetoothControllerPairingController::~BluetoothControllerPairingController() { + Reset(); +} + +device::BluetoothDevice* BluetoothControllerPairingController::GetController() { + DCHECK(!controller_device_id_.empty()); + device::BluetoothDevice* device = adapter_->GetDevice(controller_device_id_); + if (!device) { + LOG(ERROR) << "Lost connection to controller."; + ChangeStage(STAGE_ESTABLISHING_CONNECTION_ERROR); + } + + return device; +} + +void BluetoothControllerPairingController::ChangeStage(Stage new_stage) { + if (current_stage_ == new_stage) + return; + current_stage_ = new_stage; + FOR_EACH_OBSERVER(ControllerPairingController::Observer, observers_, + PairingStageChanged(new_stage)); +} + +void BluetoothControllerPairingController::Reset() { + got_initial_status_ = false; + controller_device_id_.clear(); + discovery_session_.reset(); + + if (socket_) { + socket_->Close(); + socket_ = NULL; + } + + if (adapter_) { + adapter_->RemoveObserver(this); + adapter_ = NULL; + } +} + +void BluetoothControllerPairingController::DeviceFound( + device::BluetoothDevice* device) { + DCHECK_EQ(current_stage_, STAGE_DEVICES_DISCOVERY); + DCHECK(thread_checker_.CalledOnValidThread()); + if (StartsWith(device->GetName(), base::ASCIIToUTF16(kDeviceNamePrefix), + false)) { + discovered_devices_.insert(device->GetAddress()); + FOR_EACH_OBSERVER(ControllerPairingController::Observer, observers_, + DiscoveredDevicesListChanged()); + } +} + +void BluetoothControllerPairingController::DeviceLost( + device::BluetoothDevice* device) { + DCHECK_EQ(current_stage_, STAGE_DEVICES_DISCOVERY); + DCHECK(thread_checker_.CalledOnValidThread()); + std::set<std::string>::iterator ix = + discovered_devices_.find(device->GetAddress()); + if (ix != discovered_devices_.end()) { + discovered_devices_.erase(ix); + FOR_EACH_OBSERVER(ControllerPairingController::Observer, observers_, + DiscoveredDevicesListChanged()); + } +} + +void BluetoothControllerPairingController::OnSetPowered() { + DCHECK(thread_checker_.CalledOnValidThread()); + adapter_->StartDiscoverySession( + base::Bind(&BluetoothControllerPairingController::OnStartDiscoverySession, + ptr_factory_.GetWeakPtr()), + base::Bind(&BluetoothControllerPairingController::OnError, + ptr_factory_.GetWeakPtr())); +} + +void BluetoothControllerPairingController::OnGetAdapter( + scoped_refptr<device::BluetoothAdapter> adapter) { + DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(!adapter_); + adapter_ = adapter; + adapter_->AddObserver(this); + + if (adapter_->IsPowered()) { + OnSetPowered(); + } else { + adapter_->SetPowered( + true, + base::Bind(&BluetoothControllerPairingController::OnSetPowered, + ptr_factory_.GetWeakPtr()), + base::Bind(&BluetoothControllerPairingController::OnError, + ptr_factory_.GetWeakPtr())); + } +} + +void BluetoothControllerPairingController::OnStartDiscoverySession( + scoped_ptr<device::BluetoothDiscoverySession> discovery_session) { + DCHECK(thread_checker_.CalledOnValidThread()); + discovery_session_ = discovery_session.Pass(); + ChangeStage(STAGE_DEVICES_DISCOVERY); + + device::BluetoothAdapter::DeviceList device_list = adapter_->GetDevices(); + for (device::BluetoothAdapter::DeviceList::iterator ix = device_list.begin(); + ix != device_list.end(); ++ix) { + DeviceFound(*ix); + } +} + +void BluetoothControllerPairingController::OnConnect() { + DCHECK(thread_checker_.CalledOnValidThread()); + device::BluetoothDevice* device = GetController(); + if (device) { + device->ConnectToService( + device::BluetoothUUID(kPairingServiceUUID), + base::Bind(&BluetoothControllerPairingController::OnConnectToService, + ptr_factory_.GetWeakPtr()), + base::Bind(&BluetoothControllerPairingController::OnErrorWithMessage, + ptr_factory_.GetWeakPtr())); + } +} + +void BluetoothControllerPairingController::OnConnectToService( + scoped_refptr<device::BluetoothSocket> socket) { + DCHECK(thread_checker_.CalledOnValidThread()); + socket_ = socket; + + socket_->Receive( + kReceiveSize, + base::Bind(&BluetoothControllerPairingController::OnReceiveComplete, + ptr_factory_.GetWeakPtr()), + base::Bind(&BluetoothControllerPairingController::OnReceiveError, + ptr_factory_.GetWeakPtr())); +} + +void BluetoothControllerPairingController::OnSendComplete(int bytes_sent) {} + +void BluetoothControllerPairingController::OnReceiveComplete( + int bytes, scoped_refptr<net::IOBuffer> io_buffer) { + DCHECK(thread_checker_.CalledOnValidThread()); + proto_decoder_->DecodeIOBuffer(bytes, io_buffer); + + socket_->Receive( + kReceiveSize, + base::Bind(&BluetoothControllerPairingController::OnReceiveComplete, + ptr_factory_.GetWeakPtr()), + base::Bind(&BluetoothControllerPairingController::OnReceiveError, + ptr_factory_.GetWeakPtr())); +} + +void BluetoothControllerPairingController::OnError() { + // TODO(zork): Add a stage for initialization error. (http://crbug.com/405744) + LOG(ERROR) << "Pairing initialization failed"; + Reset(); +} + +void BluetoothControllerPairingController::OnErrorWithMessage( + const std::string& message) { + // TODO(zork): Add a stage for initialization error. (http://crbug.com/405744) + LOG(ERROR) << message; + Reset(); +} + +void BluetoothControllerPairingController::OnConnectError( + device::BluetoothDevice::ConnectErrorCode error_code) { + DCHECK(thread_checker_.CalledOnValidThread()); + device::BluetoothDevice* device = GetController(); + + if (device && device->IsPaired()) { + // The connection attempt is only used to start the pairing between the + // devices. If the connection fails, it's not a problem as long as pairing + // was successful. + OnConnect(); + } +} + +void BluetoothControllerPairingController::OnReceiveError( + device::BluetoothSocket::ErrorReason reason, + const std::string& error_message) { + LOG(ERROR) << reason << ", " << error_message; + Reset(); +} + +void BluetoothControllerPairingController::AddObserver( + ControllerPairingController::Observer* observer) { + observers_.AddObserver(observer); +} + +void BluetoothControllerPairingController::RemoveObserver( + ControllerPairingController::Observer* observer) { + observers_.RemoveObserver(observer); +} + +ControllerPairingController::Stage +BluetoothControllerPairingController::GetCurrentStage() { + return current_stage_; +} + +void BluetoothControllerPairingController::StartPairing() { + DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(current_stage_ == STAGE_NONE || + current_stage_ == STAGE_DEVICE_NOT_FOUND || + current_stage_ == STAGE_ESTABLISHING_CONNECTION_ERROR || + current_stage_ == STAGE_HOST_ENROLLMENT_ERROR); + // TODO(zork): Add a stage for no bluetooth. (http://crbug.com/405744) + if (!device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) { + ChangeStage(STAGE_DEVICE_NOT_FOUND); + return; + } + + device::BluetoothAdapterFactory::GetAdapter( + base::Bind(&BluetoothControllerPairingController::OnGetAdapter, + ptr_factory_.GetWeakPtr())); + +} + +ControllerPairingController::DeviceIdList +BluetoothControllerPairingController::GetDiscoveredDevices() { + DCHECK_EQ(current_stage_, STAGE_DEVICES_DISCOVERY); + return DeviceIdList(discovered_devices_.begin(), discovered_devices_.end()); +} + +void BluetoothControllerPairingController::ChooseDeviceForPairing( + const std::string& device_id) { + DCHECK_EQ(current_stage_, STAGE_DEVICES_DISCOVERY); + DCHECK(discovered_devices_.count(device_id)); + discovery_session_.reset(); + controller_device_id_ = device_id; + + device::BluetoothDevice* device = GetController(); + + if (device) { + ChangeStage(STAGE_ESTABLISHING_CONNECTION); + if (device->IsPaired()) { + OnConnect(); + } else { + device->Connect( + this, + base::Bind(&BluetoothControllerPairingController::OnConnect, + ptr_factory_.GetWeakPtr()), + base::Bind(&BluetoothControllerPairingController::OnConnectError, + ptr_factory_.GetWeakPtr())); + } + } +} + +void BluetoothControllerPairingController::RepeatDiscovery() { + DCHECK(current_stage_ == STAGE_DEVICE_NOT_FOUND || + current_stage_ == STAGE_ESTABLISHING_CONNECTION_ERROR || + current_stage_ == STAGE_HOST_ENROLLMENT_ERROR); + Reset(); + StartPairing(); +} + +std::string BluetoothControllerPairingController::GetConfirmationCode() { + DCHECK_EQ(current_stage_, STAGE_WAITING_FOR_CODE_CONFIRMATION); + DCHECK(!confirmation_code_.empty()); + return confirmation_code_; +} + +void BluetoothControllerPairingController::SetConfirmationCodeIsCorrect( + bool correct) { + DCHECK_EQ(current_stage_, STAGE_WAITING_FOR_CODE_CONFIRMATION); + + device::BluetoothDevice* device = GetController(); + if (!device) + return; + + if (correct) { + device->ConfirmPairing(); + // Once pairing is confirmed, the connection will either be successful, or + // fail. Either case is acceptable as long as the devices are paired. + } else { + device->RejectPairing(); + controller_device_id_.clear(); + RepeatDiscovery(); + } +} + +void BluetoothControllerPairingController::OnAuthenticationDone( + const chromeos::UserContext& user_context, + content::BrowserContext* browser_context) { + DCHECK_EQ(current_stage_, STAGE_WAITING_FOR_CREDENTIALS); + + // TODO(zork): Get configuration from UI and send to Host. + // (http://crbug.com/405744) + + // TODO(zork): Get proper credentials. (http://crbug.com/405744) + // For now, send a fake domain. + pairing_api::PairDevices pair_devices; + pair_devices.set_api_version(kPairingAPIVersion); + pair_devices.mutable_parameters()->set_admin_access_token( + kFakeEnrollmentDomain); + + int size = 0; + scoped_refptr<net::IOBuffer> io_buffer( + ProtoDecoder::SendPairDevices(pair_devices, &size)); + + socket_->Send( + io_buffer, size, + base::Bind(&BluetoothControllerPairingController::OnSendComplete, + ptr_factory_.GetWeakPtr()), + base::Bind(&BluetoothControllerPairingController::OnErrorWithMessage, + ptr_factory_.GetWeakPtr())); + ChangeStage(STAGE_HOST_ENROLLMENT_IN_PROGRESS); +} + +void BluetoothControllerPairingController::StartSession() { + DCHECK_EQ(current_stage_, STAGE_PAIRING_DONE); + ChangeStage(STAGE_FINISHED); +} + +// ProtoDecoder::Observer: +void BluetoothControllerPairingController::OnHostStatusMessage( + const pairing_api::HostStatus& message) { + if (got_initial_status_) { + if (message.parameters().has_domain()) { + // TODO(zork): Remove this if we don't actually need the domain for UI. + // (http://crbug.com/405761) + if (message.parameters().domain() == kFakeEnrollmentDomain) { + pairing_api::CompleteSetup complete_setup; + complete_setup.set_api_version(kPairingAPIVersion); + // TODO(zork): Get AddAnother from UI (http://crbug.com/405757) + complete_setup.mutable_parameters()->set_add_another(false); + + int size = 0; + scoped_refptr<net::IOBuffer> io_buffer( + ProtoDecoder::SendCompleteSetup(complete_setup, &size)); + + socket_->Send( + io_buffer, size, + base::Bind(&BluetoothControllerPairingController::OnSendComplete, + ptr_factory_.GetWeakPtr()), + base::Bind( + &BluetoothControllerPairingController::OnErrorWithMessage, + ptr_factory_.GetWeakPtr())); + ChangeStage(STAGE_PAIRING_DONE); + } else { + ChangeStage(STAGE_HOST_ENROLLMENT_ERROR); + } + } else { + ChangeStage(STAGE_HOST_ENROLLMENT_ERROR); + } + } else { + got_initial_status_ = true; + + // TODO(zork): Check domain. (http://crbug.com/405761) + + // TODO(zork): Handling updating stages (http://crbug.com/405754). + ChangeStage(STAGE_WAITING_FOR_CREDENTIALS); + } +} + +void BluetoothControllerPairingController::OnConfigureHostMessage( + const pairing_api::ConfigureHost& message) { + NOTREACHED(); +} + +void BluetoothControllerPairingController::OnPairDevicesMessage( + const pairing_api::PairDevices& message) { + NOTREACHED(); +} + +void BluetoothControllerPairingController::OnCompleteSetupMessage( + const pairing_api::CompleteSetup& message) { + NOTREACHED(); +} + +void BluetoothControllerPairingController::OnErrorMessage( + const pairing_api::Error& message) { + LOG(ERROR) << message.parameters().code() << ", " << + message.parameters().description(); + ChangeStage(STAGE_HOST_ENROLLMENT_ERROR); +} + +void BluetoothControllerPairingController::DeviceAdded( + device::BluetoothAdapter* adapter, + device::BluetoothDevice* device) { + DCHECK_EQ(adapter, adapter_.get()); + DeviceFound(device); +} + +void BluetoothControllerPairingController::DeviceRemoved( + device::BluetoothAdapter* adapter, + device::BluetoothDevice* device) { + DCHECK_EQ(adapter, adapter_.get()); + DeviceLost(device); +} + +void BluetoothControllerPairingController::RequestPinCode( + device::BluetoothDevice* device) { + // Disallow unknown device. + device->RejectPairing(); +} + +void BluetoothControllerPairingController::RequestPasskey( + device::BluetoothDevice* device) { + // Disallow unknown device. + device->RejectPairing(); +} + +void BluetoothControllerPairingController::DisplayPinCode( + device::BluetoothDevice* device, + const std::string& pincode) { + // Disallow unknown device. + device->RejectPairing(); +} + +void BluetoothControllerPairingController::DisplayPasskey( + device::BluetoothDevice* device, + uint32 passkey) { + // Disallow unknown device. + device->RejectPairing(); +} + +void BluetoothControllerPairingController::KeysEntered( + device::BluetoothDevice* device, + uint32 entered) { + // Disallow unknown device. + device->RejectPairing(); +} + +void BluetoothControllerPairingController::ConfirmPasskey( + device::BluetoothDevice* device, + uint32 passkey) { + confirmation_code_ = base::StringPrintf("%06d", passkey); + ChangeStage(STAGE_WAITING_FOR_CODE_CONFIRMATION); +} + +void BluetoothControllerPairingController::AuthorizePairing( + device::BluetoothDevice* device) { + // Disallow unknown device. + device->RejectPairing(); +} + +} // namespace pairing_chromeos diff --git a/components/pairing/bluetooth_controller_pairing_controller.h b/components/pairing/bluetooth_controller_pairing_controller.h new file mode 100644 index 0000000..43ddd75 --- /dev/null +++ b/components/pairing/bluetooth_controller_pairing_controller.h @@ -0,0 +1,125 @@ +// 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. + +#ifndef CHROMEOS_PAIRING_BLUETOOTH_CONTROLLER_PAIRING_FLOW_H_ +#define CHROMEOS_PAIRING_BLUETOOTH_CONTROLLER_PAIRING_FLOW_H_ + +#include <set> + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "base/observer_list.h" +#include "base/threading/thread_checker.h" +#include "components/pairing/controller_pairing_controller.h" +#include "components/pairing/proto_decoder.h" +#include "device/bluetooth/bluetooth_adapter.h" +#include "device/bluetooth/bluetooth_device.h" +#include "device/bluetooth/bluetooth_socket.h" + +namespace net { +class IOBuffer; +} + +namespace pairing_chromeos { + +class BluetoothControllerPairingController + : public ControllerPairingController, + public ProtoDecoder::Observer, + public device::BluetoothAdapter::Observer, + public device::BluetoothDevice::PairingDelegate { + public: + BluetoothControllerPairingController(); + virtual ~BluetoothControllerPairingController(); + + private: + void ChangeStage(Stage new_stage); + device::BluetoothDevice* GetController(); + void Reset(); + void DeviceFound(device::BluetoothDevice* device); + void DeviceLost(device::BluetoothDevice* device); + + void OnSetPowered(); + void OnGetAdapter(scoped_refptr<device::BluetoothAdapter> adapter); + void OnStartDiscoverySession( + scoped_ptr<device::BluetoothDiscoverySession> discovery_session); + void OnConnect(); + void OnConnectToService(scoped_refptr<device::BluetoothSocket> socket); + void OnSendComplete(int bytes_sent); + void OnReceiveComplete(int bytes, scoped_refptr<net::IOBuffer> io_buffer); + + void OnError(); + void OnErrorWithMessage(const std::string& message); + void OnConnectError(device::BluetoothDevice::ConnectErrorCode error_code); + void OnReceiveError(device::BluetoothSocket::ErrorReason reason, + const std::string& error_message); + + // ControllerPairingController: + virtual void AddObserver( + ControllerPairingController::Observer* observer) OVERRIDE; + virtual void RemoveObserver( + ControllerPairingController::Observer* observer) OVERRIDE; + virtual Stage GetCurrentStage() OVERRIDE; + virtual void StartPairing() OVERRIDE; + virtual DeviceIdList GetDiscoveredDevices() OVERRIDE; + virtual void ChooseDeviceForPairing(const std::string& device_id) OVERRIDE; + virtual void RepeatDiscovery() OVERRIDE; + virtual std::string GetConfirmationCode() OVERRIDE; + virtual void SetConfirmationCodeIsCorrect(bool correct) OVERRIDE; + virtual void OnAuthenticationDone( + const chromeos::UserContext& user_context, + content::BrowserContext* browser_context) OVERRIDE; + virtual void StartSession() OVERRIDE; + + // ProtoDecoder::Observer: + virtual void OnHostStatusMessage( + const pairing_api::HostStatus& message) OVERRIDE; + virtual void OnConfigureHostMessage( + const pairing_api::ConfigureHost& message) OVERRIDE; + virtual void OnPairDevicesMessage( + const pairing_api::PairDevices& message) OVERRIDE; + virtual void OnCompleteSetupMessage( + const pairing_api::CompleteSetup& message) OVERRIDE; + virtual void OnErrorMessage(const pairing_api::Error& message) OVERRIDE; + + // BluetoothAdapter::Observer: + virtual void DeviceAdded(device::BluetoothAdapter* adapter, + device::BluetoothDevice* device) OVERRIDE; + virtual void DeviceRemoved(device::BluetoothAdapter* adapter, + device::BluetoothDevice* device) OVERRIDE; + + // device::BluetoothDevice::PairingDelegate: + virtual void RequestPinCode(device::BluetoothDevice* device) OVERRIDE; + virtual void RequestPasskey(device::BluetoothDevice* device) OVERRIDE; + virtual void DisplayPinCode(device::BluetoothDevice* device, + const std::string& pincode) OVERRIDE; + virtual void DisplayPasskey(device::BluetoothDevice* device, + uint32 passkey) OVERRIDE; + virtual void KeysEntered(device::BluetoothDevice* device, + uint32 entered) OVERRIDE; + virtual void ConfirmPasskey(device::BluetoothDevice* device, + uint32 passkey) OVERRIDE; + virtual void AuthorizePairing(device::BluetoothDevice* device) OVERRIDE; + + Stage current_stage_; + bool got_initial_status_; + scoped_refptr<device::BluetoothAdapter> adapter_; + scoped_ptr<device::BluetoothDiscoverySession> discovery_session_; + scoped_refptr<device::BluetoothSocket> socket_; + std::string controller_device_id_; + + std::string confirmation_code_; + std::set<std::string> discovered_devices_; + + scoped_ptr<ProtoDecoder> proto_decoder_; + + base::ThreadChecker thread_checker_; + ObserverList<ControllerPairingController::Observer> observers_; + base::WeakPtrFactory<BluetoothControllerPairingController> ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(BluetoothControllerPairingController); +}; + +} // namespace pairing_chromeos + +#endif // CHROMEOS_PAIRING_BLUETOOTH_CONTROLLER_PAIRING_FLOW_H_ diff --git a/components/pairing/bluetooth_host_pairing_controller.cc b/components/pairing/bluetooth_host_pairing_controller.cc new file mode 100644 index 0000000..fc229a1 --- /dev/null +++ b/components/pairing/bluetooth_host_pairing_controller.cc @@ -0,0 +1,379 @@ +// 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() + : current_stage_(STAGE_NONE), + device_(NULL), + proto_decoder_(new ProtoDecoder(this)), + ptr_factory_(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(zork): Get these values from the UI. (http://crbug.com/405744) + 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(zork): Get a list of other paired controllers. + // (http://crbug.com/405757) + + 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) { + DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(!adapter_); + adapter_ = adapter; + + // TODO(zork): Make the device name prettier. (http://crbug.com/405774) + 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() { + DCHECK(thread_checker_.CalledOnValidThread()); + 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() { + DCHECK(thread_checker_.CalledOnValidThread()); + 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) { + DCHECK(thread_checker_.CalledOnValidThread()); + 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) { + DCHECK(thread_checker_.CalledOnValidThread()); + 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. (http://crbug.com/405754) + 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) { + DCHECK(thread_checker_.CalledOnValidThread()); + 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) { + DCHECK(thread_checker_.CalledOnValidThread()); + 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 initialization error. (http://crbug.com/405744) + ChangeStage(STAGE_NONE); +} + +void BluetoothHostPairingController::OnSetError() { + adapter_->RemovePairingDelegate(this); + // TODO(zork): Add a stage for initialization error. (http://crbug.com/405744) + 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. (http://crbug.com/405744) +} + +void BluetoothHostPairingController::OnPairDevicesMessage( + const pairing_api::PairDevices& message) { + DCHECK(thread_checker_.CalledOnValidThread()); + if (current_stage_ != STAGE_WAITING_FOR_CREDENTIALS) { + AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT, kErrorInvalidProtocol); + return; + } + + ChangeStage(STAGE_ENROLLING); + // TODO(zork,achuith): Enroll device, send error on error. + // (http://crbug.com/374990) + // For now, test domain is sent in the access token. + enrollment_domain_ = message.parameters().admin_access_token(); + ChangeStage(STAGE_PAIRING_DONE); + SendHostStatus(); +} + +void BluetoothHostPairingController::OnCompleteSetupMessage( + const pairing_api::CompleteSetup& message) { + DCHECK(thread_checker_.CalledOnValidThread()); + if (current_stage_ != STAGE_PAIRING_DONE) { + AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT, kErrorInvalidProtocol); + return; + } + + // TODO(zork): Handle adding another controller. (http://crbug.com/405757) + ChangeStage(STAGE_FINISHED); +} + +void BluetoothHostPairingController::OnErrorMessage( + const pairing_api::Error& message) { + NOTREACHED(); +} + +void BluetoothHostPairingController::AddObserver(Observer* observer) { + observers_.AddObserver(observer); +} + +void BluetoothHostPairingController::RemoveObserver(Observer* observer) { + observers_.RemoveObserver(observer); +} + +HostPairingController::Stage BluetoothHostPairingController::GetCurrentStage() { + return current_stage_; +} + +void BluetoothHostPairingController::StartPairing() { + DCHECK_EQ(current_stage_, STAGE_NONE); + bool bluetooth_available = + device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable(); + // TODO(zork): Add a stage for initialization error. (http://crbug.com/405744) + if (!bluetooth_available) + return; + + device::BluetoothAdapterFactory::GetAdapter( + base::Bind(&BluetoothHostPairingController::OnGetAdapter, + ptr_factory_.GetWeakPtr())); +} + +std::string BluetoothHostPairingController::GetDeviceName() { + return device_name_; +} + +std::string BluetoothHostPairingController::GetConfirmationCode() { + DCHECK_EQ(current_stage_, STAGE_WAITING_FOR_CODE_CONFIRMATION); + return confirmation_code_; +} + +std::string BluetoothHostPairingController::GetEnrollmentDomain() { + return enrollment_domain_; +} + +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 diff --git a/components/pairing/bluetooth_host_pairing_controller.h b/components/pairing/bluetooth_host_pairing_controller.h new file mode 100644 index 0000000..c033584 --- /dev/null +++ b/components/pairing/bluetooth_host_pairing_controller.h @@ -0,0 +1,114 @@ +// 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. + +#ifndef CHROMEOS_PAIRING_BLUETOOTH_HOST_PAIRING_CONTROLLER_H_ +#define CHROMEOS_PAIRING_BLUETOOTH_HOST_PAIRING_CONTROLLER_H_ + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "base/observer_list.h" +#include "base/threading/thread_checker.h" +#include "components/pairing/host_pairing_controller.h" +#include "components/pairing/proto_decoder.h" +#include "device/bluetooth/bluetooth_device.h" +#include "device/bluetooth/bluetooth_socket.h" + +namespace device { +class BluetoothAdapter; +} + +namespace net { +class IOBuffer; +} + +namespace pairing_chromeos { + +class BluetoothHostPairingController + : public HostPairingController, + public ProtoDecoder::Observer, + public device::BluetoothDevice::PairingDelegate { + public: + typedef HostPairingController::Observer Observer; + + BluetoothHostPairingController(); + virtual ~BluetoothHostPairingController(); + + private: + void ChangeStage(Stage new_stage); + void SendHostStatus(); + void AbortWithError(int code, const std::string& message); + void Reset(); + + void OnGetAdapter(scoped_refptr<device::BluetoothAdapter> adapter); + void OnSetName(); + void OnSetPowered(); + void OnCreateService(scoped_refptr<device::BluetoothSocket> socket); + void OnSetDiscoverable(bool change_stage); + void OnAccept(const device::BluetoothDevice* device, + scoped_refptr<device::BluetoothSocket> socket); + void OnSendComplete(int bytes_sent); + void OnReceiveComplete(int bytes, scoped_refptr<net::IOBuffer> io_buffer); + + void OnCreateServiceError(const std::string& message); + void OnSetError(); + void OnAcceptError(const std::string& error_message); + void OnSendError(const std::string& error_message); + void OnReceiveError(device::BluetoothSocket::ErrorReason reason, + const std::string& error_message); + + // HostPairingController: + virtual void AddObserver(Observer* observer) OVERRIDE; + virtual void RemoveObserver(Observer* observer) OVERRIDE; + virtual Stage GetCurrentStage() OVERRIDE; + virtual void StartPairing() OVERRIDE; + virtual std::string GetDeviceName() OVERRIDE; + virtual std::string GetConfirmationCode() OVERRIDE; + virtual std::string GetEnrollmentDomain() OVERRIDE; + + // ProtoDecoder::Observer: + virtual void OnHostStatusMessage( + const pairing_api::HostStatus& message) OVERRIDE; + virtual void OnConfigureHostMessage( + const pairing_api::ConfigureHost& message) OVERRIDE; + virtual void OnPairDevicesMessage( + const pairing_api::PairDevices& message) OVERRIDE; + virtual void OnCompleteSetupMessage( + const pairing_api::CompleteSetup& message) OVERRIDE; + virtual void OnErrorMessage(const pairing_api::Error& message) OVERRIDE; + + // device::BluetoothDevice::PairingDelegate: + virtual void RequestPinCode(device::BluetoothDevice* device) OVERRIDE; + virtual void RequestPasskey(device::BluetoothDevice* device) OVERRIDE; + virtual void DisplayPinCode(device::BluetoothDevice* device, + const std::string& pincode) OVERRIDE; + virtual void DisplayPasskey(device::BluetoothDevice* device, + uint32 passkey) OVERRIDE; + virtual void KeysEntered(device::BluetoothDevice* device, + uint32 entered) OVERRIDE; + virtual void ConfirmPasskey(device::BluetoothDevice* device, + uint32 passkey) OVERRIDE; + virtual void AuthorizePairing(device::BluetoothDevice* device) OVERRIDE; + + Stage current_stage_; + std::string device_name_; + std::string confirmation_code_; + std::string enrollment_domain_; + + scoped_refptr<device::BluetoothAdapter> adapter_; + device::BluetoothDevice* device_; + scoped_refptr<device::BluetoothSocket> service_socket_; + scoped_refptr<device::BluetoothSocket> controller_socket_; + scoped_ptr<ProtoDecoder> proto_decoder_; + + base::ThreadChecker thread_checker_; + ObserverList<Observer> observers_; + base::WeakPtrFactory<BluetoothHostPairingController> ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(BluetoothHostPairingController); +}; + +} // namespace pairing_chromeos + +#endif // CHROMEOS_PAIRING_BLUETOOTH_HOST_PAIRING_CONTROLLER_H_ diff --git a/components/pairing/bluetooth_pairing_constants.cc b/components/pairing/bluetooth_pairing_constants.cc new file mode 100644 index 0000000..f25f8f7 --- /dev/null +++ b/components/pairing/bluetooth_pairing_constants.cc @@ -0,0 +1,15 @@ +// 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_pairing_constants.h" + +namespace pairing_chromeos { + +const char* kPairingServiceUUID = "f035ff16-c025-468e-bb16-967704d141ea"; +const char* kPairingServiceName = "ChromeboxPairing"; +const char* kDeviceNamePrefix = "Chromebox_"; +const char* kErrorInvalidProtocol = "Invalid protocol"; +const int kPairingAPIVersion = 1; + +} // namespace pairing_chromeos diff --git a/components/pairing/bluetooth_pairing_constants.h b/components/pairing/bluetooth_pairing_constants.h new file mode 100644 index 0000000..f28d7ab --- /dev/null +++ b/components/pairing/bluetooth_pairing_constants.h @@ -0,0 +1,23 @@ +// 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. + +#ifndef CHROMEOS_PAIRING_BLUETOOTH_PAIRING_CONSTANTS_H_ +#define CHROMEOS_PAIRING_BLUETOOTH_PAIRING_CONSTANTS_H_ + +namespace pairing_chromeos { + +extern const char* kPairingServiceUUID; +extern const char* kPairingServiceName; +extern const char* kDeviceNamePrefix; +extern const char* kErrorInvalidProtocol; +extern const int kPairingAPIVersion; + +enum { + PAIRING_ERROR_NONE = 0, + PAIRING_ERROR_PAIRING_OR_ENROLLMENT = 1, +}; + +} // namespace pairing_chromeos + +#endif // CHROMEOS_PAIRING_BLUETOOTH_PAIRING_CONSTANTS_H_ |