1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/pairing/bluetooth_host_pairing_controller.h"
9 #include "base/logging.h"
10 #include "base/strings/stringprintf.h"
11 #include "components/pairing/bluetooth_pairing_constants.h"
12 #include "components/pairing/pairing_api.pb.h"
13 #include "components/pairing/proto_decoder.h"
14 #include "device/bluetooth/bluetooth_adapter_factory.h"
15 #include "net/base/io_buffer.h"
18 const int kReceiveSize = 16384;
21 namespace pairing_chromeos {
23 BluetoothHostPairingController::BluetoothHostPairingController()
24 : current_stage_(STAGE_NONE),
26 proto_decoder_(new ProtoDecoder(this)),
30 BluetoothHostPairingController::~BluetoothHostPairingController() {
32 if (adapter_->IsDiscoverable()) {
33 adapter_->SetDiscoverable(false, base::Closure(), base::Closure());
35 adapter_->RemoveObserver(this);
40 void BluetoothHostPairingController::ChangeStage(Stage new_stage) {
41 if (current_stage_ == new_stage)
43 current_stage_ = new_stage;
44 FOR_EACH_OBSERVER(Observer, observers_, PairingStageChanged(new_stage));
47 void BluetoothHostPairingController::SendHostStatus() {
48 pairing_api::HostStatus host_status;
50 host_status.set_api_version(kPairingAPIVersion);
51 if (!enrollment_domain_.empty())
52 host_status.mutable_parameters()->set_domain(enrollment_domain_);
54 // TODO(zork): Get these values from the UI. (http://crbug.com/405744)
55 host_status.mutable_parameters()->set_connectivity(
56 pairing_api::HostStatusParameters::CONNECTIVITY_CONNECTED);
57 host_status.mutable_parameters()->set_update_status(
58 pairing_api::HostStatusParameters::UPDATE_STATUS_UPDATED);
60 // TODO(zork): Get a list of other paired controllers.
61 // (http://crbug.com/405757)
64 scoped_refptr<net::IOBuffer> io_buffer(
65 ProtoDecoder::SendHostStatus(host_status, &size));
67 controller_socket_->Send(
69 base::Bind(&BluetoothHostPairingController::OnSendComplete,
70 ptr_factory_.GetWeakPtr()),
71 base::Bind(&BluetoothHostPairingController::OnSendError,
72 ptr_factory_.GetWeakPtr()));
75 void BluetoothHostPairingController::AbortWithError(
77 const std::string& message) {
78 if (controller_socket_.get()) {
79 pairing_api::Error error;
81 error.set_api_version(kPairingAPIVersion);
82 error.mutable_parameters()->set_code(PAIRING_ERROR_PAIRING_OR_ENROLLMENT);
83 error.mutable_parameters()->set_description(message);
86 scoped_refptr<net::IOBuffer> io_buffer(
87 ProtoDecoder::SendError(error, &size));
89 controller_socket_->Send(
91 base::Bind(&BluetoothHostPairingController::OnSendComplete,
92 ptr_factory_.GetWeakPtr()),
93 base::Bind(&BluetoothHostPairingController::OnSendError,
94 ptr_factory_.GetWeakPtr()));
99 void BluetoothHostPairingController::Reset() {
100 if (controller_socket_.get()) {
101 controller_socket_->Close();
102 controller_socket_ = NULL;
105 if (service_socket_.get()) {
106 service_socket_->Close();
107 service_socket_ = NULL;
109 ChangeStage(STAGE_NONE);
112 void BluetoothHostPairingController::OnGetAdapter(
113 scoped_refptr<device::BluetoothAdapter> adapter) {
114 DCHECK(thread_checker_.CalledOnValidThread());
115 DCHECK(!adapter_.get());
118 if (adapter_->IsPresent()) {
121 // Set the name once the adapter is present.
122 adapter_->AddObserver(this);
126 void BluetoothHostPairingController::SetName() {
127 // Hash the bluetooth address and take the lower 2 bytes to create a human
128 // readable device name.
129 const uint32 device_id = base::Hash(adapter_->GetAddress()) & 0xFFFF;
130 device_name_ = base::StringPrintf("%s%04X", kDeviceNamePrefix, device_id);
134 base::Bind(&BluetoothHostPairingController::OnSetName,
135 ptr_factory_.GetWeakPtr()),
136 base::Bind(&BluetoothHostPairingController::OnSetError,
137 ptr_factory_.GetWeakPtr()));
140 void BluetoothHostPairingController::OnSetName() {
141 DCHECK(thread_checker_.CalledOnValidThread());
142 if (adapter_->IsPowered()) {
145 adapter_->SetPowered(
147 base::Bind(&BluetoothHostPairingController::OnSetPowered,
148 ptr_factory_.GetWeakPtr()),
149 base::Bind(&BluetoothHostPairingController::OnSetError,
150 ptr_factory_.GetWeakPtr()));
154 void BluetoothHostPairingController::OnSetPowered() {
155 DCHECK(thread_checker_.CalledOnValidThread());
156 adapter_->AddPairingDelegate(
157 this, device::BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH);
159 device::BluetoothAdapter::ServiceOptions options;
160 options.name.reset(new std::string(kPairingServiceName));
162 adapter_->CreateRfcommService(
163 device::BluetoothUUID(kPairingServiceUUID), options,
164 base::Bind(&BluetoothHostPairingController::OnCreateService,
165 ptr_factory_.GetWeakPtr()),
166 base::Bind(&BluetoothHostPairingController::OnCreateServiceError,
167 ptr_factory_.GetWeakPtr()));
170 void BluetoothHostPairingController::OnCreateService(
171 scoped_refptr<device::BluetoothSocket> socket) {
172 DCHECK(thread_checker_.CalledOnValidThread());
173 service_socket_ = socket;
175 service_socket_->Accept(
176 base::Bind(&BluetoothHostPairingController::OnAccept,
177 ptr_factory_.GetWeakPtr()),
178 base::Bind(&BluetoothHostPairingController::OnAcceptError,
179 ptr_factory_.GetWeakPtr()));
181 adapter_->SetDiscoverable(
183 base::Bind(&BluetoothHostPairingController::OnSetDiscoverable,
184 ptr_factory_.GetWeakPtr(), true),
185 base::Bind(&BluetoothHostPairingController::OnSetError,
186 ptr_factory_.GetWeakPtr()));
189 void BluetoothHostPairingController::OnAccept(
190 const device::BluetoothDevice* device,
191 scoped_refptr<device::BluetoothSocket> socket) {
192 DCHECK(thread_checker_.CalledOnValidThread());
193 adapter_->SetDiscoverable(
195 base::Bind(&BluetoothHostPairingController::OnSetDiscoverable,
196 ptr_factory_.GetWeakPtr(), false),
197 base::Bind(&BluetoothHostPairingController::OnSetError,
198 ptr_factory_.GetWeakPtr()));
200 controller_socket_ = socket;
201 service_socket_ = NULL;
203 // TODO: Update Host. (http://crbug.com/405754)
206 controller_socket_->Receive(
208 base::Bind(&BluetoothHostPairingController::OnReceiveComplete,
209 ptr_factory_.GetWeakPtr()),
210 base::Bind(&BluetoothHostPairingController::OnReceiveError,
211 ptr_factory_.GetWeakPtr()));
213 ChangeStage(STAGE_WAITING_FOR_CREDENTIALS);
216 void BluetoothHostPairingController::OnSetDiscoverable(bool change_stage) {
217 DCHECK(thread_checker_.CalledOnValidThread());
219 DCHECK_EQ(current_stage_, STAGE_NONE);
220 ChangeStage(STAGE_WAITING_FOR_CONTROLLER);
224 void BluetoothHostPairingController::OnSendComplete(int bytes_sent) {}
226 void BluetoothHostPairingController::OnReceiveComplete(
227 int bytes, scoped_refptr<net::IOBuffer> io_buffer) {
228 DCHECK(thread_checker_.CalledOnValidThread());
229 proto_decoder_->DecodeIOBuffer(bytes, io_buffer);
231 controller_socket_->Receive(
233 base::Bind(&BluetoothHostPairingController::OnReceiveComplete,
234 ptr_factory_.GetWeakPtr()),
235 base::Bind(&BluetoothHostPairingController::OnReceiveError,
236 ptr_factory_.GetWeakPtr()));
239 void BluetoothHostPairingController::OnCreateServiceError(
240 const std::string& message) {
241 LOG(ERROR) << message;
242 ChangeStage(STAGE_INITIALIZATION_ERROR);
245 void BluetoothHostPairingController::OnSetError() {
246 adapter_->RemovePairingDelegate(this);
247 ChangeStage(STAGE_INITIALIZATION_ERROR);
250 void BluetoothHostPairingController::OnAcceptError(
251 const std::string& error_message) {
252 LOG(ERROR) << error_message;
255 void BluetoothHostPairingController::OnSendError(
256 const std::string& error_message) {
257 LOG(ERROR) << error_message;
260 void BluetoothHostPairingController::OnReceiveError(
261 device::BluetoothSocket::ErrorReason reason,
262 const std::string& error_message) {
263 LOG(ERROR) << reason << ", " << error_message;
266 void BluetoothHostPairingController::OnHostStatusMessage(
267 const pairing_api::HostStatus& message) {
271 void BluetoothHostPairingController::OnConfigureHostMessage(
272 const pairing_api::ConfigureHost& message) {
273 FOR_EACH_OBSERVER(Observer, observers_,
274 ConfigureHost(message.parameters().accepted_eula(),
275 message.parameters().lang(),
276 message.parameters().timezone(),
277 message.parameters().send_reports(),
278 message.parameters().keyboard_layout()));
281 void BluetoothHostPairingController::OnPairDevicesMessage(
282 const pairing_api::PairDevices& message) {
283 DCHECK(thread_checker_.CalledOnValidThread());
284 if (current_stage_ != STAGE_WAITING_FOR_CREDENTIALS) {
285 AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT, kErrorInvalidProtocol);
289 ChangeStage(STAGE_ENROLLING);
290 FOR_EACH_OBSERVER(Observer, observers_,
291 EnrollHost(message.parameters().admin_access_token()));
294 void BluetoothHostPairingController::SetEnrollmentComplete(bool success) {
295 DCHECK_EQ(current_stage_, STAGE_ENROLLING);
296 DCHECK(thread_checker_.CalledOnValidThread());
298 ChangeStage(STAGE_PAIRING_DONE);
301 AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT, kErrorEnrollmentFailed);
305 void BluetoothHostPairingController::OnCompleteSetupMessage(
306 const pairing_api::CompleteSetup& message) {
307 DCHECK(thread_checker_.CalledOnValidThread());
308 if (current_stage_ != STAGE_PAIRING_DONE) {
309 AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT, kErrorInvalidProtocol);
313 // TODO(zork): Handle adding another controller. (http://crbug.com/405757)
314 ChangeStage(STAGE_FINISHED);
317 void BluetoothHostPairingController::OnErrorMessage(
318 const pairing_api::Error& message) {
322 void BluetoothHostPairingController::AdapterPresentChanged(
323 device::BluetoothAdapter* adapter,
325 DCHECK_EQ(adapter, adapter_.get());
327 adapter_->RemoveObserver(this);
332 void BluetoothHostPairingController::AddObserver(Observer* observer) {
333 observers_.AddObserver(observer);
336 void BluetoothHostPairingController::RemoveObserver(Observer* observer) {
337 observers_.RemoveObserver(observer);
340 HostPairingController::Stage BluetoothHostPairingController::GetCurrentStage() {
341 return current_stage_;
344 void BluetoothHostPairingController::StartPairing() {
345 DCHECK_EQ(current_stage_, STAGE_NONE);
346 bool bluetooth_available =
347 device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable();
348 if (!bluetooth_available) {
349 ChangeStage(STAGE_INITIALIZATION_ERROR);
353 device::BluetoothAdapterFactory::GetAdapter(
354 base::Bind(&BluetoothHostPairingController::OnGetAdapter,
355 ptr_factory_.GetWeakPtr()));
358 std::string BluetoothHostPairingController::GetDeviceName() {
362 std::string BluetoothHostPairingController::GetConfirmationCode() {
363 DCHECK_EQ(current_stage_, STAGE_WAITING_FOR_CODE_CONFIRMATION);
364 return confirmation_code_;
367 std::string BluetoothHostPairingController::GetEnrollmentDomain() {
368 return enrollment_domain_;
371 void BluetoothHostPairingController::OnUpdateStatusChanged(
372 UpdateStatus update_status) {
373 // TODO(zork): Handling updating stages (http://crbug.com/405754).
376 void BluetoothHostPairingController::RequestPinCode(
377 device::BluetoothDevice* device) {
378 // Disallow unknown device.
379 device->RejectPairing();
382 void BluetoothHostPairingController::RequestPasskey(
383 device::BluetoothDevice* device) {
384 // Disallow unknown device.
385 device->RejectPairing();
388 void BluetoothHostPairingController::DisplayPinCode(
389 device::BluetoothDevice* device,
390 const std::string& pincode) {
391 // Disallow unknown device.
392 device->RejectPairing();
395 void BluetoothHostPairingController::DisplayPasskey(
396 device::BluetoothDevice* device,
398 // Disallow unknown device.
399 device->RejectPairing();
402 void BluetoothHostPairingController::KeysEntered(
403 device::BluetoothDevice* device,
405 // Disallow unknown device.
406 device->RejectPairing();
409 void BluetoothHostPairingController::ConfirmPasskey(
410 device::BluetoothDevice* device,
412 confirmation_code_ = base::StringPrintf("%06d", passkey);
413 device->ConfirmPairing();
414 ChangeStage(STAGE_WAITING_FOR_CODE_CONFIRMATION);
417 void BluetoothHostPairingController::AuthorizePairing(
418 device::BluetoothDevice* device) {
419 // Disallow unknown device.
420 device->RejectPairing();
423 } // namespace pairing_chromeos