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