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.
4
5 #include "components/pairing/bluetooth_controller_pairing_controller.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "components/pairing/bluetooth_pairing_constants.h"
13 #include "components/pairing/pairing_api.pb.h"
14 #include "device/bluetooth/bluetooth_adapter_factory.h"
15 #include "device/bluetooth/bluetooth_discovery_session.h"
16 #include "net/base/io_buffer.h"
17
18 namespace {
19 const int kReceiveSize = 16384;
20 }
21
22 namespace pairing_chromeos {
23
BluetoothControllerPairingController()24 BluetoothControllerPairingController::BluetoothControllerPairingController()
25 : current_stage_(STAGE_NONE),
26 got_initial_status_(false),
27 proto_decoder_(new ProtoDecoder(this)),
28 ptr_factory_(this) {
29 }
30
~BluetoothControllerPairingController()31 BluetoothControllerPairingController::~BluetoothControllerPairingController() {
32 Reset();
33 }
34
GetController()35 device::BluetoothDevice* BluetoothControllerPairingController::GetController() {
36 DCHECK(!controller_device_id_.empty());
37 device::BluetoothDevice* device = adapter_->GetDevice(controller_device_id_);
38 if (!device) {
39 LOG(ERROR) << "Lost connection to controller.";
40 ChangeStage(STAGE_ESTABLISHING_CONNECTION_ERROR);
41 }
42
43 return device;
44 }
45
ChangeStage(Stage new_stage)46 void BluetoothControllerPairingController::ChangeStage(Stage new_stage) {
47 if (current_stage_ == new_stage)
48 return;
49 current_stage_ = new_stage;
50 FOR_EACH_OBSERVER(ControllerPairingController::Observer, observers_,
51 PairingStageChanged(new_stage));
52 }
53
Reset()54 void BluetoothControllerPairingController::Reset() {
55 got_initial_status_ = false;
56 controller_device_id_.clear();
57 discovery_session_.reset();
58
59 if (socket_.get()) {
60 socket_->Close();
61 socket_ = NULL;
62 }
63
64 if (adapter_.get()) {
65 adapter_->RemoveObserver(this);
66 adapter_ = NULL;
67 }
68 }
69
DeviceFound(device::BluetoothDevice * device)70 void BluetoothControllerPairingController::DeviceFound(
71 device::BluetoothDevice* device) {
72 DCHECK_EQ(current_stage_, STAGE_DEVICES_DISCOVERY);
73 DCHECK(thread_checker_.CalledOnValidThread());
74 if (StartsWith(device->GetName(), base::ASCIIToUTF16(kDeviceNamePrefix),
75 false)) {
76 discovered_devices_.insert(device->GetAddress());
77 FOR_EACH_OBSERVER(ControllerPairingController::Observer, observers_,
78 DiscoveredDevicesListChanged());
79 }
80 }
81
DeviceLost(device::BluetoothDevice * device)82 void BluetoothControllerPairingController::DeviceLost(
83 device::BluetoothDevice* device) {
84 DCHECK_EQ(current_stage_, STAGE_DEVICES_DISCOVERY);
85 DCHECK(thread_checker_.CalledOnValidThread());
86 std::set<std::string>::iterator ix =
87 discovered_devices_.find(device->GetAddress());
88 if (ix != discovered_devices_.end()) {
89 discovered_devices_.erase(ix);
90 FOR_EACH_OBSERVER(ControllerPairingController::Observer, observers_,
91 DiscoveredDevicesListChanged());
92 }
93 }
94
SendBuffer(scoped_refptr<net::IOBuffer> io_buffer,int size)95 void BluetoothControllerPairingController::SendBuffer(
96 scoped_refptr<net::IOBuffer> io_buffer, int size) {
97 socket_->Send(
98 io_buffer, size,
99 base::Bind(&BluetoothControllerPairingController::OnSendComplete,
100 ptr_factory_.GetWeakPtr()),
101 base::Bind(&BluetoothControllerPairingController::OnErrorWithMessage,
102 ptr_factory_.GetWeakPtr()));
103 }
104
OnSetPowered()105 void BluetoothControllerPairingController::OnSetPowered() {
106 DCHECK(thread_checker_.CalledOnValidThread());
107 adapter_->StartDiscoverySession(
108 base::Bind(&BluetoothControllerPairingController::OnStartDiscoverySession,
109 ptr_factory_.GetWeakPtr()),
110 base::Bind(&BluetoothControllerPairingController::OnError,
111 ptr_factory_.GetWeakPtr()));
112 }
113
OnGetAdapter(scoped_refptr<device::BluetoothAdapter> adapter)114 void BluetoothControllerPairingController::OnGetAdapter(
115 scoped_refptr<device::BluetoothAdapter> adapter) {
116 DCHECK(thread_checker_.CalledOnValidThread());
117 DCHECK(!adapter_.get());
118 adapter_ = adapter;
119 adapter_->AddObserver(this);
120
121 if (adapter_->IsPowered()) {
122 OnSetPowered();
123 } else {
124 adapter_->SetPowered(
125 true,
126 base::Bind(&BluetoothControllerPairingController::OnSetPowered,
127 ptr_factory_.GetWeakPtr()),
128 base::Bind(&BluetoothControllerPairingController::OnError,
129 ptr_factory_.GetWeakPtr()));
130 }
131 }
132
OnStartDiscoverySession(scoped_ptr<device::BluetoothDiscoverySession> discovery_session)133 void BluetoothControllerPairingController::OnStartDiscoverySession(
134 scoped_ptr<device::BluetoothDiscoverySession> discovery_session) {
135 DCHECK(thread_checker_.CalledOnValidThread());
136 discovery_session_ = discovery_session.Pass();
137 ChangeStage(STAGE_DEVICES_DISCOVERY);
138
139 device::BluetoothAdapter::DeviceList device_list = adapter_->GetDevices();
140 for (device::BluetoothAdapter::DeviceList::iterator ix = device_list.begin();
141 ix != device_list.end(); ++ix) {
142 DeviceFound(*ix);
143 }
144 }
145
OnConnect()146 void BluetoothControllerPairingController::OnConnect() {
147 DCHECK(thread_checker_.CalledOnValidThread());
148 device::BluetoothDevice* device = GetController();
149 if (device) {
150 device->ConnectToService(
151 device::BluetoothUUID(kPairingServiceUUID),
152 base::Bind(&BluetoothControllerPairingController::OnConnectToService,
153 ptr_factory_.GetWeakPtr()),
154 base::Bind(&BluetoothControllerPairingController::OnErrorWithMessage,
155 ptr_factory_.GetWeakPtr()));
156 }
157 }
158
OnConnectToService(scoped_refptr<device::BluetoothSocket> socket)159 void BluetoothControllerPairingController::OnConnectToService(
160 scoped_refptr<device::BluetoothSocket> socket) {
161 DCHECK(thread_checker_.CalledOnValidThread());
162 socket_ = socket;
163
164 socket_->Receive(
165 kReceiveSize,
166 base::Bind(&BluetoothControllerPairingController::OnReceiveComplete,
167 ptr_factory_.GetWeakPtr()),
168 base::Bind(&BluetoothControllerPairingController::OnReceiveError,
169 ptr_factory_.GetWeakPtr()));
170 }
171
OnSendComplete(int bytes_sent)172 void BluetoothControllerPairingController::OnSendComplete(int bytes_sent) {}
173
OnReceiveComplete(int bytes,scoped_refptr<net::IOBuffer> io_buffer)174 void BluetoothControllerPairingController::OnReceiveComplete(
175 int bytes, scoped_refptr<net::IOBuffer> io_buffer) {
176 DCHECK(thread_checker_.CalledOnValidThread());
177 proto_decoder_->DecodeIOBuffer(bytes, io_buffer);
178
179 socket_->Receive(
180 kReceiveSize,
181 base::Bind(&BluetoothControllerPairingController::OnReceiveComplete,
182 ptr_factory_.GetWeakPtr()),
183 base::Bind(&BluetoothControllerPairingController::OnReceiveError,
184 ptr_factory_.GetWeakPtr()));
185 }
186
OnError()187 void BluetoothControllerPairingController::OnError() {
188 LOG(ERROR) << "Pairing initialization failed";
189 ChangeStage(STAGE_INITIALIZATION_ERROR);
190 Reset();
191 }
192
OnErrorWithMessage(const std::string & message)193 void BluetoothControllerPairingController::OnErrorWithMessage(
194 const std::string& message) {
195 LOG(ERROR) << message;
196 ChangeStage(STAGE_INITIALIZATION_ERROR);
197 Reset();
198 }
199
OnConnectError(device::BluetoothDevice::ConnectErrorCode error_code)200 void BluetoothControllerPairingController::OnConnectError(
201 device::BluetoothDevice::ConnectErrorCode error_code) {
202 DCHECK(thread_checker_.CalledOnValidThread());
203 device::BluetoothDevice* device = GetController();
204
205 if (device && device->IsPaired()) {
206 // The connection attempt is only used to start the pairing between the
207 // devices. If the connection fails, it's not a problem as long as pairing
208 // was successful.
209 OnConnect();
210 }
211 }
212
OnReceiveError(device::BluetoothSocket::ErrorReason reason,const std::string & error_message)213 void BluetoothControllerPairingController::OnReceiveError(
214 device::BluetoothSocket::ErrorReason reason,
215 const std::string& error_message) {
216 LOG(ERROR) << reason << ", " << error_message;
217 Reset();
218 }
219
AddObserver(ControllerPairingController::Observer * observer)220 void BluetoothControllerPairingController::AddObserver(
221 ControllerPairingController::Observer* observer) {
222 observers_.AddObserver(observer);
223 }
224
RemoveObserver(ControllerPairingController::Observer * observer)225 void BluetoothControllerPairingController::RemoveObserver(
226 ControllerPairingController::Observer* observer) {
227 observers_.RemoveObserver(observer);
228 }
229
230 ControllerPairingController::Stage
GetCurrentStage()231 BluetoothControllerPairingController::GetCurrentStage() {
232 return current_stage_;
233 }
234
StartPairing()235 void BluetoothControllerPairingController::StartPairing() {
236 DCHECK(thread_checker_.CalledOnValidThread());
237 DCHECK(current_stage_ == STAGE_NONE ||
238 current_stage_ == STAGE_DEVICE_NOT_FOUND ||
239 current_stage_ == STAGE_ESTABLISHING_CONNECTION_ERROR ||
240 current_stage_ == STAGE_HOST_ENROLLMENT_ERROR);
241 if (!device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) {
242 ChangeStage(STAGE_INITIALIZATION_ERROR);
243 return;
244 }
245
246 device::BluetoothAdapterFactory::GetAdapter(
247 base::Bind(&BluetoothControllerPairingController::OnGetAdapter,
248 ptr_factory_.GetWeakPtr()));
249
250 }
251
252 ControllerPairingController::DeviceIdList
GetDiscoveredDevices()253 BluetoothControllerPairingController::GetDiscoveredDevices() {
254 DCHECK_EQ(current_stage_, STAGE_DEVICES_DISCOVERY);
255 return DeviceIdList(discovered_devices_.begin(), discovered_devices_.end());
256 }
257
ChooseDeviceForPairing(const std::string & device_id)258 void BluetoothControllerPairingController::ChooseDeviceForPairing(
259 const std::string& device_id) {
260 DCHECK_EQ(current_stage_, STAGE_DEVICES_DISCOVERY);
261 DCHECK(discovered_devices_.count(device_id));
262 discovery_session_.reset();
263 controller_device_id_ = device_id;
264
265 device::BluetoothDevice* device = GetController();
266
267 if (device) {
268 ChangeStage(STAGE_ESTABLISHING_CONNECTION);
269 if (device->IsPaired()) {
270 OnConnect();
271 } else {
272 device->Connect(
273 this,
274 base::Bind(&BluetoothControllerPairingController::OnConnect,
275 ptr_factory_.GetWeakPtr()),
276 base::Bind(&BluetoothControllerPairingController::OnConnectError,
277 ptr_factory_.GetWeakPtr()));
278 }
279 }
280 }
281
RepeatDiscovery()282 void BluetoothControllerPairingController::RepeatDiscovery() {
283 DCHECK(current_stage_ == STAGE_DEVICE_NOT_FOUND ||
284 current_stage_ == STAGE_ESTABLISHING_CONNECTION_ERROR ||
285 current_stage_ == STAGE_HOST_ENROLLMENT_ERROR);
286 Reset();
287 StartPairing();
288 }
289
GetConfirmationCode()290 std::string BluetoothControllerPairingController::GetConfirmationCode() {
291 DCHECK_EQ(current_stage_, STAGE_WAITING_FOR_CODE_CONFIRMATION);
292 DCHECK(!confirmation_code_.empty());
293 return confirmation_code_;
294 }
295
SetConfirmationCodeIsCorrect(bool correct)296 void BluetoothControllerPairingController::SetConfirmationCodeIsCorrect(
297 bool correct) {
298 DCHECK_EQ(current_stage_, STAGE_WAITING_FOR_CODE_CONFIRMATION);
299
300 device::BluetoothDevice* device = GetController();
301 if (!device)
302 return;
303
304 if (correct) {
305 device->ConfirmPairing();
306 // Once pairing is confirmed, the connection will either be successful, or
307 // fail. Either case is acceptable as long as the devices are paired.
308 } else {
309 device->RejectPairing();
310 controller_device_id_.clear();
311 RepeatDiscovery();
312 }
313 }
314
SetHostConfiguration(bool accepted_eula,const std::string & lang,const std::string & timezone,bool send_reports,const std::string & keyboard_layout)315 void BluetoothControllerPairingController::SetHostConfiguration(
316 bool accepted_eula,
317 const std::string& lang,
318 const std::string& timezone,
319 bool send_reports,
320 const std::string& keyboard_layout) {
321
322 pairing_api::ConfigureHost host_config;
323 host_config.set_api_version(kPairingAPIVersion);
324 host_config.mutable_parameters()->set_accepted_eula(accepted_eula);
325 host_config.mutable_parameters()->set_lang(lang);
326 host_config.mutable_parameters()->set_timezone(timezone);
327 host_config.mutable_parameters()->set_send_reports(send_reports);
328 host_config.mutable_parameters()->set_keyboard_layout(keyboard_layout);
329
330 int size = 0;
331 scoped_refptr<net::IOBuffer> io_buffer(
332 ProtoDecoder::SendConfigureHost(host_config, &size));
333
334 SendBuffer(io_buffer, size);
335 }
336
OnAuthenticationDone(const std::string & domain,const std::string & auth_token)337 void BluetoothControllerPairingController::OnAuthenticationDone(
338 const std::string& domain,
339 const std::string& auth_token) {
340 DCHECK_EQ(current_stage_, STAGE_WAITING_FOR_CREDENTIALS);
341
342 pairing_api::PairDevices pair_devices;
343 pair_devices.set_api_version(kPairingAPIVersion);
344 pair_devices.mutable_parameters()->set_admin_access_token(auth_token);
345
346 int size = 0;
347 scoped_refptr<net::IOBuffer> io_buffer(
348 ProtoDecoder::SendPairDevices(pair_devices, &size));
349
350 SendBuffer(io_buffer, size);
351 ChangeStage(STAGE_HOST_ENROLLMENT_IN_PROGRESS);
352 }
353
StartSession()354 void BluetoothControllerPairingController::StartSession() {
355 DCHECK_EQ(current_stage_, STAGE_PAIRING_DONE);
356 ChangeStage(STAGE_FINISHED);
357 }
358
359 // ProtoDecoder::Observer:
OnHostStatusMessage(const pairing_api::HostStatus & message)360 void BluetoothControllerPairingController::OnHostStatusMessage(
361 const pairing_api::HostStatus& message) {
362 if (got_initial_status_) {
363 // TODO(zork): Check that the domain matches. (http://crbug.com/405761)
364 // TODO(zork): Handling updating stages (http://crbug.com/405754).
365 pairing_api::CompleteSetup complete_setup;
366 complete_setup.set_api_version(kPairingAPIVersion);
367 // TODO(zork): Get AddAnother from UI (http://crbug.com/405757)
368 complete_setup.mutable_parameters()->set_add_another(false);
369
370 int size = 0;
371 scoped_refptr<net::IOBuffer> io_buffer(
372 ProtoDecoder::SendCompleteSetup(complete_setup, &size));
373
374 SendBuffer(io_buffer, size);
375 ChangeStage(STAGE_PAIRING_DONE);
376 } else {
377 got_initial_status_ = true;
378
379 // TODO(zork): Check domain. (http://crbug.com/405761)
380 ChangeStage(STAGE_WAITING_FOR_CREDENTIALS);
381 }
382 }
383
OnConfigureHostMessage(const pairing_api::ConfigureHost & message)384 void BluetoothControllerPairingController::OnConfigureHostMessage(
385 const pairing_api::ConfigureHost& message) {
386 NOTREACHED();
387 }
388
OnPairDevicesMessage(const pairing_api::PairDevices & message)389 void BluetoothControllerPairingController::OnPairDevicesMessage(
390 const pairing_api::PairDevices& message) {
391 NOTREACHED();
392 }
393
OnCompleteSetupMessage(const pairing_api::CompleteSetup & message)394 void BluetoothControllerPairingController::OnCompleteSetupMessage(
395 const pairing_api::CompleteSetup& message) {
396 NOTREACHED();
397 }
398
OnErrorMessage(const pairing_api::Error & message)399 void BluetoothControllerPairingController::OnErrorMessage(
400 const pairing_api::Error& message) {
401 LOG(ERROR) << message.parameters().code() << ", " <<
402 message.parameters().description();
403 ChangeStage(STAGE_HOST_ENROLLMENT_ERROR);
404 }
405
DeviceAdded(device::BluetoothAdapter * adapter,device::BluetoothDevice * device)406 void BluetoothControllerPairingController::DeviceAdded(
407 device::BluetoothAdapter* adapter,
408 device::BluetoothDevice* device) {
409 DCHECK_EQ(adapter, adapter_.get());
410 DeviceFound(device);
411 }
412
DeviceRemoved(device::BluetoothAdapter * adapter,device::BluetoothDevice * device)413 void BluetoothControllerPairingController::DeviceRemoved(
414 device::BluetoothAdapter* adapter,
415 device::BluetoothDevice* device) {
416 DCHECK_EQ(adapter, adapter_.get());
417 DeviceLost(device);
418 }
419
RequestPinCode(device::BluetoothDevice * device)420 void BluetoothControllerPairingController::RequestPinCode(
421 device::BluetoothDevice* device) {
422 // Disallow unknown device.
423 device->RejectPairing();
424 }
425
RequestPasskey(device::BluetoothDevice * device)426 void BluetoothControllerPairingController::RequestPasskey(
427 device::BluetoothDevice* device) {
428 // Disallow unknown device.
429 device->RejectPairing();
430 }
431
DisplayPinCode(device::BluetoothDevice * device,const std::string & pincode)432 void BluetoothControllerPairingController::DisplayPinCode(
433 device::BluetoothDevice* device,
434 const std::string& pincode) {
435 // Disallow unknown device.
436 device->RejectPairing();
437 }
438
DisplayPasskey(device::BluetoothDevice * device,uint32 passkey)439 void BluetoothControllerPairingController::DisplayPasskey(
440 device::BluetoothDevice* device,
441 uint32 passkey) {
442 // Disallow unknown device.
443 device->RejectPairing();
444 }
445
KeysEntered(device::BluetoothDevice * device,uint32 entered)446 void BluetoothControllerPairingController::KeysEntered(
447 device::BluetoothDevice* device,
448 uint32 entered) {
449 // Disallow unknown device.
450 device->RejectPairing();
451 }
452
ConfirmPasskey(device::BluetoothDevice * device,uint32 passkey)453 void BluetoothControllerPairingController::ConfirmPasskey(
454 device::BluetoothDevice* device,
455 uint32 passkey) {
456 confirmation_code_ = base::StringPrintf("%06d", passkey);
457 ChangeStage(STAGE_WAITING_FOR_CODE_CONFIRMATION);
458 }
459
AuthorizePairing(device::BluetoothDevice * device)460 void BluetoothControllerPairingController::AuthorizePairing(
461 device::BluetoothDevice* device) {
462 // Disallow unknown device.
463 device->RejectPairing();
464 }
465
466 } // namespace pairing_chromeos
467