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