Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(50)

Side by Side Diff: chromeos/components/tether/ble_connection_manager.cc

Issue 2697763002: [CrOS Tether]: Create BleConnectionManager, which manages secure connections between the current de… (Closed)
Patch Set: hansberry@ comments. Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 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 "chromeos/components/tether/ble_connection_manager.h"
6
7 #include "chromeos/components/tether/ble_constants.h"
8 #include "components/cryptauth/ble/bluetooth_low_energy_weave_client_connection. h"
9 #include "components/proximity_auth/logging/logging.h"
10 #include "device/bluetooth/bluetooth_uuid.h"
11
12 namespace chromeos {
13
14 namespace tether {
15
16 namespace {
17 const char kTetherFeature[] = "magic_tether";
18 const int64_t kAdvertisingTimeoutInSeconds = 12;
19 const int64_t kShortErrorTimeoutInSeconds = 1;
20 } // namespace
21
22 // static
23 std::string BleConnectionManager::MessageTypeToString(
24 const MessageType& reason) {
25 switch (reason) {
26 case MessageType::TETHER_AVAILABILITY_REQUEST:
27 return "[TetherAvailabilityRequest]";
28 case MessageType::CONNECT_TETHERING_REQUEST:
29 return "[ConnectTetheringRequest]";
30 case MessageType::KEEP_ALIVE_TICKLE:
31 return "[KeepAliveTickle]";
32 case MessageType::DISCONNECT_TETHERING_REQUEST:
33 return "[DisconnectTetheringRequest]";
34 default:
35 return "[invalid MessageType]";
36 }
37 }
38
39 BleConnectionManager::ConnectionMetadata::ConnectionMetadata(
40 const cryptauth::RemoteDevice remote_device,
41 std::shared_ptr<base::Timer> timer)
42 : remote_device_(remote_device),
43 connection_attempt_timeout_timer_(timer),
44 weak_ptr_factory_(this) {}
45
46 BleConnectionManager::ConnectionMetadata::~ConnectionMetadata() {}
47
48 void BleConnectionManager::ConnectionMetadata::RegisterConnectionReason(
49 const MessageType& connection_reason) {
50 active_connection_reasons_.insert(connection_reason);
51 }
52
53 void BleConnectionManager::ConnectionMetadata::UnregisterConnectionReason(
54 const MessageType& connection_reason) {
55 active_connection_reasons_.erase(connection_reason);
56 }
57
58 bool BleConnectionManager::ConnectionMetadata::HasReasonForConnection() const {
59 return !active_connection_reasons_.empty();
60 }
61
62 cryptauth::SecureChannel::Status
63 BleConnectionManager::ConnectionMetadata::GetStatus() const {
64 if (IsActivelyConnecting()) {
65 return cryptauth::SecureChannel::Status::CONNECTING;
66 } else if (!HasEstablishedConnection()) {
67 return cryptauth::SecureChannel::Status::DISCONNECTED;
68 }
69
70 return secure_channel_->status();
71 }
72
73 bool BleConnectionManager::ConnectionMetadata::IsActivelyConnecting() const {
74 return connection_attempt_timeout_timer_->IsRunning();
75 }
76
77 bool BleConnectionManager::ConnectionMetadata::HasEstablishedConnection()
78 const {
79 return secure_channel_.get();
80 }
81
82 bool BleConnectionManager::ConnectionMetadata::CanSendMessage() const {
83 return secure_channel_ &&
84 secure_channel_->status() ==
85 cryptauth::SecureChannel::Status::AUTHENTICATED;
86 }
87
88 void BleConnectionManager::ConnectionMetadata::StartConnectionAttemptTimeout(
89 const ConnectionAttemptTimeoutCallback& handler,
90 bool use_short_error_timeout) {
91 DCHECK(!IsActivelyConnecting());
92 DCHECK(!secure_channel_);
93 DCHECK(timeout_handler_.is_null());
94
95 int64_t timeout_sec = use_short_error_timeout ? kShortErrorTimeoutInSeconds
96 : kAdvertisingTimeoutInSeconds;
97
98 timeout_handler_ = handler;
99 connection_attempt_timeout_timer_->Start(
100 FROM_HERE, base::TimeDelta::FromSeconds(timeout_sec),
101 base::Bind(&ConnectionMetadata::OnConnectionAttemptTimeout,
102 weak_ptr_factory_.GetWeakPtr()));
103 }
104
105 void BleConnectionManager::ConnectionMetadata::OnConnectionAttemptTimeout() {
106 // First, store |timeout_handler_| to a temporary variable and reset
107 // |timeout_handler_|.
108 ConnectionAttemptTimeoutCallback handler = timeout_handler_;
109 timeout_handler_.Reset();
110
111 // Run the handler after |timeout_handler_| has already been reset to ensure
112 // that if the callback references this instance, internal state is correct.
113 handler.Run(remote_device_);
114 }
115
116 void BleConnectionManager::ConnectionMetadata::SetSecureChannel(
117 std::unique_ptr<cryptauth::SecureChannel> secure_channel,
118 const SecureChannelStatusChangeCallback& status_change_handler,
119 const MessageReceivedCallback message_received_handler) {
120 DCHECK(!secure_channel_);
121 DCHECK(status_change_handler_.is_null());
122 DCHECK(message_received_handler_.is_null());
123
124 // The connection has succeeded, so cancel the timeout.
125 connection_attempt_timeout_timer_->Stop();
126
127 status_change_handler_ = status_change_handler;
128 message_received_handler_ = message_received_handler;
129
130 secure_channel_ = std::move(secure_channel);
131 secure_channel_->AddObserver(this);
132 secure_channel_->Initialize();
133 }
134
135 void BleConnectionManager::ConnectionMetadata::SendMessage(
136 const std::string& payload) {
137 DCHECK(CanSendMessage());
138 secure_channel_->SendMessage(std::string(kTetherFeature), payload);
139 }
140
141 void BleConnectionManager::ConnectionMetadata::OnSecureChannelStatusChanged(
142 cryptauth::SecureChannel* secure_channel,
143 const cryptauth::SecureChannel::Status& old_status,
144 const cryptauth::SecureChannel::Status& new_status) {
145 DCHECK(secure_channel_.get() == secure_channel);
146
147 if (new_status == cryptauth::SecureChannel::Status::CONNECTING) {
148 // BleConnectionManager already broadcasts "disconnected => connecting"
149 // status updates when a connection attempt begins, so there is no need to
150 // handle this case.
151 return;
152 }
153
154 if (new_status == cryptauth::SecureChannel::Status::DISCONNECTED) {
155 // First, store |status_change_handler_| to a temporary variable and reset
156 // |status_change_handler_|.
157 SecureChannelStatusChangeCallback handler = status_change_handler_;
158 secure_channel_->RemoveObserver(this);
159 secure_channel_.reset();
160 timeout_handler_.Reset();
161 status_change_handler_.Reset();
162 message_received_handler_.Reset();
163
164 // Run the handler after the other two handlers have already been reset to
165 // ensure that if the callback references this instance, internal state is
166 // correct.
167 handler.Run(remote_device_, old_status,
168 cryptauth::SecureChannel::Status::DISCONNECTED);
169 return;
170 }
171
172 status_change_handler_.Run(remote_device_, old_status, new_status);
173 }
174
175 void BleConnectionManager::ConnectionMetadata::OnMessageReceived(
176 cryptauth::SecureChannel* secure_channel,
177 const std::string& feature,
178 const std::string& payload) {
179 DCHECK(secure_channel_.get() == secure_channel);
180 if (feature != std::string(kTetherFeature)) {
181 // If the message received was not a tether feature, ignore it.
182 return;
183 }
184
185 message_received_handler_.Run(remote_device_, payload);
186 }
187
188 std::unique_ptr<base::Timer> BleConnectionManager::TimerFactory::CreateTimer() {
189 return base::MakeUnique<base::OneShotTimer>();
190 }
191
192 BleConnectionManager::BleConnectionManager(
193 std::unique_ptr<Delegate> delegate,
194 scoped_refptr<device::BluetoothAdapter> adapter,
195 const LocalDeviceDataProvider* local_device_data_provider,
196 const cryptauth::RemoteBeaconSeedFetcher* remote_beacon_seed_fetcher,
197 cryptauth::BluetoothThrottler* bluetooth_throttler)
198 : BleConnectionManager(
199 std::move(delegate),
200 adapter,
201 // TODO(khorimoto): Inject |adapter| into |BleScanner|.
202 base::MakeUnique<BleScanner>(local_device_data_provider),
203 base::MakeUnique<BleAdvertiser>(adapter,
204 local_device_data_provider,
205 remote_beacon_seed_fetcher),
206 base::MakeUnique<BleAdvertisementDeviceQueue>(),
207 base::WrapUnique<TimerFactory>(new TimerFactory()),
208 bluetooth_throttler) {}
209
210 BleConnectionManager::BleConnectionManager(
211 std::unique_ptr<Delegate> delegate,
212 scoped_refptr<device::BluetoothAdapter> adapter,
213 std::unique_ptr<BleScanner> ble_scanner,
214 std::unique_ptr<BleAdvertiser> ble_advertiser,
215 std::unique_ptr<BleAdvertisementDeviceQueue> device_queue,
216 std::unique_ptr<TimerFactory> timer_factory,
217 cryptauth::BluetoothThrottler* bluetooth_throttler)
218 : delegate_(std::move(delegate)),
219 adapter_(adapter),
220 ble_scanner_(std::move(ble_scanner)),
221 ble_advertiser_(std::move(ble_advertiser)),
222 device_queue_(std::move(device_queue)),
223 timer_factory_(std::move(timer_factory)),
224 bluetooth_throttler_(bluetooth_throttler),
225 weak_ptr_factory_(this) {
226 ble_scanner_->AddObserver(this);
227 }
228
229 BleConnectionManager::~BleConnectionManager() {
230 ble_scanner_->RemoveObserver(this);
231 }
232
233 void BleConnectionManager::RegisterRemoteDevice(
234 const cryptauth::RemoteDevice& remote_device,
235 const MessageType& connection_reason) {
236 PA_LOG(INFO) << "Registering device with ID "
237 << remote_device.GetTruncatedDeviceIdForLogs() << " for reason "
238 << MessageTypeToString(connection_reason);
239
240 std::shared_ptr<ConnectionMetadata> data =
241 GetConnectionMetadata(remote_device);
242 if (!data) {
243 data = AddMetadataForDevice(remote_device);
244 }
245
246 data->RegisterConnectionReason(connection_reason);
247 UpdateConnectionAttempts();
248 }
249
250 void BleConnectionManager::UnregisterRemoteDevice(
251 const cryptauth::RemoteDevice& remote_device,
252 const MessageType& connection_reason) {
253 PA_LOG(INFO) << "Unregistering device with ID "
254 << remote_device.GetTruncatedDeviceIdForLogs() << " for reason "
255 << MessageTypeToString(connection_reason);
256
257 std::shared_ptr<ConnectionMetadata> data =
258 GetConnectionMetadata(remote_device);
259 if (!data) {
260 // If the device was not registered, there is nothing to do.
261 return;
262 }
263
264 data->UnregisterConnectionReason(connection_reason);
265 if (!data->HasReasonForConnection()) {
266 cryptauth::SecureChannel::Status status_before_disconnect =
267 data->GetStatus();
268 device_to_metadata_map_.erase(remote_device);
269 if (status_before_disconnect ==
270 cryptauth::SecureChannel::Status::CONNECTING) {
271 StopConnectionAttemptAndMoveToEndOfQueue(remote_device);
272 }
273 if (status_before_disconnect !=
274 cryptauth::SecureChannel::Status::DISCONNECTED) {
275 // Send a status update for the disconnection.
276 SendSecureChannelStatusChangeEvent(
277 remote_device, status_before_disconnect,
278 cryptauth::SecureChannel::Status::DISCONNECTED);
279 }
280 }
281
282 UpdateConnectionAttempts();
283 }
284
285 void BleConnectionManager::SendMessage(
286 const cryptauth::RemoteDevice& remote_device,
287 const std::string& message) {
288 std::shared_ptr<ConnectionMetadata> data =
289 GetConnectionMetadata(remote_device);
290 if (!data || !data->CanSendMessage()) {
291 PA_LOG(ERROR) << "Attempted to send a message to device with ID "
292 << remote_device.GetTruncatedDeviceIdForLogs() << ". "
293 << "Message: \"" << message << "\"";
294 return;
295 }
296
297 PA_LOG(INFO) << "Sending message to device with ID "
298 << remote_device.GetTruncatedDeviceIdForLogs() << ". "
299 << "Message: \"" << message << "\"";
300 data->SendMessage(message);
301 }
302
303 void BleConnectionManager::AddObserver(Observer* observer) {
304 observer_list_.AddObserver(observer);
305 }
306
307 void BleConnectionManager::RemoveObserver(Observer* observer) {
308 observer_list_.RemoveObserver(observer);
309 }
310
311 void BleConnectionManager::OnReceivedAdvertisementFromDevice(
312 const std::string& device_address,
313 cryptauth::RemoteDevice remote_device) {
314 std::shared_ptr<ConnectionMetadata> data =
315 GetConnectionMetadata(remote_device);
316 if (!data) {
317 // If an advertisement is received from a device that is not registered,
318 // ignore it.
319 PA_LOG(WARNING) << "Received an advertisement from a device which is not "
320 << "registered. Bluetooth address: " << device_address
321 << ", Remote Device ID: " << remote_device.GetDeviceId();
322 return;
323 }
324
325 PA_LOG(INFO) << "Received advertisement from device with ID "
326 << remote_device.GetTruncatedDeviceIdForLogs() << ". "
327 << "Starting authentication handshake to that device.";
328
329 // Create a connection to that device.
330 std::unique_ptr<cryptauth::Connection> connection =
331 cryptauth::weave::BluetoothLowEnergyWeaveClientConnection::Factory::
332 NewInstance(remote_device, device_address, adapter_,
333 device::BluetoothUUID(std::string(kGattServerUuid)),
334 bluetooth_throttler_);
335 std::unique_ptr<cryptauth::SecureChannel> secure_channel =
336 cryptauth::SecureChannel::Factory::NewInstance(
337 std::move(connection), delegate_->CreateSecureChannelDelegate());
338 data->SetSecureChannel(
339 std::move(secure_channel),
340 base::Bind(&BleConnectionManager::OnSecureChannelStatusChanged,
341 weak_ptr_factory_.GetWeakPtr()),
342 base::Bind(&BleConnectionManager::SendMessageReceivedEvent,
343 weak_ptr_factory_.GetWeakPtr()));
344
345 // Stop trying to connect to that device, since a connection already exists.
346 StopConnectionAttemptAndMoveToEndOfQueue(remote_device);
347 UpdateConnectionAttempts();
348 }
349
350 std::shared_ptr<BleConnectionManager::ConnectionMetadata>
351 BleConnectionManager::GetConnectionMetadata(
352 const cryptauth::RemoteDevice& remote_device) {
353 const auto map_iter = device_to_metadata_map_.find(remote_device);
354 if (map_iter == device_to_metadata_map_.end()) {
355 return nullptr;
356 }
357
358 return map_iter->second;
359 }
360
361 std::shared_ptr<BleConnectionManager::ConnectionMetadata>
362 BleConnectionManager::AddMetadataForDevice(
363 const cryptauth::RemoteDevice& remote_device) {
364 std::shared_ptr<ConnectionMetadata> existing_data =
365 GetConnectionMetadata(remote_device);
366 if (existing_data) {
367 return existing_data;
368 }
369
370 std::unique_ptr<base::Timer> timer = timer_factory_->CreateTimer();
371 device_to_metadata_map_.insert(
372 std::pair<cryptauth::RemoteDevice, std::shared_ptr<ConnectionMetadata>>(
373 remote_device,
374 std::shared_ptr<ConnectionMetadata>(
375 new ConnectionMetadata(remote_device, std::move(timer)))));
376 return device_to_metadata_map_.at(remote_device);
377 }
378
379 void BleConnectionManager::UpdateConnectionAttempts() {
380 UpdateAdvertisementQueue();
381
382 std::vector<cryptauth::RemoteDevice> should_advertise_to =
383 device_queue_->GetDevicesToWhichToAdvertise();
384 DCHECK(should_advertise_to.size() <=
385 static_cast<size_t>(kMaxConcurrentAdvertisements));
386
387 for (const auto& remote_device : should_advertise_to) {
388 std::shared_ptr<ConnectionMetadata> associated_data =
389 GetConnectionMetadata(remote_device);
390 if (!associated_data->IsActivelyConnecting()) {
391 // If there is no active attempt to connect to a device at the front of
392 // the queue, start a connection attempt.
393 StartConnectionAttempt(remote_device);
394 }
395 }
396 }
397
398 void BleConnectionManager::UpdateAdvertisementQueue() {
399 std::vector<cryptauth::RemoteDevice> devices_for_queue;
400 for (const auto& map_entry : device_to_metadata_map_) {
401 if (map_entry.second->HasEstablishedConnection()) {
402 // If there is already an active connection to the device, there is no
403 // need to advertise to the device to bootstrap a connection.
404 continue;
405 }
406
407 devices_for_queue.push_back(map_entry.first);
408 }
409
410 device_queue_->SetDevices(devices_for_queue);
411 }
412
413 void BleConnectionManager::StartConnectionAttempt(
414 const cryptauth::RemoteDevice& remote_device) {
415 std::shared_ptr<ConnectionMetadata> data =
416 GetConnectionMetadata(remote_device);
417 DCHECK(data);
418
419 PA_LOG(INFO) << "Starting connection attempt to device with ID "
420 << remote_device.GetTruncatedDeviceIdForLogs();
421
422 // Send a "disconnected => connecting" update to alert clients that a
423 // connection attempt for |remote_device| is underway.
424 SendSecureChannelStatusChangeEvent(
425 remote_device, cryptauth::SecureChannel::Status::DISCONNECTED,
426 cryptauth::SecureChannel::Status::CONNECTING);
427
428 bool success = ble_scanner_->RegisterScanFilterForDevice(remote_device) &&
429 ble_advertiser_->StartAdvertisingToDevice(remote_device);
430
431 data->StartConnectionAttemptTimeout(
Ryan Hansberry 2017/02/15 18:56:02 As discussed please add a comment on why we are st
Kyle Horimoto 2017/02/15 22:24:14 Done.
432 base::Bind(&BleConnectionManager::OnConnectionAttemptTimeout,
433 weak_ptr_factory_.GetWeakPtr()),
434 !success);
435 }
436
437 void BleConnectionManager::StopConnectionAttemptAndMoveToEndOfQueue(
438 const cryptauth::RemoteDevice& remote_device) {
439 PA_LOG(INFO) << "Stopping connection attempt to device with ID "
440 << remote_device.GetTruncatedDeviceIdForLogs();
441
442 ble_scanner_->UnregisterScanFilterForDevice(remote_device);
443 ble_advertiser_->StopAdvertisingToDevice(remote_device);
444
445 device_queue_->MoveDeviceToEnd(remote_device.GetDeviceId());
446 }
447
448 void BleConnectionManager::OnConnectionAttemptTimeout(
449 const cryptauth::RemoteDevice& remote_device) {
450 PA_LOG(INFO) << "Connection attempt timed out for device with ID "
451 << remote_device.GetTruncatedDeviceIdForLogs();
452
453 StopConnectionAttemptAndMoveToEndOfQueue(remote_device);
454
455 // Send a "connecting => disconnected" update to alert clients that a
456 // connection attempt for |remote_device| has failed.
457 SendSecureChannelStatusChangeEvent(
458 remote_device, cryptauth::SecureChannel::Status::CONNECTING,
459 cryptauth::SecureChannel::Status::DISCONNECTED);
460
461 UpdateConnectionAttempts();
462 }
463
464 void BleConnectionManager::OnSecureChannelStatusChanged(
465 const cryptauth::RemoteDevice& remote_device,
466 const cryptauth::SecureChannel::Status& old_status,
467 const cryptauth::SecureChannel::Status& new_status) {
468 SendSecureChannelStatusChangeEvent(remote_device, old_status, new_status);
469 UpdateConnectionAttempts();
470 }
471
472 void BleConnectionManager::SendMessageReceivedEvent(
473 const cryptauth::RemoteDevice& remote_device,
474 const std::string& payload) {
475 PA_LOG(INFO) << "Broadcasting message received event: "
476 << "Device ID \"" << remote_device.GetTruncatedDeviceIdForLogs()
477 << "\" received message \"" << payload << "\".";
478 for (auto& observer : observer_list_) {
479 observer.OnMessageReceived(remote_device, payload);
480 }
481 }
482
483 void BleConnectionManager::SendSecureChannelStatusChangeEvent(
484 const cryptauth::RemoteDevice& remote_device,
485 const cryptauth::SecureChannel::Status& old_status,
486 const cryptauth::SecureChannel::Status& new_status) {
487 PA_LOG(INFO) << "Broadcasting status change event: "
488 << "Device ID \"" << remote_device.GetTruncatedDeviceIdForLogs()
489 << "\": " << cryptauth::SecureChannel::StatusToString(old_status)
490 << " => "
491 << cryptauth::SecureChannel::StatusToString(new_status);
492 for (auto& observer : observer_list_) {
493 observer.OnSecureChannelStatusChanged(remote_device, old_status,
494 new_status);
495 }
496 }
497
498 } // namespace tether
499
500 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698