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