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

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 } // namespace
19
20 const int64_t BleConnectionManager::kAdvertisingTimeoutMillis = 12000;
21 const int64_t BleConnectionManager::kShortErrorTimeoutMillis = 0;
22
23 // static
24 std::string BleConnectionManager::MessageTypeToString(
25 const MessageType& reason) {
26 switch (reason) {
27 case MessageType::TETHER_AVAILABILITY_REQUEST:
28 return "[TetherAvailabilityRequest]";
29 case MessageType::CONNECT_TETHERING_REQUEST:
30 return "[ConnectTetheringRequest]";
31 case MessageType::KEEP_ALIVE_TICKLE:
32 return "[KeepAliveTickle]";
33 case MessageType::DISCONNECT_TETHERING_REQUEST:
34 return "[DisconnectTetheringRequest]";
35 default:
36 return "[invalid MessageType]";
37 }
38 }
39
40 BleConnectionManager::ConnectionMetadata::ConnectionMetadata(
41 const cryptauth::RemoteDevice remote_device,
42 std::shared_ptr<base::Timer> timer,
43 base::WeakPtr<BleConnectionManager> manager)
44 : remote_device_(remote_device),
45 connection_attempt_timeout_timer_(timer),
46 manager_(manager),
47 weak_ptr_factory_(this) {}
48
49 BleConnectionManager::ConnectionMetadata::~ConnectionMetadata() {}
50
51 void BleConnectionManager::ConnectionMetadata::RegisterConnectionReason(
52 const MessageType& connection_reason) {
53 active_connection_reasons_.insert(connection_reason);
54 }
55
56 void BleConnectionManager::ConnectionMetadata::UnregisterConnectionReason(
57 const MessageType& connection_reason) {
58 active_connection_reasons_.erase(connection_reason);
59 }
60
61 bool BleConnectionManager::ConnectionMetadata::HasReasonForConnection() const {
62 return !active_connection_reasons_.empty();
63 }
64
65 bool BleConnectionManager::ConnectionMetadata::HasEstablishedConnection()
66 const {
67 return secure_channel_.get();
68 }
69
70 cryptauth::SecureChannel::Status
71 BleConnectionManager::ConnectionMetadata::GetStatus() const {
72 if (connection_attempt_timeout_timer_->IsRunning()) {
73 return cryptauth::SecureChannel::Status::CONNECTING;
74 } else if (!HasEstablishedConnection()) {
75 return cryptauth::SecureChannel::Status::DISCONNECTED;
76 }
77
78 return secure_channel_->status();
79 }
80
81 void BleConnectionManager::ConnectionMetadata::StartConnectionAttemptTimer(
82 bool use_short_error_timeout) {
83 DCHECK(!secure_channel_);
84 DCHECK(!connection_attempt_timeout_timer_->IsRunning());
85
86 int64_t timeout_millis = use_short_error_timeout ? kShortErrorTimeoutMillis
87 : kAdvertisingTimeoutMillis;
88
89 connection_attempt_timeout_timer_->Start(
90 FROM_HERE, base::TimeDelta::FromMilliseconds(timeout_millis),
91 base::Bind(&ConnectionMetadata::OnConnectionAttemptTimeout,
92 weak_ptr_factory_.GetWeakPtr()));
93 }
94
95 void BleConnectionManager::ConnectionMetadata::OnConnectionAttemptTimeout() {
96 manager_->OnConnectionAttemptTimeout(remote_device_);
97 }
98
99 void BleConnectionManager::ConnectionMetadata::SetSecureChannel(
100 std::unique_ptr<cryptauth::SecureChannel> secure_channel) {
101 DCHECK(!secure_channel_);
102
103 // The connection has succeeded, so cancel the timeout.
104 connection_attempt_timeout_timer_->Stop();
105
106 secure_channel_ = std::move(secure_channel);
107 secure_channel_->AddObserver(this);
108 secure_channel_->Initialize();
109 }
110
111 void BleConnectionManager::ConnectionMetadata::SendMessage(
112 const std::string& payload) {
113 DCHECK(GetStatus() == cryptauth::SecureChannel::Status::AUTHENTICATED);
114 secure_channel_->SendMessage(std::string(kTetherFeature), payload);
115 }
116
117 void BleConnectionManager::ConnectionMetadata::OnSecureChannelStatusChanged(
118 cryptauth::SecureChannel* secure_channel,
119 const cryptauth::SecureChannel::Status& old_status,
120 const cryptauth::SecureChannel::Status& new_status) {
121 DCHECK(secure_channel_.get() == secure_channel);
122
123 if (new_status == cryptauth::SecureChannel::Status::CONNECTING) {
124 // BleConnectionManager already broadcasts "disconnected => connecting"
125 // status updates when a connection attempt begins, so there is no need to
126 // handle this case.
127 return;
128 }
129
130 // Make a copy of the two statuses. If |secure_channel_.reset()| is called
131 // below, the SecureChannel instance will be destroyed and |old_status| and
132 // |new_status| may refer to memory which has been deleted.
133 const cryptauth::SecureChannel::Status old_status_copy = old_status;
134 const cryptauth::SecureChannel::Status new_status_copy = new_status;
135
136 if (new_status == cryptauth::SecureChannel::Status::DISCONNECTED) {
137 secure_channel_->RemoveObserver(this);
138 secure_channel_.reset();
139 }
140
141 manager_->OnSecureChannelStatusChanged(remote_device_, old_status_copy,
142 new_status_copy);
143 }
144
145 void BleConnectionManager::ConnectionMetadata::OnMessageReceived(
146 cryptauth::SecureChannel* secure_channel,
147 const std::string& feature,
148 const std::string& payload) {
149 DCHECK(secure_channel_.get() == secure_channel);
150 if (feature != std::string(kTetherFeature)) {
151 // If the message received was not a tether feature, ignore it.
152 return;
153 }
154
155 manager_->SendMessageReceivedEvent(remote_device_, payload);
156 }
157
158 std::unique_ptr<base::Timer> BleConnectionManager::TimerFactory::CreateTimer() {
159 return base::MakeUnique<base::OneShotTimer>();
160 }
161
162 BleConnectionManager::BleConnectionManager(
163 std::unique_ptr<Delegate> delegate,
164 scoped_refptr<device::BluetoothAdapter> adapter,
165 const LocalDeviceDataProvider* local_device_data_provider,
166 const cryptauth::RemoteBeaconSeedFetcher* remote_beacon_seed_fetcher,
167 cryptauth::BluetoothThrottler* bluetooth_throttler)
168 : BleConnectionManager(
169 std::move(delegate),
170 adapter,
171 // TODO(khorimoto): Inject |adapter| into |BleScanner|.
172 base::MakeUnique<BleScanner>(local_device_data_provider),
173 base::MakeUnique<BleAdvertiser>(adapter,
174 local_device_data_provider,
175 remote_beacon_seed_fetcher),
176 base::MakeUnique<BleAdvertisementDeviceQueue>(),
177 base::WrapUnique<TimerFactory>(new TimerFactory()),
178 bluetooth_throttler) {}
179
180 BleConnectionManager::BleConnectionManager(
181 std::unique_ptr<Delegate> delegate,
182 scoped_refptr<device::BluetoothAdapter> adapter,
183 std::unique_ptr<BleScanner> ble_scanner,
184 std::unique_ptr<BleAdvertiser> ble_advertiser,
185 std::unique_ptr<BleAdvertisementDeviceQueue> device_queue,
186 std::unique_ptr<TimerFactory> timer_factory,
187 cryptauth::BluetoothThrottler* bluetooth_throttler)
188 : delegate_(std::move(delegate)),
189 adapter_(adapter),
190 ble_scanner_(std::move(ble_scanner)),
191 ble_advertiser_(std::move(ble_advertiser)),
192 device_queue_(std::move(device_queue)),
193 timer_factory_(std::move(timer_factory)),
194 bluetooth_throttler_(bluetooth_throttler),
195 weak_ptr_factory_(this) {
196 ble_scanner_->AddObserver(this);
197 }
198
199 BleConnectionManager::~BleConnectionManager() {
200 ble_scanner_->RemoveObserver(this);
201 }
202
203 void BleConnectionManager::RegisterRemoteDevice(
204 const cryptauth::RemoteDevice& remote_device,
205 const MessageType& connection_reason) {
206 PA_LOG(INFO) << "Registering device with ID "
207 << remote_device.GetTruncatedDeviceIdForLogs() << " for reason "
208 << MessageTypeToString(connection_reason);
209
210 std::shared_ptr<ConnectionMetadata> data =
Ryan Hansberry 2017/02/17 01:59:05 nit: Please use the variable name 'metadata' or 'c
Kyle Horimoto 2017/02/17 02:08:52 Done.
211 GetConnectionMetadata(remote_device);
212 if (!data) {
213 data = AddMetadataForDevice(remote_device);
214 }
215
216 data->RegisterConnectionReason(connection_reason);
217 UpdateConnectionAttempts();
218 }
219
220 void BleConnectionManager::UnregisterRemoteDevice(
221 const cryptauth::RemoteDevice& remote_device,
222 const MessageType& connection_reason) {
223 PA_LOG(INFO) << "Unregistering device with ID "
224 << remote_device.GetTruncatedDeviceIdForLogs() << " for reason "
225 << MessageTypeToString(connection_reason);
226
227 std::shared_ptr<ConnectionMetadata> data =
228 GetConnectionMetadata(remote_device);
229 if (!data) {
230 // If the device was not registered, there is nothing to do.
231 return;
232 }
233
234 data->UnregisterConnectionReason(connection_reason);
235 if (!data->HasReasonForConnection()) {
236 cryptauth::SecureChannel::Status status_before_disconnect =
237 data->GetStatus();
238 device_to_metadata_map_.erase(remote_device);
239 if (status_before_disconnect ==
240 cryptauth::SecureChannel::Status::CONNECTING) {
241 StopConnectionAttemptAndMoveToEndOfQueue(remote_device);
242 }
243 if (status_before_disconnect !=
244 cryptauth::SecureChannel::Status::DISCONNECTED) {
245 // Send a status update for the disconnection.
246 SendSecureChannelStatusChangeEvent(
247 remote_device, status_before_disconnect,
248 cryptauth::SecureChannel::Status::DISCONNECTED);
249 }
250 }
251
252 UpdateConnectionAttempts();
253 }
254
255 void BleConnectionManager::SendMessage(
256 const cryptauth::RemoteDevice& remote_device,
257 const std::string& message) {
258 std::shared_ptr<ConnectionMetadata> data =
259 GetConnectionMetadata(remote_device);
260 if (!data ||
261 data->GetStatus() != cryptauth::SecureChannel::Status::AUTHENTICATED) {
262 PA_LOG(ERROR) << "Attempted to send a message to device with ID "
263 << remote_device.GetTruncatedDeviceIdForLogs() << ". "
264 << "Message: \"" << message << "\"";
265 return;
266 }
267
268 PA_LOG(INFO) << "Sending message to device with ID "
269 << remote_device.GetTruncatedDeviceIdForLogs() << ". "
270 << "Message: \"" << message << "\"";
271 data->SendMessage(message);
272 }
273
274 void BleConnectionManager::AddObserver(Observer* observer) {
275 observer_list_.AddObserver(observer);
276 }
277
278 void BleConnectionManager::RemoveObserver(Observer* observer) {
279 observer_list_.RemoveObserver(observer);
280 }
281
282 void BleConnectionManager::OnReceivedAdvertisementFromDevice(
283 const std::string& device_address,
284 cryptauth::RemoteDevice remote_device) {
285 std::shared_ptr<ConnectionMetadata> data =
286 GetConnectionMetadata(remote_device);
287 if (!data) {
288 // If an advertisement is received from a device that is not registered,
289 // ignore it.
290 PA_LOG(WARNING) << "Received an advertisement from a device which is not "
291 << "registered. Bluetooth address: " << device_address
292 << ", Remote Device ID: " << remote_device.GetDeviceId();
293 return;
294 }
295
296 PA_LOG(INFO) << "Received advertisement from device with ID "
297 << remote_device.GetTruncatedDeviceIdForLogs() << ". "
298 << "Starting authentication handshake to that device.";
299
300 // Create a connection to that device.
301 std::unique_ptr<cryptauth::Connection> connection =
302 cryptauth::weave::BluetoothLowEnergyWeaveClientConnection::Factory::
303 NewInstance(remote_device, device_address, adapter_,
304 device::BluetoothUUID(std::string(kGattServerUuid)),
305 bluetooth_throttler_);
306 std::unique_ptr<cryptauth::SecureChannel> secure_channel =
307 cryptauth::SecureChannel::Factory::NewInstance(
308 std::move(connection), delegate_->CreateSecureChannelDelegate());
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(!success /* use_short_error_timeout */);
Ryan Hansberry 2017/02/17 01:59:05 What do you think of renaming this from 'use_short
Kyle Horimoto 2017/02/17 02:08: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