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/message_transfer_operation.h"
6 
7 #include <memory>
8 #include <set>
9 
10 #include "base/bind.h"
11 #include "chromeos/components/multidevice/logging/logging.h"
12 #include "chromeos/components/tether/message_wrapper.h"
13 #include "chromeos/components/tether/timer_factory.h"
14 
15 namespace chromeos {
16 
17 namespace tether {
18 
19 namespace {
20 
21 const char kTetherFeature[] = "magic_tether";
22 
RemoveDuplicatesFromVector(const multidevice::RemoteDeviceRefList & remote_devices)23 multidevice::RemoteDeviceRefList RemoveDuplicatesFromVector(
24     const multidevice::RemoteDeviceRefList& remote_devices) {
25   multidevice::RemoteDeviceRefList updated_remote_devices;
26   std::set<multidevice::RemoteDeviceRef> remote_devices_set;
27   for (const auto& remote_device : remote_devices) {
28     // Only add the device to the output vector if it has not already been put
29     // into the set.
30     if (remote_devices_set.find(remote_device) == remote_devices_set.end()) {
31       remote_devices_set.insert(remote_device);
32       updated_remote_devices.push_back(remote_device);
33     }
34   }
35   return updated_remote_devices;
36 }
37 
38 }  // namespace
39 
ConnectionAttemptDelegate(MessageTransferOperation * operation,multidevice::RemoteDeviceRef remote_device,std::unique_ptr<secure_channel::ConnectionAttempt> connection_attempt)40 MessageTransferOperation::ConnectionAttemptDelegate::ConnectionAttemptDelegate(
41     MessageTransferOperation* operation,
42     multidevice::RemoteDeviceRef remote_device,
43     std::unique_ptr<secure_channel::ConnectionAttempt> connection_attempt)
44     : operation_(operation),
45       remote_device_(remote_device),
46       connection_attempt_(std::move(connection_attempt)) {
47   connection_attempt_->SetDelegate(this);
48 }
49 
50 MessageTransferOperation::ConnectionAttemptDelegate::
51     ~ConnectionAttemptDelegate() = default;
52 
53 void MessageTransferOperation::ConnectionAttemptDelegate::
OnConnectionAttemptFailure(secure_channel::mojom::ConnectionAttemptFailureReason reason)54     OnConnectionAttemptFailure(
55         secure_channel::mojom::ConnectionAttemptFailureReason reason) {
56   operation_->OnConnectionAttemptFailure(remote_device_, reason);
57 }
58 
OnConnection(std::unique_ptr<secure_channel::ClientChannel> channel)59 void MessageTransferOperation::ConnectionAttemptDelegate::OnConnection(
60     std::unique_ptr<secure_channel::ClientChannel> channel) {
61   operation_->OnConnection(remote_device_, std::move(channel));
62 }
63 
ClientChannelObserver(MessageTransferOperation * operation,multidevice::RemoteDeviceRef remote_device,std::unique_ptr<secure_channel::ClientChannel> client_channel)64 MessageTransferOperation::ClientChannelObserver::ClientChannelObserver(
65     MessageTransferOperation* operation,
66     multidevice::RemoteDeviceRef remote_device,
67     std::unique_ptr<secure_channel::ClientChannel> client_channel)
68     : operation_(operation),
69       remote_device_(remote_device),
70       client_channel_(std::move(client_channel)) {
71   client_channel_->AddObserver(this);
72 }
73 
~ClientChannelObserver()74 MessageTransferOperation::ClientChannelObserver::~ClientChannelObserver() {
75   client_channel_->RemoveObserver(this);
76 }
77 
OnDisconnected()78 void MessageTransferOperation::ClientChannelObserver::OnDisconnected() {
79   operation_->OnDisconnected(remote_device_);
80 }
81 
OnMessageReceived(const std::string & payload)82 void MessageTransferOperation::ClientChannelObserver::OnMessageReceived(
83     const std::string& payload) {
84   operation_->OnMessageReceived(remote_device_.GetDeviceId(), payload);
85 }
86 
MessageTransferOperation(const multidevice::RemoteDeviceRefList & devices_to_connect,secure_channel::ConnectionPriority connection_priority,device_sync::DeviceSyncClient * device_sync_client,secure_channel::SecureChannelClient * secure_channel_client)87 MessageTransferOperation::MessageTransferOperation(
88     const multidevice::RemoteDeviceRefList& devices_to_connect,
89     secure_channel::ConnectionPriority connection_priority,
90     device_sync::DeviceSyncClient* device_sync_client,
91     secure_channel::SecureChannelClient* secure_channel_client)
92     : remote_devices_(RemoveDuplicatesFromVector(devices_to_connect)),
93       device_sync_client_(device_sync_client),
94       secure_channel_client_(secure_channel_client),
95       connection_priority_(connection_priority),
96       timer_factory_(std::make_unique<TimerFactory>()) {}
97 
~MessageTransferOperation()98 MessageTransferOperation::~MessageTransferOperation() {
99   // If initialization never occurred, devices were never registered.
100   if (!initialized_)
101     return;
102 
103   shutting_down_ = true;
104 
105   // Unregister any devices that are still registered; otherwise, Bluetooth
106   // connections will continue to stay alive until the Tether component is shut
107   // down (see crbug.com/761106). Note that a copy of |remote_devices_| is used
108   // here because UnregisterDevice() will modify |remote_devices_| internally.
109   multidevice::RemoteDeviceRefList remote_devices_copy = remote_devices_;
110   for (const auto& remote_device : remote_devices_copy)
111     UnregisterDevice(remote_device);
112 }
113 
Initialize()114 void MessageTransferOperation::Initialize() {
115   if (initialized_) {
116     return;
117   }
118   initialized_ = true;
119 
120   // Store the message type for this connection as a private field. This is
121   // necessary because when UnregisterDevice() is called in the destructor, the
122   // derived class has already been destroyed, so invoking
123   // GetMessageTypeForConnection() will fail due to it being a pure virtual
124   // function at that time.
125   message_type_for_connection_ = GetMessageTypeForConnection();
126 
127   OnOperationStarted();
128 
129   for (const auto& remote_device : remote_devices_) {
130     StartConnectionTimerForDevice(remote_device);
131     remote_device_to_connection_attempt_delegate_map_[remote_device] =
132         std::make_unique<ConnectionAttemptDelegate>(
133             this, remote_device,
134             secure_channel_client_->ListenForConnectionFromDevice(
135                 remote_device, *device_sync_client_->GetLocalDeviceMetadata(),
136                 kTetherFeature,
137                 secure_channel::ConnectionMedium::kBluetoothLowEnergy,
138                 connection_priority_));
139   }
140 }
141 
OnMessageReceived(const std::string & device_id,const std::string & payload)142 void MessageTransferOperation::OnMessageReceived(const std::string& device_id,
143                                                  const std::string& payload) {
144   base::Optional<multidevice::RemoteDeviceRef> remote_device =
145       GetRemoteDevice(device_id);
146   if (!remote_device) {
147     // If the device from which the message has been received does not
148     // correspond to any of the devices passed to this MessageTransferOperation
149     // instance, ignore the message.
150     return;
151   }
152 
153   std::unique_ptr<MessageWrapper> message_wrapper =
154       MessageWrapper::FromRawMessage(payload);
155   if (message_wrapper) {
156     OnMessageReceived(std::move(message_wrapper), *remote_device);
157   }
158 }
159 
UnregisterDevice(multidevice::RemoteDeviceRef remote_device)160 void MessageTransferOperation::UnregisterDevice(
161     multidevice::RemoteDeviceRef remote_device) {
162   // Note: This function may be called from the destructor. It is invalid to
163   // invoke any virtual methods if |shutting_down_| is true.
164 
165   // Make a copy of |remote_device| before continuing, since the code below may
166   // cause the original reference to be deleted.
167   multidevice::RemoteDeviceRef remote_device_copy = remote_device;
168 
169   remote_devices_.erase(std::remove(remote_devices_.begin(),
170                                     remote_devices_.end(), remote_device_copy),
171                         remote_devices_.end());
172   StopTimerForDeviceIfRunning(remote_device_copy);
173 
174   remote_device_to_connection_attempt_delegate_map_.erase(remote_device);
175 
176   if (base::Contains(remote_device_to_client_channel_observer_map_,
177                      remote_device)) {
178     remote_device_to_client_channel_observer_map_.erase(remote_device);
179   }
180 
181   if (!shutting_down_ && remote_devices_.empty())
182     OnOperationFinished();
183 }
184 
SendMessageToDevice(multidevice::RemoteDeviceRef remote_device,std::unique_ptr<MessageWrapper> message_wrapper)185 int MessageTransferOperation::SendMessageToDevice(
186     multidevice::RemoteDeviceRef remote_device,
187     std::unique_ptr<MessageWrapper> message_wrapper) {
188   DCHECK(base::Contains(remote_device_to_client_channel_observer_map_,
189                         remote_device));
190   int sequence_number = next_message_sequence_number_++;
191   bool success =
192       remote_device_to_client_channel_observer_map_[remote_device]
193           ->channel()
194           ->SendMessage(
195               message_wrapper->ToRawMessage(),
196               base::BindOnce(&MessageTransferOperation::OnMessageSent,
197                              weak_ptr_factory_.GetWeakPtr(), sequence_number));
198   return success ? sequence_number : -1;
199 }
200 
GetMessageTimeoutSeconds()201 uint32_t MessageTransferOperation::GetMessageTimeoutSeconds() {
202   return MessageTransferOperation::kDefaultMessageTimeoutSeconds;
203 }
204 
OnConnectionAttemptFailure(multidevice::RemoteDeviceRef remote_device,secure_channel::mojom::ConnectionAttemptFailureReason reason)205 void MessageTransferOperation::OnConnectionAttemptFailure(
206     multidevice::RemoteDeviceRef remote_device,
207     secure_channel::mojom::ConnectionAttemptFailureReason reason) {
208   PA_LOG(WARNING) << "Failed to connect to device "
209                   << remote_device.GetTruncatedDeviceIdForLogs()
210                   << ", error: " << reason;
211   UnregisterDevice(remote_device);
212 }
213 
OnConnection(multidevice::RemoteDeviceRef remote_device,std::unique_ptr<secure_channel::ClientChannel> channel)214 void MessageTransferOperation::OnConnection(
215     multidevice::RemoteDeviceRef remote_device,
216     std::unique_ptr<secure_channel::ClientChannel> channel) {
217   remote_device_to_client_channel_observer_map_[remote_device] =
218       std::make_unique<ClientChannelObserver>(this, remote_device,
219                                               std::move(channel));
220 
221   // Stop the timer which was started from StartConnectionTimerForDevice() since
222   // the connection has now been established. Start another timer now via
223   // StartMessageTimerForDevice() while waiting for messages to be sent to and
224   // received by |remote_device|.
225   StopTimerForDeviceIfRunning(remote_device);
226   StartMessageTimerForDevice(remote_device);
227 
228   OnDeviceAuthenticated(remote_device);
229 }
230 
OnDisconnected(multidevice::RemoteDeviceRef remote_device)231 void MessageTransferOperation::OnDisconnected(
232     multidevice::RemoteDeviceRef remote_device) {
233   PA_LOG(VERBOSE) << "Remote device disconnected from this device: "
234                   << remote_device.GetTruncatedDeviceIdForLogs();
235   UnregisterDevice(remote_device);
236 }
237 
StartConnectionTimerForDevice(multidevice::RemoteDeviceRef remote_device)238 void MessageTransferOperation::StartConnectionTimerForDevice(
239     multidevice::RemoteDeviceRef remote_device) {
240   StartTimerForDevice(remote_device, kConnectionTimeoutSeconds);
241 }
242 
StartMessageTimerForDevice(multidevice::RemoteDeviceRef remote_device)243 void MessageTransferOperation::StartMessageTimerForDevice(
244     multidevice::RemoteDeviceRef remote_device) {
245   StartTimerForDevice(remote_device, GetMessageTimeoutSeconds());
246 }
247 
StartTimerForDevice(multidevice::RemoteDeviceRef remote_device,uint32_t timeout_seconds)248 void MessageTransferOperation::StartTimerForDevice(
249     multidevice::RemoteDeviceRef remote_device,
250     uint32_t timeout_seconds) {
251   PA_LOG(VERBOSE) << "Starting timer for operation with message type "
252                   << message_type_for_connection_ << " from device with ID "
253                   << remote_device.GetTruncatedDeviceIdForLogs() << ".";
254 
255   remote_device_to_timer_map_.emplace(remote_device,
256                                       timer_factory_->CreateOneShotTimer());
257   remote_device_to_timer_map_[remote_device]->Start(
258       FROM_HERE, base::TimeDelta::FromSeconds(timeout_seconds),
259       base::BindOnce(&MessageTransferOperation::OnTimeout,
260                      weak_ptr_factory_.GetWeakPtr(), remote_device));
261 }
262 
StopTimerForDeviceIfRunning(multidevice::RemoteDeviceRef remote_device)263 void MessageTransferOperation::StopTimerForDeviceIfRunning(
264     multidevice::RemoteDeviceRef remote_device) {
265   if (!remote_device_to_timer_map_[remote_device])
266     return;
267 
268   remote_device_to_timer_map_[remote_device]->Stop();
269   remote_device_to_timer_map_.erase(remote_device);
270 }
271 
OnTimeout(multidevice::RemoteDeviceRef remote_device)272 void MessageTransferOperation::OnTimeout(
273     multidevice::RemoteDeviceRef remote_device) {
274   PA_LOG(WARNING) << "Timed out operation for message type "
275                   << message_type_for_connection_ << " from device with ID "
276                   << remote_device.GetTruncatedDeviceIdForLogs() << ".";
277 
278   remote_device_to_timer_map_.erase(remote_device);
279   UnregisterDevice(remote_device);
280 }
281 
282 base::Optional<multidevice::RemoteDeviceRef>
GetRemoteDevice(const std::string & device_id)283 MessageTransferOperation::GetRemoteDevice(const std::string& device_id) {
284   for (auto& remote_device : remote_devices_) {
285     if (remote_device.GetDeviceId() == device_id)
286       return remote_device;
287   }
288 
289   return base::nullopt;
290 }
291 
SetTimerFactoryForTest(std::unique_ptr<TimerFactory> timer_factory_for_test)292 void MessageTransferOperation::SetTimerFactoryForTest(
293     std::unique_ptr<TimerFactory> timer_factory_for_test) {
294   timer_factory_ = std::move(timer_factory_for_test);
295 }
296 
297 }  // namespace tether
298 
299 }  // namespace chromeos
300