summaryrefslogtreecommitdiffstats
path: root/components/pairing
diff options
context:
space:
mode:
authorzork <zork@chromium.org>2014-08-26 15:34:23 -0700
committerCommit bot <commit-bot@chromium.org>2014-08-26 22:46:36 +0000
commitde5908f77c572532a0d76a72b02c49a9165f582e (patch)
tree802a783f39517c4cde4d33184132ea602116db13 /components/pairing
parent00bff42f5738f985d04a888d64a64e802b65977d (diff)
downloadchromium_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.gn10
-rw-r--r--components/pairing/bluetooth_controller_pairing_controller.cc463
-rw-r--r--components/pairing/bluetooth_controller_pairing_controller.h125
-rw-r--r--components/pairing/bluetooth_host_pairing_controller.cc379
-rw-r--r--components/pairing/bluetooth_host_pairing_controller.h114
-rw-r--r--components/pairing/bluetooth_pairing_constants.cc15
-rw-r--r--components/pairing/bluetooth_pairing_constants.h23
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_