Roll libvpx 861f35:1fff3e
[chromium-blink-merge.git] / components / pairing / bluetooth_host_pairing_controller.cc
blob5ffd2f58c209080f52af73a94e97956fd6328df7
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 if (adapter_.get()) {
68 if (adapter_->IsDiscoverable()) {
69 adapter_->SetDiscoverable(false, base::Closure(), base::Closure());
71 adapter_->RemoveObserver(this);
72 adapter_ = NULL;
76 void BluetoothHostPairingController::ChangeStage(Stage new_stage) {
77 if (current_stage_ == new_stage)
78 return;
79 VLOG(1) << "ChangeStage " << new_stage;
80 current_stage_ = new_stage;
81 FOR_EACH_OBSERVER(Observer, observers_, PairingStageChanged(new_stage));
84 void BluetoothHostPairingController::SendHostStatus() {
85 pairing_api::HostStatus host_status;
87 host_status.set_api_version(kPairingAPIVersion);
88 if (!enrollment_domain_.empty())
89 host_status.mutable_parameters()->set_domain(enrollment_domain_);
91 // TODO(zork): Get these values from the UI. (http://crbug.com/405744)
92 host_status.mutable_parameters()->set_connectivity(
93 pairing_api::HostStatusParameters::CONNECTIVITY_CONNECTED);
94 host_status.mutable_parameters()->set_update_status(
95 PairingApiUpdateStatus(update_status_));
96 host_status.mutable_parameters()->set_enrollment_status(
97 PairingApiEnrollmentStatus(enrollment_status_));
99 // TODO(zork): Get a list of other paired controllers.
100 // (http://crbug.com/405757)
102 int size = 0;
103 scoped_refptr<net::IOBuffer> io_buffer(
104 ProtoDecoder::SendHostStatus(host_status, &size));
106 controller_socket_->Send(
107 io_buffer, size,
108 base::Bind(&BluetoothHostPairingController::OnSendComplete,
109 ptr_factory_.GetWeakPtr()),
110 base::Bind(&BluetoothHostPairingController::OnSendError,
111 ptr_factory_.GetWeakPtr()));
114 void BluetoothHostPairingController::AbortWithError(
115 int code,
116 const std::string& message) {
117 if (controller_socket_.get()) {
118 pairing_api::Error error;
120 error.set_api_version(kPairingAPIVersion);
121 error.mutable_parameters()->set_code(PAIRING_ERROR_PAIRING_OR_ENROLLMENT);
122 error.mutable_parameters()->set_description(message);
124 int size = 0;
125 scoped_refptr<net::IOBuffer> io_buffer(
126 ProtoDecoder::SendError(error, &size));
128 controller_socket_->Send(
129 io_buffer, size,
130 base::Bind(&BluetoothHostPairingController::OnSendComplete,
131 ptr_factory_.GetWeakPtr()),
132 base::Bind(&BluetoothHostPairingController::OnSendError,
133 ptr_factory_.GetWeakPtr()));
135 Reset();
138 void BluetoothHostPairingController::Reset() {
139 if (controller_socket_.get()) {
140 controller_socket_->Close();
141 controller_socket_ = NULL;
144 if (service_socket_.get()) {
145 service_socket_->Close();
146 service_socket_ = NULL;
148 ChangeStage(STAGE_NONE);
151 void BluetoothHostPairingController::OnGetAdapter(
152 scoped_refptr<device::BluetoothAdapter> adapter) {
153 DCHECK(thread_checker_.CalledOnValidThread());
154 DCHECK(!adapter_.get());
155 adapter_ = adapter;
157 if (adapter_->IsPresent()) {
158 SetName();
159 } else {
160 // Set the name once the adapter is present.
161 adapter_->AddObserver(this);
165 void BluetoothHostPairingController::SetName() {
166 // Hash the bluetooth address and take the lower 2 bytes to create a human
167 // readable device name.
168 const uint32 device_id = base::Hash(adapter_->GetAddress()) & 0xFFFF;
169 device_name_ = base::StringPrintf("%s%04X", kDeviceNamePrefix, device_id);
171 adapter_->SetName(
172 device_name_,
173 base::Bind(&BluetoothHostPairingController::OnSetName,
174 ptr_factory_.GetWeakPtr()),
175 base::Bind(&BluetoothHostPairingController::OnSetError,
176 ptr_factory_.GetWeakPtr()));
179 void BluetoothHostPairingController::OnSetName() {
180 DCHECK(thread_checker_.CalledOnValidThread());
181 if (adapter_->IsPowered()) {
182 OnSetPowered();
183 } else {
184 adapter_->SetPowered(
185 true,
186 base::Bind(&BluetoothHostPairingController::OnSetPowered,
187 ptr_factory_.GetWeakPtr()),
188 base::Bind(&BluetoothHostPairingController::OnSetError,
189 ptr_factory_.GetWeakPtr()));
193 void BluetoothHostPairingController::OnSetPowered() {
194 DCHECK(thread_checker_.CalledOnValidThread());
195 adapter_->AddPairingDelegate(
196 this, device::BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH);
198 device::BluetoothAdapter::ServiceOptions options;
199 options.name.reset(new std::string(kPairingServiceName));
201 adapter_->CreateRfcommService(
202 device::BluetoothUUID(kPairingServiceUUID), options,
203 base::Bind(&BluetoothHostPairingController::OnCreateService,
204 ptr_factory_.GetWeakPtr()),
205 base::Bind(&BluetoothHostPairingController::OnCreateServiceError,
206 ptr_factory_.GetWeakPtr()));
209 void BluetoothHostPairingController::OnCreateService(
210 scoped_refptr<device::BluetoothSocket> socket) {
211 DCHECK(thread_checker_.CalledOnValidThread());
212 service_socket_ = socket;
214 service_socket_->Accept(
215 base::Bind(&BluetoothHostPairingController::OnAccept,
216 ptr_factory_.GetWeakPtr()),
217 base::Bind(&BluetoothHostPairingController::OnAcceptError,
218 ptr_factory_.GetWeakPtr()));
220 adapter_->SetDiscoverable(
221 true,
222 base::Bind(&BluetoothHostPairingController::OnSetDiscoverable,
223 ptr_factory_.GetWeakPtr(), true),
224 base::Bind(&BluetoothHostPairingController::OnSetError,
225 ptr_factory_.GetWeakPtr()));
228 void BluetoothHostPairingController::OnAccept(
229 const device::BluetoothDevice* device,
230 scoped_refptr<device::BluetoothSocket> socket) {
231 DCHECK(thread_checker_.CalledOnValidThread());
232 adapter_->SetDiscoverable(
233 false,
234 base::Bind(&BluetoothHostPairingController::OnSetDiscoverable,
235 ptr_factory_.GetWeakPtr(), false),
236 base::Bind(&BluetoothHostPairingController::OnSetError,
237 ptr_factory_.GetWeakPtr()));
239 controller_socket_ = socket;
240 service_socket_ = NULL;
242 SendHostStatus();
244 controller_socket_->Receive(
245 kReceiveSize,
246 base::Bind(&BluetoothHostPairingController::OnReceiveComplete,
247 ptr_factory_.GetWeakPtr()),
248 base::Bind(&BluetoothHostPairingController::OnReceiveError,
249 ptr_factory_.GetWeakPtr()));
252 void BluetoothHostPairingController::OnSetDiscoverable(bool change_stage) {
253 DCHECK(thread_checker_.CalledOnValidThread());
254 if (change_stage) {
255 DCHECK_EQ(current_stage_, STAGE_NONE);
256 ChangeStage(STAGE_WAITING_FOR_CONTROLLER);
260 void BluetoothHostPairingController::OnSendComplete(int bytes_sent) {}
262 void BluetoothHostPairingController::OnReceiveComplete(
263 int bytes, scoped_refptr<net::IOBuffer> io_buffer) {
264 DCHECK(thread_checker_.CalledOnValidThread());
265 proto_decoder_->DecodeIOBuffer(bytes, io_buffer);
267 controller_socket_->Receive(
268 kReceiveSize,
269 base::Bind(&BluetoothHostPairingController::OnReceiveComplete,
270 ptr_factory_.GetWeakPtr()),
271 base::Bind(&BluetoothHostPairingController::OnReceiveError,
272 ptr_factory_.GetWeakPtr()));
275 void BluetoothHostPairingController::OnCreateServiceError(
276 const std::string& message) {
277 LOG(ERROR) << message;
278 ChangeStage(STAGE_INITIALIZATION_ERROR);
281 void BluetoothHostPairingController::OnSetError() {
282 adapter_->RemovePairingDelegate(this);
283 ChangeStage(STAGE_INITIALIZATION_ERROR);
286 void BluetoothHostPairingController::OnAcceptError(
287 const std::string& error_message) {
288 LOG(ERROR) << error_message;
291 void BluetoothHostPairingController::OnSendError(
292 const std::string& error_message) {
293 LOG(ERROR) << error_message;
296 void BluetoothHostPairingController::OnReceiveError(
297 device::BluetoothSocket::ErrorReason reason,
298 const std::string& error_message) {
299 LOG(ERROR) << reason << ", " << error_message;
302 void BluetoothHostPairingController::OnHostStatusMessage(
303 const pairing_api::HostStatus& message) {
304 NOTREACHED();
307 void BluetoothHostPairingController::OnConfigureHostMessage(
308 const pairing_api::ConfigureHost& message) {
309 FOR_EACH_OBSERVER(Observer, observers_,
310 ConfigureHost(message.parameters().accepted_eula(),
311 message.parameters().lang(),
312 message.parameters().timezone(),
313 message.parameters().send_reports(),
314 message.parameters().keyboard_layout()));
317 void BluetoothHostPairingController::OnPairDevicesMessage(
318 const pairing_api::PairDevices& message) {
319 DCHECK(thread_checker_.CalledOnValidThread());
320 ChangeStage(STAGE_ENROLLING);
321 FOR_EACH_OBSERVER(Observer, observers_,
322 EnrollHost(message.parameters().admin_access_token()));
325 void BluetoothHostPairingController::OnCompleteSetupMessage(
326 const pairing_api::CompleteSetup& message) {
327 DCHECK(thread_checker_.CalledOnValidThread());
328 if (current_stage_ != STAGE_ENROLLMENT_SUCCESS) {
329 AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT, kErrorInvalidProtocol);
330 return;
333 // TODO(zork): Handle adding another controller. (http://crbug.com/405757)
334 ChangeStage(STAGE_FINISHED);
337 void BluetoothHostPairingController::OnErrorMessage(
338 const pairing_api::Error& message) {
339 NOTREACHED();
342 void BluetoothHostPairingController::AdapterPresentChanged(
343 device::BluetoothAdapter* adapter,
344 bool present) {
345 DCHECK_EQ(adapter, adapter_.get());
346 if (present) {
347 adapter_->RemoveObserver(this);
348 SetName();
352 void BluetoothHostPairingController::AddObserver(Observer* observer) {
353 observers_.AddObserver(observer);
356 void BluetoothHostPairingController::RemoveObserver(Observer* observer) {
357 observers_.RemoveObserver(observer);
360 HostPairingController::Stage BluetoothHostPairingController::GetCurrentStage() {
361 return current_stage_;
364 void BluetoothHostPairingController::StartPairing() {
365 DCHECK_EQ(current_stage_, STAGE_NONE);
366 bool bluetooth_available =
367 device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable();
368 if (!bluetooth_available) {
369 ChangeStage(STAGE_INITIALIZATION_ERROR);
370 return;
373 device::BluetoothAdapterFactory::GetAdapter(
374 base::Bind(&BluetoothHostPairingController::OnGetAdapter,
375 ptr_factory_.GetWeakPtr()));
378 std::string BluetoothHostPairingController::GetDeviceName() {
379 return device_name_;
382 std::string BluetoothHostPairingController::GetConfirmationCode() {
383 DCHECK_EQ(current_stage_, STAGE_WAITING_FOR_CODE_CONFIRMATION);
384 return confirmation_code_;
387 std::string BluetoothHostPairingController::GetEnrollmentDomain() {
388 return enrollment_domain_;
391 void BluetoothHostPairingController::OnUpdateStatusChanged(
392 UpdateStatus update_status) {
393 update_status_ = update_status;
394 if (update_status == UPDATE_STATUS_UPDATED)
395 ChangeStage(STAGE_WAITING_FOR_CREDENTIALS);
396 SendHostStatus();
399 void BluetoothHostPairingController::OnEnrollmentStatusChanged(
400 EnrollmentStatus enrollment_status) {
401 DCHECK_EQ(current_stage_, STAGE_ENROLLING);
402 DCHECK(thread_checker_.CalledOnValidThread());
404 enrollment_status_ = enrollment_status;
405 if (enrollment_status == ENROLLMENT_STATUS_SUCCESS) {
406 ChangeStage(STAGE_ENROLLMENT_SUCCESS);
407 } else if (enrollment_status == ENROLLMENT_STATUS_FAILURE) {
408 AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT,
409 kErrorEnrollmentFailed);
411 SendHostStatus();
414 void BluetoothHostPairingController::RequestPinCode(
415 device::BluetoothDevice* device) {
416 // Disallow unknown device.
417 device->RejectPairing();
420 void BluetoothHostPairingController::RequestPasskey(
421 device::BluetoothDevice* device) {
422 // Disallow unknown device.
423 device->RejectPairing();
426 void BluetoothHostPairingController::DisplayPinCode(
427 device::BluetoothDevice* device,
428 const std::string& pincode) {
429 // Disallow unknown device.
430 device->RejectPairing();
433 void BluetoothHostPairingController::DisplayPasskey(
434 device::BluetoothDevice* device,
435 uint32 passkey) {
436 // Disallow unknown device.
437 device->RejectPairing();
440 void BluetoothHostPairingController::KeysEntered(
441 device::BluetoothDevice* device,
442 uint32 entered) {
443 // Disallow unknown device.
444 device->RejectPairing();
447 void BluetoothHostPairingController::ConfirmPasskey(
448 device::BluetoothDevice* device,
449 uint32 passkey) {
450 // If a new connection is occurring, reset the stage. This can occur if the
451 // pairing times out, or a new controller connects.
452 if (current_stage_ == STAGE_WAITING_FOR_CODE_CONFIRMATION)
453 ChangeStage(STAGE_WAITING_FOR_CONTROLLER);
455 confirmation_code_ = base::StringPrintf("%06d", passkey);
456 device->ConfirmPairing();
457 ChangeStage(STAGE_WAITING_FOR_CODE_CONFIRMATION);
460 void BluetoothHostPairingController::AuthorizePairing(
461 device::BluetoothDevice* device) {
462 // Disallow unknown device.
463 device->RejectPairing();
466 } // namespace pairing_chromeos