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

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 kAdvertisingTimeoutMillis = 12000;
19 const int64_t kShortErrorTimeoutMillis = 100;
Ryan Hansberry 2017/02/16 19:29:35 Didn't we agree to make this 0?
Kyle Horimoto 2017/02/17 01:06:52 Done.
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 base::WeakPtr<BleConnectionManager> manager)
43 : remote_device_(remote_device),
44 connection_attempt_timeout_timer_(timer),
45 manager_(manager),
46 weak_ptr_factory_(this) {}
47
48 BleConnectionManager::ConnectionMetadata::~ConnectionMetadata() {}
49
50 void BleConnectionManager::ConnectionMetadata::RegisterConnectionReason(
51 const MessageType& connection_reason) {
52 active_connection_reasons_.insert(connection_reason);
53 }
54
55 void BleConnectionManager::ConnectionMetadata::UnregisterConnectionReason(
56 const MessageType& connection_reason) {
57 active_connection_reasons_.erase(connection_reason);
58 }
59
60 bool BleConnectionManager::ConnectionMetadata::HasReasonForConnection() const {
61 return !active_connection_reasons_.empty();
62 }
63
64 bool BleConnectionManager::ConnectionMetadata::HasEstablishedConnection()
65 const {
66 return secure_channel_.get();
67 }
68
69 cryptauth::SecureChannel::Status
70 BleConnectionManager::ConnectionMetadata::GetStatus() const {
Ryan Hansberry 2017/02/16 19:29:35 Why not always return secure_channel's status unle
Kyle Horimoto 2017/02/17 01:06:52 If the ConnectionMetadata is associated with a dev
Ryan Hansberry 2017/02/17 01:59:05 Got it. Please add a brief comment explaining that
Kyle Horimoto 2017/02/17 02:08:52 Done.
71 if (connection_attempt_timeout_timer_->IsRunning()) {
72 return cryptauth::SecureChannel::Status::CONNECTING;
73 } else if (!HasEstablishedConnection()) {
74 return cryptauth::SecureChannel::Status::DISCONNECTED;
75 }
76
77 return secure_channel_->status();
78 }
79
80 void BleConnectionManager::ConnectionMetadata::StartConnectionAttemptTimer(
81 bool use_short_error_timeout) {
82 DCHECK(!secure_channel_);
83 DCHECK(!connection_attempt_timeout_timer_->IsRunning());
84
85 int64_t timeout_millis = use_short_error_timeout ? kShortErrorTimeoutMillis
86 : kAdvertisingTimeoutMillis;
87
88 connection_attempt_timeout_timer_->Start(
89 FROM_HERE, base::TimeDelta::FromMilliseconds(timeout_millis),
90 base::Bind(&ConnectionMetadata::OnConnectionAttemptTimeout,
91 weak_ptr_factory_.GetWeakPtr()));
92 }
93
94 void BleConnectionManager::ConnectionMetadata::OnConnectionAttemptTimeout() {
95 manager_->OnConnectionAttemptTimeout(remote_device_);
96 }
97
98 void BleConnectionManager::ConnectionMetadata::SetSecureChannel(
99 std::unique_ptr<cryptauth::SecureChannel> secure_channel) {
100 DCHECK(!secure_channel_);
101
102 // The connection has succeeded, so cancel the timeout.
103 connection_attempt_timeout_timer_->Stop();
104
105 secure_channel_ = std::move(secure_channel);
106 secure_channel_->AddObserver(this);
107 secure_channel_->Initialize();
108 }
109
110 void BleConnectionManager::ConnectionMetadata::SendMessage(
111 const std::string& payload) {
112 DCHECK(GetStatus() == cryptauth::SecureChannel::Status::AUTHENTICATED);
113 secure_channel_->SendMessage(std::string(kTetherFeature), payload);
114 }
115
116 void BleConnectionManager::ConnectionMetadata::OnSecureChannelStatusChanged(
117 cryptauth::SecureChannel* secure_channel,
118 const cryptauth::SecureChannel::Status& old_status,
119 const cryptauth::SecureChannel::Status& new_status) {
120 DCHECK(secure_channel_.get() == secure_channel);
121
122 if (new_status == cryptauth::SecureChannel::Status::CONNECTING) {
123 // BleConnectionManager already broadcasts "disconnected => connecting"
124 // status updates when a connection attempt begins, so there is no need to
125 // handle this case.
126 return;
127 }
128
129 if (new_status == cryptauth::SecureChannel::Status::DISCONNECTED) {
130 secure_channel_->RemoveObserver(this);
131 secure_channel_.reset();
132
133 manager_->OnSecureChannelStatusChanged(
134 remote_device_, old_status,
135 cryptauth::SecureChannel::Status::DISCONNECTED);
136 return;
Ryan Hansberry 2017/02/16 19:29:35 returning early is unnecessary. let it fall throug
Kyle Horimoto 2017/02/17 01:06:52 Done.
137 }
138
139 manager_->OnSecureChannelStatusChanged(remote_device_, old_status,
140 new_status);
141 }
142
143 void BleConnectionManager::ConnectionMetadata::OnMessageReceived(
144 cryptauth::SecureChannel* secure_channel,
145 const std::string& feature,
146 const std::string& payload) {
147 DCHECK(secure_channel_.get() == secure_channel);
148 if (feature != std::string(kTetherFeature)) {
149 // If the message received was not a tether feature, ignore it.
150 return;
151 }
152
153 manager_->SendMessageReceivedEvent(remote_device_, payload);
154 }
155
156 std::unique_ptr<base::Timer> BleConnectionManager::TimerFactory::CreateTimer() {
157 return base::MakeUnique<base::OneShotTimer>();
158 }
159
160 BleConnectionManager::BleConnectionManager(
161 std::unique_ptr<Delegate> delegate,
162 scoped_refptr<device::BluetoothAdapter> adapter,
163 const LocalDeviceDataProvider* local_device_data_provider,
164 const cryptauth::RemoteBeaconSeedFetcher* remote_beacon_seed_fetcher,
165 cryptauth::BluetoothThrottler* bluetooth_throttler)
166 : BleConnectionManager(
167 std::move(delegate),
168 adapter,
169 // TODO(khorimoto): Inject |adapter| into |BleScanner|.
170 base::MakeUnique<BleScanner>(local_device_data_provider),
171 base::MakeUnique<BleAdvertiser>(adapter,
172 local_device_data_provider,
173 remote_beacon_seed_fetcher),
174 base::MakeUnique<BleAdvertisementDeviceQueue>(),
175 base::WrapUnique<TimerFactory>(new TimerFactory()),
176 bluetooth_throttler) {}
177
178 BleConnectionManager::BleConnectionManager(
179 std::unique_ptr<Delegate> delegate,
180 scoped_refptr<device::BluetoothAdapter> adapter,
181 std::unique_ptr<BleScanner> ble_scanner,
182 std::unique_ptr<BleAdvertiser> ble_advertiser,
183 std::unique_ptr<BleAdvertisementDeviceQueue> device_queue,
184 std::unique_ptr<TimerFactory> timer_factory,
185 cryptauth::BluetoothThrottler* bluetooth_throttler)
186 : delegate_(std::move(delegate)),
187 adapter_(adapter),
188 ble_scanner_(std::move(ble_scanner)),
189 ble_advertiser_(std::move(ble_advertiser)),
190 device_queue_(std::move(device_queue)),
191 timer_factory_(std::move(timer_factory)),
192 bluetooth_throttler_(bluetooth_throttler),
193 weak_ptr_factory_(this) {
194 ble_scanner_->AddObserver(this);
195 }
196
197 BleConnectionManager::~BleConnectionManager() {
198 ble_scanner_->RemoveObserver(this);
199 }
200
201 void BleConnectionManager::RegisterRemoteDevice(
202 const cryptauth::RemoteDevice& remote_device,
203 const MessageType& connection_reason) {
204 PA_LOG(INFO) << "Registering device with ID "
205 << remote_device.GetTruncatedDeviceIdForLogs() << " for reason "
206 << MessageTypeToString(connection_reason);
207
208 std::shared_ptr<ConnectionMetadata> data =
209 GetConnectionMetadata(remote_device);
210 if (!data) {
211 data = AddMetadataForDevice(remote_device);
212 }
213
214 data->RegisterConnectionReason(connection_reason);
215 UpdateConnectionAttempts();
216 }
217
218 void BleConnectionManager::UnregisterRemoteDevice(
219 const cryptauth::RemoteDevice& remote_device,
220 const MessageType& connection_reason) {
221 PA_LOG(INFO) << "Unregistering device with ID "
222 << remote_device.GetTruncatedDeviceIdForLogs() << " for reason "
223 << MessageTypeToString(connection_reason);
224
225 std::shared_ptr<ConnectionMetadata> data =
226 GetConnectionMetadata(remote_device);
227 if (!data) {
228 // If the device was not registered, there is nothing to do.
229 return;
230 }
231
232 data->UnregisterConnectionReason(connection_reason);
233 if (!data->HasReasonForConnection()) {
234 cryptauth::SecureChannel::Status status_before_disconnect =
235 data->GetStatus();
236 device_to_metadata_map_.erase(remote_device);
237 if (status_before_disconnect ==
238 cryptauth::SecureChannel::Status::CONNECTING) {
239 StopConnectionAttemptAndMoveToEndOfQueue(remote_device);
240 }
241 if (status_before_disconnect !=
242 cryptauth::SecureChannel::Status::DISCONNECTED) {
243 // Send a status update for the disconnection.
244 SendSecureChannelStatusChangeEvent(
245 remote_device, status_before_disconnect,
246 cryptauth::SecureChannel::Status::DISCONNECTED);
247 }
248 }
249
250 UpdateConnectionAttempts();
251 }
252
253 void BleConnectionManager::SendMessage(
254 const cryptauth::RemoteDevice& remote_device,
255 const std::string& message) {
256 std::shared_ptr<ConnectionMetadata> data =
257 GetConnectionMetadata(remote_device);
258 if (!data ||
259 data->GetStatus() != cryptauth::SecureChannel::Status::AUTHENTICATED) {
260 PA_LOG(ERROR) << "Attempted to send a message to device with ID "
261 << remote_device.GetTruncatedDeviceIdForLogs() << ". "
262 << "Message: \"" << message << "\"";
263 return;
264 }
265
266 PA_LOG(INFO) << "Sending message to device with ID "
267 << remote_device.GetTruncatedDeviceIdForLogs() << ". "
268 << "Message: \"" << message << "\"";
269 data->SendMessage(message);
270 }
271
272 void BleConnectionManager::AddObserver(Observer* observer) {
273 observer_list_.AddObserver(observer);
274 }
275
276 void BleConnectionManager::RemoveObserver(Observer* observer) {
277 observer_list_.RemoveObserver(observer);
278 }
279
280 void BleConnectionManager::OnReceivedAdvertisementFromDevice(
281 const std::string& device_address,
282 cryptauth::RemoteDevice remote_device) {
283 std::shared_ptr<ConnectionMetadata> data =
284 GetConnectionMetadata(remote_device);
285 if (!data) {
286 // If an advertisement is received from a device that is not registered,
287 // ignore it.
288 PA_LOG(WARNING) << "Received an advertisement from a device which is not "
289 << "registered. Bluetooth address: " << device_address
290 << ", Remote Device ID: " << remote_device.GetDeviceId();
291 return;
292 }
293
294 PA_LOG(INFO) << "Received advertisement from device with ID "
295 << remote_device.GetTruncatedDeviceIdForLogs() << ". "
296 << "Starting authentication handshake to that device.";
297
298 // Create a connection to that device.
299 std::unique_ptr<cryptauth::Connection> connection =
300 cryptauth::weave::BluetoothLowEnergyWeaveClientConnection::Factory::
301 NewInstance(remote_device, device_address, adapter_,
302 device::BluetoothUUID(std::string(kGattServerUuid)),
303 bluetooth_throttler_);
304 PA_LOG(INFO) << "3 " << connection.get();
Ryan Hansberry 2017/02/16 19:29:35 Are these leftover debug logs?
Kyle Horimoto 2017/02/17 01:06:52 Yes; removed.
305 std::unique_ptr<cryptauth::SecureChannel> secure_channel =
306 cryptauth::SecureChannel::Factory::NewInstance(
307 std::move(connection), delegate_->CreateSecureChannelDelegate());
308 PA_LOG(INFO) << "4 " << secure_channel.get();
309 data->SetSecureChannel(std::move(secure_channel));
310
311 // Stop trying to connect to that device, since a connection already exists.
312 StopConnectionAttemptAndMoveToEndOfQueue(remote_device);
313 UpdateConnectionAttempts();
314 }
315
316 std::shared_ptr<BleConnectionManager::ConnectionMetadata>
317 BleConnectionManager::GetConnectionMetadata(
318 const cryptauth::RemoteDevice& remote_device) {
319 const auto map_iter = device_to_metadata_map_.find(remote_device);
320 if (map_iter == device_to_metadata_map_.end()) {
321 return nullptr;
322 }
323
324 return map_iter->second;
325 }
326
327 std::shared_ptr<BleConnectionManager::ConnectionMetadata>
328 BleConnectionManager::AddMetadataForDevice(
329 const cryptauth::RemoteDevice& remote_device) {
330 std::shared_ptr<ConnectionMetadata> existing_data =
331 GetConnectionMetadata(remote_device);
332 if (existing_data) {
333 return existing_data;
334 }
335
336 std::unique_ptr<base::Timer> timer = timer_factory_->CreateTimer();
337 device_to_metadata_map_.insert(
338 std::pair<cryptauth::RemoteDevice, std::shared_ptr<ConnectionMetadata>>(
339 remote_device,
340 std::shared_ptr<ConnectionMetadata>(
341 new ConnectionMetadata(remote_device, std::move(timer),
342 weak_ptr_factory_.GetWeakPtr()))));
343 return device_to_metadata_map_.at(remote_device);
344 }
345
346 void BleConnectionManager::UpdateConnectionAttempts() {
347 UpdateAdvertisementQueue();
348
349 std::vector<cryptauth::RemoteDevice> should_advertise_to =
350 device_queue_->GetDevicesToWhichToAdvertise();
351 DCHECK(should_advertise_to.size() <=
352 static_cast<size_t>(kMaxConcurrentAdvertisements));
353
354 for (const auto& remote_device : should_advertise_to) {
355 std::shared_ptr<ConnectionMetadata> associated_data =
356 GetConnectionMetadata(remote_device);
357 if (associated_data->GetStatus() !=
358 cryptauth::SecureChannel::Status::CONNECTING) {
359 // If there is no active attempt to connect to a device at the front of
360 // the queue, start a connection attempt.
361 StartConnectionAttempt(remote_device);
362 }
363 }
364 }
365
366 void BleConnectionManager::UpdateAdvertisementQueue() {
367 std::vector<cryptauth::RemoteDevice> devices_for_queue;
368 for (const auto& map_entry : device_to_metadata_map_) {
369 if (map_entry.second->HasEstablishedConnection()) {
370 // If there is already an active connection to the device, there is no
371 // need to advertise to the device to bootstrap a connection.
372 continue;
373 }
374
375 devices_for_queue.push_back(map_entry.first);
376 }
377
378 device_queue_->SetDevices(devices_for_queue);
379 }
380
381 void BleConnectionManager::StartConnectionAttempt(
382 const cryptauth::RemoteDevice& remote_device) {
383 std::shared_ptr<ConnectionMetadata> data =
384 GetConnectionMetadata(remote_device);
385 DCHECK(data);
386
387 PA_LOG(INFO) << "Starting connection attempt to device with ID "
388 << remote_device.GetTruncatedDeviceIdForLogs();
389
390 // Send a "disconnected => connecting" update to alert clients that a
391 // connection attempt for |remote_device| is underway.
392 SendSecureChannelStatusChangeEvent(
393 remote_device, cryptauth::SecureChannel::Status::DISCONNECTED,
394 cryptauth::SecureChannel::Status::CONNECTING);
395
396 bool success = ble_scanner_->RegisterScanFilterForDevice(remote_device) &&
397 ble_advertiser_->StartAdvertisingToDevice(remote_device);
398
399 // Start a timer; if a connection is unable to be created before the timer
400 // fires, a timeout occurs. Note that if this class is unable to start both
401 // the scanner and advertiser successfully (i.e., |success| is |false|), a
402 // short error timeout is set instead of the full timeout, which has the
403 // effect of quickly sending out "disconnected => connecting => disconnecting"
404 // status updates. A short timeout is used here instead of a special case in
405 // order to route all connection failures through the same code path.
406 data->StartConnectionAttemptTimer(/* use_short_error_timeout */ !success);
Ryan Hansberry 2017/02/16 19:29:35 The param comment should come after the param.
Kyle Horimoto 2017/02/17 01:06:52 Done.
407 }
408
409 void BleConnectionManager::StopConnectionAttemptAndMoveToEndOfQueue(
410 const cryptauth::RemoteDevice& remote_device) {
411 PA_LOG(INFO) << "Stopping connection attempt to device with ID "
412 << remote_device.GetTruncatedDeviceIdForLogs();
413
414 ble_scanner_->UnregisterScanFilterForDevice(remote_device);
415 ble_advertiser_->StopAdvertisingToDevice(remote_device);
416
417 device_queue_->MoveDeviceToEnd(remote_device.GetDeviceId());
418 }
419
420 void BleConnectionManager::OnConnectionAttemptTimeout(
421 const cryptauth::RemoteDevice& remote_device) {
422 PA_LOG(INFO) << "Connection attempt timed out for device with ID "
423 << remote_device.GetTruncatedDeviceIdForLogs();
424
425 StopConnectionAttemptAndMoveToEndOfQueue(remote_device);
426
427 // Send a "connecting => disconnected" update to alert clients that a
428 // connection attempt for |remote_device| has failed.
429 SendSecureChannelStatusChangeEvent(
430 remote_device, cryptauth::SecureChannel::Status::CONNECTING,
431 cryptauth::SecureChannel::Status::DISCONNECTED);
432
433 UpdateConnectionAttempts();
434 }
435
436 void BleConnectionManager::OnSecureChannelStatusChanged(
437 const cryptauth::RemoteDevice& remote_device,
438 const cryptauth::SecureChannel::Status& old_status,
439 const cryptauth::SecureChannel::Status& new_status) {
440 SendSecureChannelStatusChangeEvent(remote_device, old_status, new_status);
441 UpdateConnectionAttempts();
442 }
443
444 void BleConnectionManager::SendMessageReceivedEvent(
445 const cryptauth::RemoteDevice& remote_device,
446 const std::string& payload) {
447 PA_LOG(INFO) << "Broadcasting message received event: "
448 << "Device ID \"" << remote_device.GetTruncatedDeviceIdForLogs()
449 << "\" received message \"" << payload << "\".";
450 for (auto& observer : observer_list_) {
451 observer.OnMessageReceived(remote_device, payload);
452 }
453 }
454
455 void BleConnectionManager::SendSecureChannelStatusChangeEvent(
456 const cryptauth::RemoteDevice& remote_device,
457 const cryptauth::SecureChannel::Status& old_status,
458 const cryptauth::SecureChannel::Status& new_status) {
459 PA_LOG(INFO) << "Broadcasting status change event: "
460 << "Device ID \"" << remote_device.GetTruncatedDeviceIdForLogs()
461 << "\": " << cryptauth::SecureChannel::StatusToString(old_status)
462 << " => "
463 << cryptauth::SecureChannel::StatusToString(new_status);
464 for (auto& observer : observer_list_) {
465 observer.OnSecureChannelStatusChanged(remote_device, old_status,
466 new_status);
467 }
468 }
469
470 } // namespace tether
471
472 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698