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 adapter_
->RemoveObserver(this);
35 void BluetoothHostPairingController::ChangeStage(Stage new_stage
) {
36 if (current_stage_
== new_stage
)
38 current_stage_
= new_stage
;
39 FOR_EACH_OBSERVER(Observer
, observers_
, PairingStageChanged(new_stage
));
42 void BluetoothHostPairingController::SendHostStatus() {
43 pairing_api::HostStatus host_status
;
45 host_status
.set_api_version(kPairingAPIVersion
);
46 if (!enrollment_domain_
.empty())
47 host_status
.mutable_parameters()->set_domain(enrollment_domain_
);
49 // TODO(zork): Get these values from the UI. (http://crbug.com/405744)
50 host_status
.mutable_parameters()->set_connectivity(
51 pairing_api::HostStatusParameters::CONNECTIVITY_CONNECTED
);
52 host_status
.mutable_parameters()->set_update_status(
53 pairing_api::HostStatusParameters::UPDATE_STATUS_UPDATED
);
55 // TODO(zork): Get a list of other paired controllers.
56 // (http://crbug.com/405757)
59 scoped_refptr
<net::IOBuffer
> io_buffer(
60 ProtoDecoder::SendHostStatus(host_status
, &size
));
62 controller_socket_
->Send(
64 base::Bind(&BluetoothHostPairingController::OnSendComplete
,
65 ptr_factory_
.GetWeakPtr()),
66 base::Bind(&BluetoothHostPairingController::OnSendError
,
67 ptr_factory_
.GetWeakPtr()));
70 void BluetoothHostPairingController::AbortWithError(
72 const std::string
& message
) {
73 if (controller_socket_
.get()) {
74 pairing_api::Error error
;
76 error
.set_api_version(kPairingAPIVersion
);
77 error
.mutable_parameters()->set_code(PAIRING_ERROR_PAIRING_OR_ENROLLMENT
);
78 error
.mutable_parameters()->set_description(message
);
81 scoped_refptr
<net::IOBuffer
> io_buffer(
82 ProtoDecoder::SendError(error
, &size
));
84 controller_socket_
->Send(
86 base::Bind(&BluetoothHostPairingController::OnSendComplete
,
87 ptr_factory_
.GetWeakPtr()),
88 base::Bind(&BluetoothHostPairingController::OnSendError
,
89 ptr_factory_
.GetWeakPtr()));
94 void BluetoothHostPairingController::Reset() {
95 if (controller_socket_
.get()) {
96 controller_socket_
->Close();
97 controller_socket_
= NULL
;
100 if (service_socket_
.get()) {
101 service_socket_
->Close();
102 service_socket_
= NULL
;
104 ChangeStage(STAGE_NONE
);
107 void BluetoothHostPairingController::OnGetAdapter(
108 scoped_refptr
<device::BluetoothAdapter
> adapter
) {
109 DCHECK(thread_checker_
.CalledOnValidThread());
110 DCHECK(!adapter_
.get());
113 if (adapter_
->IsPresent()) {
116 // Set the name once the adapter is present.
117 adapter_
->AddObserver(this);
121 void BluetoothHostPairingController::SetName() {
122 // Hash the bluetooth address and take the lower 2 bytes to create a human
123 // readable device name.
124 const uint32 device_id
= base::Hash(adapter_
->GetAddress()) & 0xFFFF;
125 device_name_
= base::StringPrintf("%s%04X", kDeviceNamePrefix
, device_id
);
129 base::Bind(&BluetoothHostPairingController::OnSetName
,
130 ptr_factory_
.GetWeakPtr()),
131 base::Bind(&BluetoothHostPairingController::OnSetError
,
132 ptr_factory_
.GetWeakPtr()));
135 void BluetoothHostPairingController::OnSetName() {
136 DCHECK(thread_checker_
.CalledOnValidThread());
137 if (adapter_
->IsPowered()) {
140 adapter_
->SetPowered(
142 base::Bind(&BluetoothHostPairingController::OnSetPowered
,
143 ptr_factory_
.GetWeakPtr()),
144 base::Bind(&BluetoothHostPairingController::OnSetError
,
145 ptr_factory_
.GetWeakPtr()));
149 void BluetoothHostPairingController::OnSetPowered() {
150 DCHECK(thread_checker_
.CalledOnValidThread());
151 adapter_
->AddPairingDelegate(
152 this, device::BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH
);
154 device::BluetoothAdapter::ServiceOptions options
;
155 options
.name
.reset(new std::string(kPairingServiceName
));
157 adapter_
->CreateRfcommService(
158 device::BluetoothUUID(kPairingServiceUUID
), options
,
159 base::Bind(&BluetoothHostPairingController::OnCreateService
,
160 ptr_factory_
.GetWeakPtr()),
161 base::Bind(&BluetoothHostPairingController::OnCreateServiceError
,
162 ptr_factory_
.GetWeakPtr()));
165 void BluetoothHostPairingController::OnCreateService(
166 scoped_refptr
<device::BluetoothSocket
> socket
) {
167 DCHECK(thread_checker_
.CalledOnValidThread());
168 service_socket_
= socket
;
170 service_socket_
->Accept(
171 base::Bind(&BluetoothHostPairingController::OnAccept
,
172 ptr_factory_
.GetWeakPtr()),
173 base::Bind(&BluetoothHostPairingController::OnAcceptError
,
174 ptr_factory_
.GetWeakPtr()));
176 adapter_
->SetDiscoverable(
178 base::Bind(&BluetoothHostPairingController::OnSetDiscoverable
,
179 ptr_factory_
.GetWeakPtr(), true),
180 base::Bind(&BluetoothHostPairingController::OnSetError
,
181 ptr_factory_
.GetWeakPtr()));
184 void BluetoothHostPairingController::OnAccept(
185 const device::BluetoothDevice
* device
,
186 scoped_refptr
<device::BluetoothSocket
> socket
) {
187 DCHECK(thread_checker_
.CalledOnValidThread());
188 adapter_
->SetDiscoverable(
190 base::Bind(&BluetoothHostPairingController::OnSetDiscoverable
,
191 ptr_factory_
.GetWeakPtr(), false),
192 base::Bind(&BluetoothHostPairingController::OnSetError
,
193 ptr_factory_
.GetWeakPtr()));
195 controller_socket_
= socket
;
196 service_socket_
= NULL
;
198 // TODO: Update Host. (http://crbug.com/405754)
201 controller_socket_
->Receive(
203 base::Bind(&BluetoothHostPairingController::OnReceiveComplete
,
204 ptr_factory_
.GetWeakPtr()),
205 base::Bind(&BluetoothHostPairingController::OnReceiveError
,
206 ptr_factory_
.GetWeakPtr()));
208 ChangeStage(STAGE_WAITING_FOR_CREDENTIALS
);
211 void BluetoothHostPairingController::OnSetDiscoverable(bool change_stage
) {
212 DCHECK(thread_checker_
.CalledOnValidThread());
214 DCHECK_EQ(current_stage_
, STAGE_NONE
);
215 ChangeStage(STAGE_WAITING_FOR_CONTROLLER
);
219 void BluetoothHostPairingController::OnSendComplete(int bytes_sent
) {}
221 void BluetoothHostPairingController::OnReceiveComplete(
222 int bytes
, scoped_refptr
<net::IOBuffer
> io_buffer
) {
223 DCHECK(thread_checker_
.CalledOnValidThread());
224 proto_decoder_
->DecodeIOBuffer(bytes
, io_buffer
);
226 controller_socket_
->Receive(
228 base::Bind(&BluetoothHostPairingController::OnReceiveComplete
,
229 ptr_factory_
.GetWeakPtr()),
230 base::Bind(&BluetoothHostPairingController::OnReceiveError
,
231 ptr_factory_
.GetWeakPtr()));
234 void BluetoothHostPairingController::OnCreateServiceError(
235 const std::string
& message
) {
236 LOG(ERROR
) << message
;
237 ChangeStage(STAGE_INITIALIZATION_ERROR
);
240 void BluetoothHostPairingController::OnSetError() {
241 adapter_
->RemovePairingDelegate(this);
242 ChangeStage(STAGE_INITIALIZATION_ERROR
);
245 void BluetoothHostPairingController::OnAcceptError(
246 const std::string
& error_message
) {
247 LOG(ERROR
) << error_message
;
251 void BluetoothHostPairingController::OnSendError(
252 const std::string
& error_message
) {
253 LOG(ERROR
) << error_message
;
256 void BluetoothHostPairingController::OnReceiveError(
257 device::BluetoothSocket::ErrorReason reason
,
258 const std::string
& error_message
) {
259 LOG(ERROR
) << reason
<< ", " << error_message
;
263 void BluetoothHostPairingController::OnHostStatusMessage(
264 const pairing_api::HostStatus
& message
) {
268 void BluetoothHostPairingController::OnConfigureHostMessage(
269 const pairing_api::ConfigureHost
& message
) {
270 FOR_EACH_OBSERVER(Observer
, observers_
,
271 ConfigureHost(message
.parameters().accepted_eula(),
272 message
.parameters().lang(),
273 message
.parameters().timezone(),
274 message
.parameters().send_reports(),
275 message
.parameters().keyboard_layout()));
278 void BluetoothHostPairingController::OnPairDevicesMessage(
279 const pairing_api::PairDevices
& message
) {
280 DCHECK(thread_checker_
.CalledOnValidThread());
281 if (current_stage_
!= STAGE_WAITING_FOR_CREDENTIALS
) {
282 AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT
, kErrorInvalidProtocol
);
286 ChangeStage(STAGE_ENROLLING
);
287 FOR_EACH_OBSERVER(Observer
, observers_
,
288 EnrollHost(message
.parameters().admin_access_token()));
291 void BluetoothHostPairingController::SetEnrollmentComplete(bool success
) {
292 DCHECK_EQ(current_stage_
, STAGE_ENROLLING
);
293 DCHECK(thread_checker_
.CalledOnValidThread());
295 ChangeStage(STAGE_PAIRING_DONE
);
298 AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT
, kErrorEnrollmentFailed
);
302 void BluetoothHostPairingController::OnCompleteSetupMessage(
303 const pairing_api::CompleteSetup
& message
) {
304 DCHECK(thread_checker_
.CalledOnValidThread());
305 if (current_stage_
!= STAGE_PAIRING_DONE
) {
306 AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT
, kErrorInvalidProtocol
);
310 // TODO(zork): Handle adding another controller. (http://crbug.com/405757)
311 ChangeStage(STAGE_FINISHED
);
314 void BluetoothHostPairingController::OnErrorMessage(
315 const pairing_api::Error
& message
) {
319 void BluetoothHostPairingController::AdapterPresentChanged(
320 device::BluetoothAdapter
* adapter
,
322 DCHECK_EQ(adapter
, adapter_
.get());
324 adapter_
->RemoveObserver(this);
329 void BluetoothHostPairingController::AddObserver(Observer
* observer
) {
330 observers_
.AddObserver(observer
);
333 void BluetoothHostPairingController::RemoveObserver(Observer
* observer
) {
334 observers_
.RemoveObserver(observer
);
337 HostPairingController::Stage
BluetoothHostPairingController::GetCurrentStage() {
338 return current_stage_
;
341 void BluetoothHostPairingController::StartPairing() {
342 DCHECK_EQ(current_stage_
, STAGE_NONE
);
343 bool bluetooth_available
=
344 device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable();
345 if (!bluetooth_available
) {
346 ChangeStage(STAGE_INITIALIZATION_ERROR
);
350 device::BluetoothAdapterFactory::GetAdapter(
351 base::Bind(&BluetoothHostPairingController::OnGetAdapter
,
352 ptr_factory_
.GetWeakPtr()));
355 std::string
BluetoothHostPairingController::GetDeviceName() {
359 std::string
BluetoothHostPairingController::GetConfirmationCode() {
360 DCHECK_EQ(current_stage_
, STAGE_WAITING_FOR_CODE_CONFIRMATION
);
361 return confirmation_code_
;
364 std::string
BluetoothHostPairingController::GetEnrollmentDomain() {
365 return enrollment_domain_
;
368 void BluetoothHostPairingController::OnUpdateStatusChanged(
369 UpdateStatus update_status
) {
370 // TODO(zork): Handling updating stages (http://crbug.com/405754).
373 void BluetoothHostPairingController::RequestPinCode(
374 device::BluetoothDevice
* device
) {
375 // Disallow unknown device.
376 device
->RejectPairing();
379 void BluetoothHostPairingController::RequestPasskey(
380 device::BluetoothDevice
* device
) {
381 // Disallow unknown device.
382 device
->RejectPairing();
385 void BluetoothHostPairingController::DisplayPinCode(
386 device::BluetoothDevice
* device
,
387 const std::string
& pincode
) {
388 // Disallow unknown device.
389 device
->RejectPairing();
392 void BluetoothHostPairingController::DisplayPasskey(
393 device::BluetoothDevice
* device
,
395 // Disallow unknown device.
396 device
->RejectPairing();
399 void BluetoothHostPairingController::KeysEntered(
400 device::BluetoothDevice
* device
,
402 // Disallow unknown device.
403 device
->RejectPairing();
406 void BluetoothHostPairingController::ConfirmPasskey(
407 device::BluetoothDevice
* device
,
409 confirmation_code_
= base::StringPrintf("%06d", passkey
);
410 device
->ConfirmPairing();
411 ChangeStage(STAGE_WAITING_FOR_CODE_CONFIRMATION
);
414 void BluetoothHostPairingController::AuthorizePairing(
415 device::BluetoothDevice
* device
) {
416 // Disallow unknown device.
417 device
->RejectPairing();
420 } // namespace pairing_chromeos