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_host_pairing_controller.h"
6
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"
16
17 namespace {
18 const int kReceiveSize = 16384;
19 }
20
21 namespace pairing_chromeos {
22
BluetoothHostPairingController()23 BluetoothHostPairingController::BluetoothHostPairingController()
24 : current_stage_(STAGE_NONE),
25 device_(NULL),
26 proto_decoder_(new ProtoDecoder(this)),
27 ptr_factory_(this) {
28 }
29
~BluetoothHostPairingController()30 BluetoothHostPairingController::~BluetoothHostPairingController() {
31 if (adapter_.get()) {
32 if (adapter_->IsDiscoverable()) {
33 adapter_->SetDiscoverable(false, base::Closure(), base::Closure());
34 }
35 adapter_->RemoveObserver(this);
36 adapter_ = NULL;
37 }
38 }
39
ChangeStage(Stage new_stage)40 void BluetoothHostPairingController::ChangeStage(Stage new_stage) {
41 if (current_stage_ == new_stage)
42 return;
43 current_stage_ = new_stage;
44 FOR_EACH_OBSERVER(Observer, observers_, PairingStageChanged(new_stage));
45 }
46
SendHostStatus()47 void BluetoothHostPairingController::SendHostStatus() {
48 pairing_api::HostStatus host_status;
49
50 host_status.set_api_version(kPairingAPIVersion);
51 if (!enrollment_domain_.empty())
52 host_status.mutable_parameters()->set_domain(enrollment_domain_);
53
54 // TODO(zork): Get these values from the UI. (http://crbug.com/405744)
55 host_status.mutable_parameters()->set_connectivity(
56 pairing_api::HostStatusParameters::CONNECTIVITY_CONNECTED);
57 host_status.mutable_parameters()->set_update_status(
58 pairing_api::HostStatusParameters::UPDATE_STATUS_UPDATED);
59
60 // TODO(zork): Get a list of other paired controllers.
61 // (http://crbug.com/405757)
62
63 int size = 0;
64 scoped_refptr<net::IOBuffer> io_buffer(
65 ProtoDecoder::SendHostStatus(host_status, &size));
66
67 controller_socket_->Send(
68 io_buffer, size,
69 base::Bind(&BluetoothHostPairingController::OnSendComplete,
70 ptr_factory_.GetWeakPtr()),
71 base::Bind(&BluetoothHostPairingController::OnSendError,
72 ptr_factory_.GetWeakPtr()));
73 }
74
AbortWithError(int code,const std::string & message)75 void BluetoothHostPairingController::AbortWithError(
76 int code,
77 const std::string& message) {
78 if (controller_socket_.get()) {
79 pairing_api::Error error;
80
81 error.set_api_version(kPairingAPIVersion);
82 error.mutable_parameters()->set_code(PAIRING_ERROR_PAIRING_OR_ENROLLMENT);
83 error.mutable_parameters()->set_description(message);
84
85 int size = 0;
86 scoped_refptr<net::IOBuffer> io_buffer(
87 ProtoDecoder::SendError(error, &size));
88
89 controller_socket_->Send(
90 io_buffer, size,
91 base::Bind(&BluetoothHostPairingController::OnSendComplete,
92 ptr_factory_.GetWeakPtr()),
93 base::Bind(&BluetoothHostPairingController::OnSendError,
94 ptr_factory_.GetWeakPtr()));
95 }
96 Reset();
97 }
98
Reset()99 void BluetoothHostPairingController::Reset() {
100 if (controller_socket_.get()) {
101 controller_socket_->Close();
102 controller_socket_ = NULL;
103 }
104
105 if (service_socket_.get()) {
106 service_socket_->Close();
107 service_socket_ = NULL;
108 }
109 ChangeStage(STAGE_NONE);
110 }
111
OnGetAdapter(scoped_refptr<device::BluetoothAdapter> adapter)112 void BluetoothHostPairingController::OnGetAdapter(
113 scoped_refptr<device::BluetoothAdapter> adapter) {
114 DCHECK(thread_checker_.CalledOnValidThread());
115 DCHECK(!adapter_.get());
116 adapter_ = adapter;
117
118 if (adapter_->IsPresent()) {
119 SetName();
120 } else {
121 // Set the name once the adapter is present.
122 adapter_->AddObserver(this);
123 }
124 }
125
SetName()126 void BluetoothHostPairingController::SetName() {
127 // Hash the bluetooth address and take the lower 2 bytes to create a human
128 // readable device name.
129 const uint32 device_id = base::Hash(adapter_->GetAddress()) & 0xFFFF;
130 device_name_ = base::StringPrintf("%s%04X", kDeviceNamePrefix, device_id);
131
132 adapter_->SetName(
133 device_name_,
134 base::Bind(&BluetoothHostPairingController::OnSetName,
135 ptr_factory_.GetWeakPtr()),
136 base::Bind(&BluetoothHostPairingController::OnSetError,
137 ptr_factory_.GetWeakPtr()));
138 }
139
OnSetName()140 void BluetoothHostPairingController::OnSetName() {
141 DCHECK(thread_checker_.CalledOnValidThread());
142 if (adapter_->IsPowered()) {
143 OnSetPowered();
144 } else {
145 adapter_->SetPowered(
146 true,
147 base::Bind(&BluetoothHostPairingController::OnSetPowered,
148 ptr_factory_.GetWeakPtr()),
149 base::Bind(&BluetoothHostPairingController::OnSetError,
150 ptr_factory_.GetWeakPtr()));
151 }
152 }
153
OnSetPowered()154 void BluetoothHostPairingController::OnSetPowered() {
155 DCHECK(thread_checker_.CalledOnValidThread());
156 adapter_->AddPairingDelegate(
157 this, device::BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH);
158
159 device::BluetoothAdapter::ServiceOptions options;
160 options.name.reset(new std::string(kPairingServiceName));
161
162 adapter_->CreateRfcommService(
163 device::BluetoothUUID(kPairingServiceUUID), options,
164 base::Bind(&BluetoothHostPairingController::OnCreateService,
165 ptr_factory_.GetWeakPtr()),
166 base::Bind(&BluetoothHostPairingController::OnCreateServiceError,
167 ptr_factory_.GetWeakPtr()));
168 }
169
OnCreateService(scoped_refptr<device::BluetoothSocket> socket)170 void BluetoothHostPairingController::OnCreateService(
171 scoped_refptr<device::BluetoothSocket> socket) {
172 DCHECK(thread_checker_.CalledOnValidThread());
173 service_socket_ = socket;
174
175 service_socket_->Accept(
176 base::Bind(&BluetoothHostPairingController::OnAccept,
177 ptr_factory_.GetWeakPtr()),
178 base::Bind(&BluetoothHostPairingController::OnAcceptError,
179 ptr_factory_.GetWeakPtr()));
180
181 adapter_->SetDiscoverable(
182 true,
183 base::Bind(&BluetoothHostPairingController::OnSetDiscoverable,
184 ptr_factory_.GetWeakPtr(), true),
185 base::Bind(&BluetoothHostPairingController::OnSetError,
186 ptr_factory_.GetWeakPtr()));
187 }
188
OnAccept(const device::BluetoothDevice * device,scoped_refptr<device::BluetoothSocket> socket)189 void BluetoothHostPairingController::OnAccept(
190 const device::BluetoothDevice* device,
191 scoped_refptr<device::BluetoothSocket> socket) {
192 DCHECK(thread_checker_.CalledOnValidThread());
193 adapter_->SetDiscoverable(
194 false,
195 base::Bind(&BluetoothHostPairingController::OnSetDiscoverable,
196 ptr_factory_.GetWeakPtr(), false),
197 base::Bind(&BluetoothHostPairingController::OnSetError,
198 ptr_factory_.GetWeakPtr()));
199
200 controller_socket_ = socket;
201 service_socket_ = NULL;
202
203 // TODO: Update Host. (http://crbug.com/405754)
204 SendHostStatus();
205
206 controller_socket_->Receive(
207 kReceiveSize,
208 base::Bind(&BluetoothHostPairingController::OnReceiveComplete,
209 ptr_factory_.GetWeakPtr()),
210 base::Bind(&BluetoothHostPairingController::OnReceiveError,
211 ptr_factory_.GetWeakPtr()));
212
213 ChangeStage(STAGE_WAITING_FOR_CREDENTIALS);
214 }
215
OnSetDiscoverable(bool change_stage)216 void BluetoothHostPairingController::OnSetDiscoverable(bool change_stage) {
217 DCHECK(thread_checker_.CalledOnValidThread());
218 if (change_stage) {
219 DCHECK_EQ(current_stage_, STAGE_NONE);
220 ChangeStage(STAGE_WAITING_FOR_CONTROLLER);
221 }
222 }
223
OnSendComplete(int bytes_sent)224 void BluetoothHostPairingController::OnSendComplete(int bytes_sent) {}
225
OnReceiveComplete(int bytes,scoped_refptr<net::IOBuffer> io_buffer)226 void BluetoothHostPairingController::OnReceiveComplete(
227 int bytes, scoped_refptr<net::IOBuffer> io_buffer) {
228 DCHECK(thread_checker_.CalledOnValidThread());
229 proto_decoder_->DecodeIOBuffer(bytes, io_buffer);
230
231 controller_socket_->Receive(
232 kReceiveSize,
233 base::Bind(&BluetoothHostPairingController::OnReceiveComplete,
234 ptr_factory_.GetWeakPtr()),
235 base::Bind(&BluetoothHostPairingController::OnReceiveError,
236 ptr_factory_.GetWeakPtr()));
237 }
238
OnCreateServiceError(const std::string & message)239 void BluetoothHostPairingController::OnCreateServiceError(
240 const std::string& message) {
241 LOG(ERROR) << message;
242 ChangeStage(STAGE_INITIALIZATION_ERROR);
243 }
244
OnSetError()245 void BluetoothHostPairingController::OnSetError() {
246 adapter_->RemovePairingDelegate(this);
247 ChangeStage(STAGE_INITIALIZATION_ERROR);
248 }
249
OnAcceptError(const std::string & error_message)250 void BluetoothHostPairingController::OnAcceptError(
251 const std::string& error_message) {
252 LOG(ERROR) << error_message;
253 }
254
OnSendError(const std::string & error_message)255 void BluetoothHostPairingController::OnSendError(
256 const std::string& error_message) {
257 LOG(ERROR) << error_message;
258 }
259
OnReceiveError(device::BluetoothSocket::ErrorReason reason,const std::string & error_message)260 void BluetoothHostPairingController::OnReceiveError(
261 device::BluetoothSocket::ErrorReason reason,
262 const std::string& error_message) {
263 LOG(ERROR) << reason << ", " << error_message;
264 }
265
OnHostStatusMessage(const pairing_api::HostStatus & message)266 void BluetoothHostPairingController::OnHostStatusMessage(
267 const pairing_api::HostStatus& message) {
268 NOTREACHED();
269 }
270
OnConfigureHostMessage(const pairing_api::ConfigureHost & message)271 void BluetoothHostPairingController::OnConfigureHostMessage(
272 const pairing_api::ConfigureHost& message) {
273 FOR_EACH_OBSERVER(Observer, observers_,
274 ConfigureHost(message.parameters().accepted_eula(),
275 message.parameters().lang(),
276 message.parameters().timezone(),
277 message.parameters().send_reports(),
278 message.parameters().keyboard_layout()));
279 }
280
OnPairDevicesMessage(const pairing_api::PairDevices & message)281 void BluetoothHostPairingController::OnPairDevicesMessage(
282 const pairing_api::PairDevices& message) {
283 DCHECK(thread_checker_.CalledOnValidThread());
284 if (current_stage_ != STAGE_WAITING_FOR_CREDENTIALS) {
285 AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT, kErrorInvalidProtocol);
286 return;
287 }
288
289 ChangeStage(STAGE_ENROLLING);
290 FOR_EACH_OBSERVER(Observer, observers_,
291 EnrollHost(message.parameters().admin_access_token()));
292 }
293
SetEnrollmentComplete(bool success)294 void BluetoothHostPairingController::SetEnrollmentComplete(bool success) {
295 DCHECK_EQ(current_stage_, STAGE_ENROLLING);
296 DCHECK(thread_checker_.CalledOnValidThread());
297 if (success) {
298 ChangeStage(STAGE_PAIRING_DONE);
299 SendHostStatus();
300 } else {
301 AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT, kErrorEnrollmentFailed);
302 }
303 }
304
OnCompleteSetupMessage(const pairing_api::CompleteSetup & message)305 void BluetoothHostPairingController::OnCompleteSetupMessage(
306 const pairing_api::CompleteSetup& message) {
307 DCHECK(thread_checker_.CalledOnValidThread());
308 if (current_stage_ != STAGE_PAIRING_DONE) {
309 AbortWithError(PAIRING_ERROR_PAIRING_OR_ENROLLMENT, kErrorInvalidProtocol);
310 return;
311 }
312
313 // TODO(zork): Handle adding another controller. (http://crbug.com/405757)
314 ChangeStage(STAGE_FINISHED);
315 }
316
OnErrorMessage(const pairing_api::Error & message)317 void BluetoothHostPairingController::OnErrorMessage(
318 const pairing_api::Error& message) {
319 NOTREACHED();
320 }
321
AdapterPresentChanged(device::BluetoothAdapter * adapter,bool present)322 void BluetoothHostPairingController::AdapterPresentChanged(
323 device::BluetoothAdapter* adapter,
324 bool present) {
325 DCHECK_EQ(adapter, adapter_.get());
326 if (present) {
327 adapter_->RemoveObserver(this);
328 SetName();
329 }
330 }
331
AddObserver(Observer * observer)332 void BluetoothHostPairingController::AddObserver(Observer* observer) {
333 observers_.AddObserver(observer);
334 }
335
RemoveObserver(Observer * observer)336 void BluetoothHostPairingController::RemoveObserver(Observer* observer) {
337 observers_.RemoveObserver(observer);
338 }
339
GetCurrentStage()340 HostPairingController::Stage BluetoothHostPairingController::GetCurrentStage() {
341 return current_stage_;
342 }
343
StartPairing()344 void BluetoothHostPairingController::StartPairing() {
345 DCHECK_EQ(current_stage_, STAGE_NONE);
346 bool bluetooth_available =
347 device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable();
348 if (!bluetooth_available) {
349 ChangeStage(STAGE_INITIALIZATION_ERROR);
350 return;
351 }
352
353 device::BluetoothAdapterFactory::GetAdapter(
354 base::Bind(&BluetoothHostPairingController::OnGetAdapter,
355 ptr_factory_.GetWeakPtr()));
356 }
357
GetDeviceName()358 std::string BluetoothHostPairingController::GetDeviceName() {
359 return device_name_;
360 }
361
GetConfirmationCode()362 std::string BluetoothHostPairingController::GetConfirmationCode() {
363 DCHECK_EQ(current_stage_, STAGE_WAITING_FOR_CODE_CONFIRMATION);
364 return confirmation_code_;
365 }
366
GetEnrollmentDomain()367 std::string BluetoothHostPairingController::GetEnrollmentDomain() {
368 return enrollment_domain_;
369 }
370
OnUpdateStatusChanged(UpdateStatus update_status)371 void BluetoothHostPairingController::OnUpdateStatusChanged(
372 UpdateStatus update_status) {
373 // TODO(zork): Handling updating stages (http://crbug.com/405754).
374 }
375
RequestPinCode(device::BluetoothDevice * device)376 void BluetoothHostPairingController::RequestPinCode(
377 device::BluetoothDevice* device) {
378 // Disallow unknown device.
379 device->RejectPairing();
380 }
381
RequestPasskey(device::BluetoothDevice * device)382 void BluetoothHostPairingController::RequestPasskey(
383 device::BluetoothDevice* device) {
384 // Disallow unknown device.
385 device->RejectPairing();
386 }
387
DisplayPinCode(device::BluetoothDevice * device,const std::string & pincode)388 void BluetoothHostPairingController::DisplayPinCode(
389 device::BluetoothDevice* device,
390 const std::string& pincode) {
391 // Disallow unknown device.
392 device->RejectPairing();
393 }
394
DisplayPasskey(device::BluetoothDevice * device,uint32 passkey)395 void BluetoothHostPairingController::DisplayPasskey(
396 device::BluetoothDevice* device,
397 uint32 passkey) {
398 // Disallow unknown device.
399 device->RejectPairing();
400 }
401
KeysEntered(device::BluetoothDevice * device,uint32 entered)402 void BluetoothHostPairingController::KeysEntered(
403 device::BluetoothDevice* device,
404 uint32 entered) {
405 // Disallow unknown device.
406 device->RejectPairing();
407 }
408
ConfirmPasskey(device::BluetoothDevice * device,uint32 passkey)409 void BluetoothHostPairingController::ConfirmPasskey(
410 device::BluetoothDevice* device,
411 uint32 passkey) {
412 confirmation_code_ = base::StringPrintf("%06d", passkey);
413 device->ConfirmPairing();
414 ChangeStage(STAGE_WAITING_FOR_CODE_CONFIRMATION);
415 }
416
AuthorizePairing(device::BluetoothDevice * device)417 void BluetoothHostPairingController::AuthorizePairing(
418 device::BluetoothDevice* device) {
419 // Disallow unknown device.
420 device->RejectPairing();
421 }
422
423 } // namespace pairing_chromeos
424