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"
8 #include "base/logging.h"
9 #include "base/strings/stringprintf.h"
10 #include "components/pairing/bluetooth_pairing_constants.h"
11 #include "components/pairing/pairing_api.pb.h"
12 #include "components/pairing/proto_decoder.h"
13 #include "device/bluetooth/bluetooth_adapter_factory.h"
14 #include "net/base/io_buffer.h"
17 const int kReceiveSize
= 16384;
20 namespace pairing_chromeos
{
22 BluetoothHostPairingController::BluetoothHostPairingController()
23 : current_stage_(STAGE_NONE
),
25 proto_decoder_(new ProtoDecoder(this)),
29 BluetoothHostPairingController::~BluetoothHostPairingController() {}
31 void BluetoothHostPairingController::ChangeStage(Stage new_stage
) {
32 if (current_stage_
== new_stage
)
34 current_stage_
= new_stage
;
35 FOR_EACH_OBSERVER(Observer
, observers_
, PairingStageChanged(new_stage
));
38 void BluetoothHostPairingController::SendHostStatus() {
39 pairing_api::HostStatus host_status
;
41 host_status
.set_api_version(kPairingAPIVersion
);
42 if (!enrollment_domain_
.empty())
43 host_status
.mutable_parameters()->set_domain(enrollment_domain_
);
45 // TODO(zork): Get these values from the UI. (http://crbug.com/405744)
46 host_status
.mutable_parameters()->set_connectivity(
47 pairing_api::HostStatusParameters::CONNECTIVITY_CONNECTED
);
48 host_status
.mutable_parameters()->set_update_status(
49 pairing_api::HostStatusParameters::UPDATE_STATUS_UPDATED
);
51 // TODO(zork): Get a list of other paired controllers.
52 // (http://crbug.com/405757)
55 scoped_refptr
<net::IOBuffer
> io_buffer(
56 ProtoDecoder::SendHostStatus(host_status
, &size
));
58 controller_socket_
->Send(
60 base::Bind(&BluetoothHostPairingController::OnSendComplete
,
61 ptr_factory_
.GetWeakPtr()),
62 base::Bind(&BluetoothHostPairingController::OnSendError
,
63 ptr_factory_
.GetWeakPtr()));
66 void BluetoothHostPairingController::AbortWithError(
68 const std::string
& message
) {
69 if (controller_socket_
) {
70 pairing_api::Error error
;
72 error
.set_api_version(kPairingAPIVersion
);
73 error
.mutable_parameters()->set_code(PAIRING_ERROR_PAIRING_OR_ENROLLMENT
);
74 error
.mutable_parameters()->set_description(message
);
77 scoped_refptr
<net::IOBuffer
> io_buffer(
78 ProtoDecoder::SendError(error
, &size
));
80 controller_socket_
->Send(
82 base::Bind(&BluetoothHostPairingController::OnSendComplete
,
83 ptr_factory_
.GetWeakPtr()),
84 base::Bind(&BluetoothHostPairingController::OnSendError
,
85 ptr_factory_
.GetWeakPtr()));
90 void BluetoothHostPairingController::Reset() {
91 if (controller_socket_
) {
92 controller_socket_
->Close();
93 controller_socket_
= NULL
;
96 if (service_socket_
) {
97 service_socket_
->Close();
98 service_socket_
= NULL
;
100 ChangeStage(STAGE_NONE
);
103 void BluetoothHostPairingController::OnGetAdapter(
104 scoped_refptr
<device::BluetoothAdapter
> adapter
) {
105 DCHECK(thread_checker_
.CalledOnValidThread());
109 // TODO(zork): Make the device name prettier. (http://crbug.com/405774)
110 device_name_
= base::StringPrintf("%s%s", kDeviceNamePrefix
,
111 adapter_
->GetAddress().c_str());
114 base::Bind(&BluetoothHostPairingController::OnSetName
,
115 ptr_factory_
.GetWeakPtr()),
116 base::Bind(&BluetoothHostPairingController::OnSetError
,
117 ptr_factory_
.GetWeakPtr()));
120 void BluetoothHostPairingController::OnSetName() {
121 DCHECK(thread_checker_
.CalledOnValidThread());
122 if (adapter_
->IsPowered()) {
125 adapter_
->SetPowered(
127 base::Bind(&BluetoothHostPairingController::OnSetPowered
,
128 ptr_factory_
.GetWeakPtr()),
129 base::Bind(&BluetoothHostPairingController::OnSetError
,
130 ptr_factory_
.GetWeakPtr()));
134 void BluetoothHostPairingController::OnSetPowered() {
135 DCHECK(thread_checker_
.CalledOnValidThread());
136 adapter_
->AddPairingDelegate(
137 this, device::BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH
);
139 device::BluetoothAdapter::ServiceOptions options
;
140 options
.name
.reset(new std::string(kPairingServiceName
));
142 adapter_
->CreateRfcommService(
143 device::BluetoothUUID(kPairingServiceUUID
), options
,
144 base::Bind(&BluetoothHostPairingController::OnCreateService
,
145 ptr_factory_
.GetWeakPtr()),
146 base::Bind(&BluetoothHostPairingController::OnCreateServiceError
,
147 ptr_factory_
.GetWeakPtr()));
150 void BluetoothHostPairingController::OnCreateService(
151 scoped_refptr
<device::BluetoothSocket
> socket
) {
152 DCHECK(thread_checker_
.CalledOnValidThread());
153 service_socket_
= socket
;
155 service_socket_
->Accept(
156 base::Bind(&BluetoothHostPairingController::OnAccept
,
157 ptr_factory_
.GetWeakPtr()),
158 base::Bind(&BluetoothHostPairingController::OnAcceptError
,
159 ptr_factory_
.GetWeakPtr()));
161 adapter_
->SetDiscoverable(
163 base::Bind(&BluetoothHostPairingController::OnSetDiscoverable
,
164 ptr_factory_
.GetWeakPtr(), true),
165 base::Bind(&BluetoothHostPairingController::OnSetError
,
166 ptr_factory_
.GetWeakPtr()));
169 void BluetoothHostPairingController::OnAccept(
170 const device::BluetoothDevice
* device
,
171 scoped_refptr
<device::BluetoothSocket
> socket
) {
172 DCHECK(thread_checker_
.CalledOnValidThread());
173 adapter_
->SetDiscoverable(
175 base::Bind(&BluetoothHostPairingController::OnSetDiscoverable
,
176 ptr_factory_
.GetWeakPtr(), false),
177 base::Bind(&BluetoothHostPairingController::OnSetError
,
178 ptr_factory_
.GetWeakPtr()));
180 controller_socket_
= socket
;
181 service_socket_
= NULL
;
183 // TODO: Update Host. (http://crbug.com/405754)
186 controller_socket_
->Receive(
188 base::Bind(&BluetoothHostPairingController::OnReceiveComplete
,
189 ptr_factory_
.GetWeakPtr()),
190 base::Bind(&BluetoothHostPairingController::OnReceiveError
,
191 ptr_factory_
.GetWeakPtr()));
193 ChangeStage(STAGE_WAITING_FOR_CREDENTIALS
);
196 void BluetoothHostPairingController::OnSetDiscoverable(bool change_stage
) {
197 DCHECK(thread_checker_
.CalledOnValidThread());
199 DCHECK_EQ(current_stage_
, STAGE_NONE
);
200 ChangeStage(STAGE_WAITING_FOR_CONTROLLER
);
204 void BluetoothHostPairingController::OnSendComplete(int bytes_sent
) {}
206 void BluetoothHostPairingController::OnReceiveComplete(
207 int bytes
, scoped_refptr
<net::IOBuffer
> io_buffer
) {
208 DCHECK(thread_checker_
.CalledOnValidThread());
209 proto_decoder_
->DecodeIOBuffer(bytes
, io_buffer
);
211 controller_socket_
->Receive(
213 base::Bind(&BluetoothHostPairingController::OnReceiveComplete
,
214 ptr_factory_
.GetWeakPtr()),
215 base::Bind(&BluetoothHostPairingController::OnReceiveError
,
216 ptr_factory_
.GetWeakPtr()));
219 void BluetoothHostPairingController::OnCreateServiceError(
220 const std::string
& message
) {
221 LOG(ERROR
) << message
;
222 // TODO(zork): Add a stage for initialization error. (http://crbug.com/405744)
223 ChangeStage(STAGE_NONE
);
226 void BluetoothHostPairingController::OnSetError() {
227 adapter_
->RemovePairingDelegate(this);
228 // TODO(zork): Add a stage for initialization error. (http://crbug.com/405744)
229 ChangeStage(STAGE_NONE
);
232 void BluetoothHostPairingController::OnAcceptError(
233 const std::string
& error_message
) {
234 LOG(ERROR
) << error_message
;
238 void BluetoothHostPairingController::OnSendError(
239 const std::string
& error_message
) {
240 LOG(ERROR
) << error_message
;
243 void BluetoothHostPairingController::OnReceiveError(
244 device::BluetoothSocket::ErrorReason reason
,
245 const std::string
& error_message
) {
246 LOG(ERROR
) << reason
<< ", " << error_message
;
250 void BluetoothHostPairingController::OnHostStatusMessage(
251 const pairing_api::HostStatus
& message
) {
255 void BluetoothHostPairingController::OnConfigureHostMessage(
256 const pairing_api::ConfigureHost
& message
) {
257 // TODO(zork): Add event to API to handle this case. (http://crbug.com/405744)
260 void BluetoothHostPairingController::OnPairDevicesMessage(
261 const pairing_api::PairDevices
& message
) {
262 DCHECK(thread_checker_
.CalledOnValidThread());
263 if (current_stage_
!= STAGE_WAITING_FOR_CREDENTIALS
) {
264 AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT
, kErrorInvalidProtocol
);
268 ChangeStage(STAGE_ENROLLING
);
269 // TODO(zork,achuith): Enroll device, send error on error.
270 // (http://crbug.com/374990)
271 // For now, test domain is sent in the access token.
272 enrollment_domain_
= message
.parameters().admin_access_token();
273 ChangeStage(STAGE_PAIRING_DONE
);
277 void BluetoothHostPairingController::OnCompleteSetupMessage(
278 const pairing_api::CompleteSetup
& message
) {
279 DCHECK(thread_checker_
.CalledOnValidThread());
280 if (current_stage_
!= STAGE_PAIRING_DONE
) {
281 AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT
, kErrorInvalidProtocol
);
285 // TODO(zork): Handle adding another controller. (http://crbug.com/405757)
286 ChangeStage(STAGE_FINISHED
);
289 void BluetoothHostPairingController::OnErrorMessage(
290 const pairing_api::Error
& message
) {
294 void BluetoothHostPairingController::AddObserver(Observer
* observer
) {
295 observers_
.AddObserver(observer
);
298 void BluetoothHostPairingController::RemoveObserver(Observer
* observer
) {
299 observers_
.RemoveObserver(observer
);
302 HostPairingController::Stage
BluetoothHostPairingController::GetCurrentStage() {
303 return current_stage_
;
306 void BluetoothHostPairingController::StartPairing() {
307 DCHECK_EQ(current_stage_
, STAGE_NONE
);
308 bool bluetooth_available
=
309 device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable();
310 // TODO(zork): Add a stage for initialization error. (http://crbug.com/405744)
311 if (!bluetooth_available
)
314 device::BluetoothAdapterFactory::GetAdapter(
315 base::Bind(&BluetoothHostPairingController::OnGetAdapter
,
316 ptr_factory_
.GetWeakPtr()));
319 std::string
BluetoothHostPairingController::GetDeviceName() {
323 std::string
BluetoothHostPairingController::GetConfirmationCode() {
324 DCHECK_EQ(current_stage_
, STAGE_WAITING_FOR_CODE_CONFIRMATION
);
325 return confirmation_code_
;
328 std::string
BluetoothHostPairingController::GetEnrollmentDomain() {
329 return enrollment_domain_
;
332 void BluetoothHostPairingController::OnUpdateStatusChanged(
333 UpdateStatus update_status
) {
334 // TODO(zork): Handling updating stages (http://crbug.com/405754).
337 void BluetoothHostPairingController::RequestPinCode(
338 device::BluetoothDevice
* device
) {
339 // Disallow unknown device.
340 device
->RejectPairing();
343 void BluetoothHostPairingController::RequestPasskey(
344 device::BluetoothDevice
* device
) {
345 // Disallow unknown device.
346 device
->RejectPairing();
349 void BluetoothHostPairingController::DisplayPinCode(
350 device::BluetoothDevice
* device
,
351 const std::string
& pincode
) {
352 // Disallow unknown device.
353 device
->RejectPairing();
356 void BluetoothHostPairingController::DisplayPasskey(
357 device::BluetoothDevice
* device
,
359 // Disallow unknown device.
360 device
->RejectPairing();
363 void BluetoothHostPairingController::KeysEntered(
364 device::BluetoothDevice
* device
,
366 // Disallow unknown device.
367 device
->RejectPairing();
370 void BluetoothHostPairingController::ConfirmPasskey(
371 device::BluetoothDevice
* device
,
373 confirmation_code_
= base::StringPrintf("%06d", passkey
);
374 device
->ConfirmPairing();
375 ChangeStage(STAGE_WAITING_FOR_CODE_CONFIRMATION
);
378 void BluetoothHostPairingController::AuthorizePairing(
379 device::BluetoothDevice
* device
) {
380 // Disallow unknown device.
381 device
->RejectPairing();
384 } // namespace pairing_chromeos