Roll src/third_party/WebKit f298044:aa8346d (svn 202628:202629)
[chromium-blink-merge.git] / components / pairing / bluetooth_host_pairing_controller.cc
blobc1573707c4fb575311dba600879372ca4a07d457
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"
7 #include "base/bind.h"
8 #include "base/hash.h"
9 #include "base/logging.h"
10 #include "base/strings/stringprintf.h"
11 #include "components/pairing/bluetooth_pairing_constants.h"
12 #include "components/pairing/pairing_api.pb.h"
13 #include "components/pairing/proto_decoder.h"
14 #include "device/bluetooth/bluetooth_adapter_factory.h"
15 #include "net/base/io_buffer.h"
17 namespace pairing_chromeos {
19 namespace {
20 const int kReceiveSize = 16384;
22 pairing_api::HostStatusParameters::UpdateStatus PairingApiUpdateStatus(
23 HostPairingController::UpdateStatus update_status) {
24 switch(update_status) {
25 case HostPairingController::UPDATE_STATUS_UNKNOWN:
26 return pairing_api::HostStatusParameters::UPDATE_STATUS_UNKNOWN;
27 case HostPairingController::UPDATE_STATUS_UPDATING:
28 return pairing_api::HostStatusParameters::UPDATE_STATUS_UPDATING;
29 case HostPairingController::UPDATE_STATUS_REBOOTING:
30 return pairing_api::HostStatusParameters::UPDATE_STATUS_REBOOTING;
31 case HostPairingController::UPDATE_STATUS_UPDATED:
32 return pairing_api::HostStatusParameters::UPDATE_STATUS_UPDATED;
33 default:
34 NOTREACHED();
35 return pairing_api::HostStatusParameters::UPDATE_STATUS_UNKNOWN;
39 pairing_api::HostStatusParameters::EnrollmentStatus PairingApiEnrollmentStatus(
40 HostPairingController::EnrollmentStatus enrollment_status) {
41 switch(enrollment_status) {
42 case HostPairingController::ENROLLMENT_STATUS_UNKNOWN:
43 return pairing_api::HostStatusParameters::ENROLLMENT_STATUS_UNKNOWN;
44 case HostPairingController::ENROLLMENT_STATUS_ENROLLING:
45 return pairing_api::HostStatusParameters::ENROLLMENT_STATUS_ENROLLING;
46 case HostPairingController::ENROLLMENT_STATUS_FAILURE:
47 return pairing_api::HostStatusParameters::ENROLLMENT_STATUS_FAILURE;
48 case HostPairingController::ENROLLMENT_STATUS_SUCCESS:
49 return pairing_api::HostStatusParameters::ENROLLMENT_STATUS_SUCCESS;
50 default:
51 NOTREACHED();
52 return pairing_api::HostStatusParameters::ENROLLMENT_STATUS_UNKNOWN;
56 } // namespace
58 BluetoothHostPairingController::BluetoothHostPairingController()
59 : current_stage_(STAGE_NONE),
60 update_status_(UPDATE_STATUS_UNKNOWN),
61 enrollment_status_(ENROLLMENT_STATUS_UNKNOWN),
62 proto_decoder_(new ProtoDecoder(this)),
63 ptr_factory_(this) {
66 BluetoothHostPairingController::~BluetoothHostPairingController() {
67 Reset();
68 if (adapter_.get()) {
69 if (adapter_->IsDiscoverable()) {
70 adapter_->SetDiscoverable(false, base::Closure(), base::Closure());
72 adapter_->RemoveObserver(this);
73 adapter_ = NULL;
77 void BluetoothHostPairingController::ChangeStage(Stage new_stage) {
78 if (current_stage_ == new_stage)
79 return;
80 VLOG(1) << "ChangeStage " << new_stage;
81 current_stage_ = new_stage;
82 FOR_EACH_OBSERVER(Observer, observers_, PairingStageChanged(new_stage));
85 void BluetoothHostPairingController::SendHostStatus() {
86 pairing_api::HostStatus host_status;
88 host_status.set_api_version(kPairingAPIVersion);
89 if (!enrollment_domain_.empty())
90 host_status.mutable_parameters()->set_domain(enrollment_domain_);
91 if (!permanent_id_.empty())
92 host_status.mutable_parameters()->set_permanent_id(permanent_id_);
94 // TODO(zork): Get these values from the UI. (http://crbug.com/405744)
95 host_status.mutable_parameters()->set_connectivity(
96 pairing_api::HostStatusParameters::CONNECTIVITY_CONNECTED);
97 host_status.mutable_parameters()->set_update_status(
98 PairingApiUpdateStatus(update_status_));
99 host_status.mutable_parameters()->set_enrollment_status(
100 PairingApiEnrollmentStatus(enrollment_status_));
102 // TODO(zork): Get a list of other paired controllers.
103 // (http://crbug.com/405757)
105 int size = 0;
106 scoped_refptr<net::IOBuffer> io_buffer(
107 ProtoDecoder::SendHostStatus(host_status, &size));
109 controller_socket_->Send(
110 io_buffer, size,
111 base::Bind(&BluetoothHostPairingController::OnSendComplete,
112 ptr_factory_.GetWeakPtr()),
113 base::Bind(&BluetoothHostPairingController::OnSendError,
114 ptr_factory_.GetWeakPtr()));
117 void BluetoothHostPairingController::AbortWithError(
118 int code,
119 const std::string& message) {
120 if (controller_socket_.get()) {
121 pairing_api::Error error;
123 error.set_api_version(kPairingAPIVersion);
124 error.mutable_parameters()->set_code(PAIRING_ERROR_PAIRING_OR_ENROLLMENT);
125 error.mutable_parameters()->set_description(message);
127 int size = 0;
128 scoped_refptr<net::IOBuffer> io_buffer(
129 ProtoDecoder::SendError(error, &size));
131 controller_socket_->Send(
132 io_buffer, size,
133 base::Bind(&BluetoothHostPairingController::OnSendComplete,
134 ptr_factory_.GetWeakPtr()),
135 base::Bind(&BluetoothHostPairingController::OnSendError,
136 ptr_factory_.GetWeakPtr()));
138 Reset();
141 void BluetoothHostPairingController::Reset() {
142 if (controller_socket_.get()) {
143 controller_socket_->Close();
144 controller_socket_ = NULL;
147 if (service_socket_.get()) {
148 service_socket_->Close();
149 service_socket_ = NULL;
151 ChangeStage(STAGE_NONE);
154 void BluetoothHostPairingController::OnGetAdapter(
155 scoped_refptr<device::BluetoothAdapter> adapter) {
156 DCHECK(thread_checker_.CalledOnValidThread());
157 DCHECK(!adapter_.get());
158 adapter_ = adapter;
160 if (adapter_->IsPresent()) {
161 SetName();
162 } else {
163 // Set the name once the adapter is present.
164 adapter_->AddObserver(this);
168 void BluetoothHostPairingController::SetName() {
169 // Hash the bluetooth address and take the lower 2 bytes to create a human
170 // readable device name.
171 const uint32 device_id = base::Hash(adapter_->GetAddress()) & 0xFFFF;
172 device_name_ = base::StringPrintf("%s%04X", kDeviceNamePrefix, device_id);
174 adapter_->SetName(
175 device_name_,
176 base::Bind(&BluetoothHostPairingController::OnSetName,
177 ptr_factory_.GetWeakPtr()),
178 base::Bind(&BluetoothHostPairingController::OnSetError,
179 ptr_factory_.GetWeakPtr()));
182 void BluetoothHostPairingController::OnSetName() {
183 DCHECK(thread_checker_.CalledOnValidThread());
184 if (adapter_->IsPowered()) {
185 OnSetPowered();
186 } else {
187 adapter_->SetPowered(
188 true,
189 base::Bind(&BluetoothHostPairingController::OnSetPowered,
190 ptr_factory_.GetWeakPtr()),
191 base::Bind(&BluetoothHostPairingController::OnSetError,
192 ptr_factory_.GetWeakPtr()));
196 void BluetoothHostPairingController::OnSetPowered() {
197 DCHECK(thread_checker_.CalledOnValidThread());
198 adapter_->AddPairingDelegate(
199 this, device::BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH);
201 device::BluetoothAdapter::ServiceOptions options;
202 options.name.reset(new std::string(kPairingServiceName));
204 adapter_->CreateRfcommService(
205 device::BluetoothUUID(kPairingServiceUUID), options,
206 base::Bind(&BluetoothHostPairingController::OnCreateService,
207 ptr_factory_.GetWeakPtr()),
208 base::Bind(&BluetoothHostPairingController::OnCreateServiceError,
209 ptr_factory_.GetWeakPtr()));
212 void BluetoothHostPairingController::OnCreateService(
213 scoped_refptr<device::BluetoothSocket> socket) {
214 DCHECK(thread_checker_.CalledOnValidThread());
215 service_socket_ = socket;
217 service_socket_->Accept(
218 base::Bind(&BluetoothHostPairingController::OnAccept,
219 ptr_factory_.GetWeakPtr()),
220 base::Bind(&BluetoothHostPairingController::OnAcceptError,
221 ptr_factory_.GetWeakPtr()));
223 adapter_->SetDiscoverable(
224 true,
225 base::Bind(&BluetoothHostPairingController::OnSetDiscoverable,
226 ptr_factory_.GetWeakPtr(), true),
227 base::Bind(&BluetoothHostPairingController::OnSetError,
228 ptr_factory_.GetWeakPtr()));
231 void BluetoothHostPairingController::OnAccept(
232 const device::BluetoothDevice* device,
233 scoped_refptr<device::BluetoothSocket> socket) {
234 DCHECK(thread_checker_.CalledOnValidThread());
235 adapter_->SetDiscoverable(
236 false,
237 base::Bind(&BluetoothHostPairingController::OnSetDiscoverable,
238 ptr_factory_.GetWeakPtr(), false),
239 base::Bind(&BluetoothHostPairingController::OnSetError,
240 ptr_factory_.GetWeakPtr()));
242 controller_socket_ = socket;
243 service_socket_ = NULL;
245 SendHostStatus();
247 controller_socket_->Receive(
248 kReceiveSize,
249 base::Bind(&BluetoothHostPairingController::OnReceiveComplete,
250 ptr_factory_.GetWeakPtr()),
251 base::Bind(&BluetoothHostPairingController::OnReceiveError,
252 ptr_factory_.GetWeakPtr()));
255 void BluetoothHostPairingController::OnSetDiscoverable(bool change_stage) {
256 DCHECK(thread_checker_.CalledOnValidThread());
257 if (change_stage) {
258 DCHECK_EQ(current_stage_, STAGE_NONE);
259 ChangeStage(STAGE_WAITING_FOR_CONTROLLER);
263 void BluetoothHostPairingController::OnSendComplete(int bytes_sent) {}
265 void BluetoothHostPairingController::OnReceiveComplete(
266 int bytes, scoped_refptr<net::IOBuffer> io_buffer) {
267 DCHECK(thread_checker_.CalledOnValidThread());
268 proto_decoder_->DecodeIOBuffer(bytes, io_buffer);
270 controller_socket_->Receive(
271 kReceiveSize,
272 base::Bind(&BluetoothHostPairingController::OnReceiveComplete,
273 ptr_factory_.GetWeakPtr()),
274 base::Bind(&BluetoothHostPairingController::OnReceiveError,
275 ptr_factory_.GetWeakPtr()));
278 void BluetoothHostPairingController::OnCreateServiceError(
279 const std::string& message) {
280 LOG(ERROR) << message;
281 ChangeStage(STAGE_INITIALIZATION_ERROR);
284 void BluetoothHostPairingController::OnSetError() {
285 adapter_->RemovePairingDelegate(this);
286 ChangeStage(STAGE_INITIALIZATION_ERROR);
289 void BluetoothHostPairingController::OnAcceptError(
290 const std::string& error_message) {
291 LOG(ERROR) << error_message;
294 void BluetoothHostPairingController::OnSendError(
295 const std::string& error_message) {
296 LOG(ERROR) << error_message;
299 void BluetoothHostPairingController::OnReceiveError(
300 device::BluetoothSocket::ErrorReason reason,
301 const std::string& error_message) {
302 LOG(ERROR) << reason << ", " << error_message;
305 void BluetoothHostPairingController::OnHostStatusMessage(
306 const pairing_api::HostStatus& message) {
307 NOTREACHED();
310 void BluetoothHostPairingController::OnConfigureHostMessage(
311 const pairing_api::ConfigureHost& message) {
312 FOR_EACH_OBSERVER(Observer, observers_,
313 ConfigureHostRequested(
314 message.parameters().accepted_eula(),
315 message.parameters().lang(),
316 message.parameters().timezone(),
317 message.parameters().send_reports(),
318 message.parameters().keyboard_layout()));
321 void BluetoothHostPairingController::OnPairDevicesMessage(
322 const pairing_api::PairDevices& message) {
323 DCHECK(thread_checker_.CalledOnValidThread());
324 ChangeStage(STAGE_ENROLLING);
325 FOR_EACH_OBSERVER(Observer, observers_,
326 EnrollHostRequested(
327 message.parameters().admin_access_token()));
330 void BluetoothHostPairingController::OnCompleteSetupMessage(
331 const pairing_api::CompleteSetup& message) {
332 DCHECK(thread_checker_.CalledOnValidThread());
333 if (current_stage_ != STAGE_ENROLLMENT_SUCCESS) {
334 AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT, kErrorInvalidProtocol);
335 return;
338 // TODO(zork): Handle adding another controller. (http://crbug.com/405757)
339 ChangeStage(STAGE_FINISHED);
342 void BluetoothHostPairingController::OnErrorMessage(
343 const pairing_api::Error& message) {
344 NOTREACHED();
347 void BluetoothHostPairingController::OnAddNetworkMessage(
348 const pairing_api::AddNetwork& message) {
349 DCHECK(thread_checker_.CalledOnValidThread());
350 FOR_EACH_OBSERVER(Observer, observers_,
351 AddNetworkRequested(message.parameters().onc_spec()));
354 void BluetoothHostPairingController::AdapterPresentChanged(
355 device::BluetoothAdapter* adapter,
356 bool present) {
357 DCHECK_EQ(adapter, adapter_.get());
358 if (present) {
359 adapter_->RemoveObserver(this);
360 SetName();
364 void BluetoothHostPairingController::AddObserver(Observer* observer) {
365 observers_.AddObserver(observer);
368 void BluetoothHostPairingController::RemoveObserver(Observer* observer) {
369 observers_.RemoveObserver(observer);
372 HostPairingController::Stage BluetoothHostPairingController::GetCurrentStage() {
373 return current_stage_;
376 void BluetoothHostPairingController::StartPairing() {
377 DCHECK_EQ(current_stage_, STAGE_NONE);
378 bool bluetooth_available =
379 device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable();
380 if (!bluetooth_available) {
381 ChangeStage(STAGE_INITIALIZATION_ERROR);
382 return;
385 device::BluetoothAdapterFactory::GetAdapter(
386 base::Bind(&BluetoothHostPairingController::OnGetAdapter,
387 ptr_factory_.GetWeakPtr()));
390 std::string BluetoothHostPairingController::GetDeviceName() {
391 return device_name_;
394 std::string BluetoothHostPairingController::GetConfirmationCode() {
395 DCHECK_EQ(current_stage_, STAGE_WAITING_FOR_CODE_CONFIRMATION);
396 return confirmation_code_;
399 std::string BluetoothHostPairingController::GetEnrollmentDomain() {
400 return enrollment_domain_;
403 void BluetoothHostPairingController::OnUpdateStatusChanged(
404 UpdateStatus update_status) {
405 update_status_ = update_status;
406 if (update_status == UPDATE_STATUS_UPDATED)
407 ChangeStage(STAGE_WAITING_FOR_CREDENTIALS);
408 SendHostStatus();
411 void BluetoothHostPairingController::OnEnrollmentStatusChanged(
412 EnrollmentStatus enrollment_status) {
413 DCHECK_EQ(current_stage_, STAGE_ENROLLING);
414 DCHECK(thread_checker_.CalledOnValidThread());
416 enrollment_status_ = enrollment_status;
417 if (enrollment_status == ENROLLMENT_STATUS_SUCCESS) {
418 ChangeStage(STAGE_ENROLLMENT_SUCCESS);
419 } else if (enrollment_status == ENROLLMENT_STATUS_FAILURE) {
420 AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT,
421 kErrorEnrollmentFailed);
423 SendHostStatus();
426 void BluetoothHostPairingController::SetPermanentId(
427 const std::string& permanent_id) {
428 permanent_id_ = permanent_id;
431 void BluetoothHostPairingController::RequestPinCode(
432 device::BluetoothDevice* device) {
433 // Disallow unknown device.
434 device->RejectPairing();
437 void BluetoothHostPairingController::RequestPasskey(
438 device::BluetoothDevice* device) {
439 // Disallow unknown device.
440 device->RejectPairing();
443 void BluetoothHostPairingController::DisplayPinCode(
444 device::BluetoothDevice* device,
445 const std::string& pincode) {
446 // Disallow unknown device.
447 device->RejectPairing();
450 void BluetoothHostPairingController::DisplayPasskey(
451 device::BluetoothDevice* device,
452 uint32 passkey) {
453 // Disallow unknown device.
454 device->RejectPairing();
457 void BluetoothHostPairingController::KeysEntered(
458 device::BluetoothDevice* device,
459 uint32 entered) {
460 // Disallow unknown device.
461 device->RejectPairing();
464 void BluetoothHostPairingController::ConfirmPasskey(
465 device::BluetoothDevice* device,
466 uint32 passkey) {
467 // If a new connection is occurring, reset the stage. This can occur if the
468 // pairing times out, or a new controller connects.
469 if (current_stage_ == STAGE_WAITING_FOR_CODE_CONFIRMATION)
470 ChangeStage(STAGE_WAITING_FOR_CONTROLLER);
472 confirmation_code_ = base::StringPrintf("%06d", passkey);
473 device->ConfirmPairing();
474 ChangeStage(STAGE_WAITING_FOR_CODE_CONFIRMATION);
477 void BluetoothHostPairingController::AuthorizePairing(
478 device::BluetoothDevice* device) {
479 // Disallow unknown device.
480 device->RejectPairing();
483 } // namespace pairing_chromeos