1 // Copyright 2013 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 "remoting/client/chromoting_session.h"
6
7 #include <stdint.h>
8
9 #include <algorithm>
10 #include <utility>
11
12 #include "base/bind.h"
13 #include "base/callback.h"
14 #include "base/callback_helpers.h"
15 #include "base/format_macros.h"
16 #include "base/logging.h"
17 #include "base/single_thread_task_runner.h"
18 #include "base/task_runner_util.h"
19 #include "base/timer/timer.h"
20 #include "jingle/glue/thread_wrapper.h"
21 #include "net/socket/client_socket_factory.h"
22 #include "remoting/base/chromoting_event.h"
23 #include "remoting/base/service_urls.h"
24 #include "remoting/client/audio/audio_player.h"
25 #include "remoting/client/chromoting_client_runtime.h"
26 #include "remoting/client/client_telemetry_logger.h"
27 #include "remoting/client/input/native_device_keymap.h"
28 #include "remoting/protocol/chromium_port_allocator_factory.h"
29 #include "remoting/protocol/chromium_socket_factory.h"
30 #include "remoting/protocol/client_authentication_config.h"
31 #include "remoting/protocol/frame_consumer.h"
32 #include "remoting/protocol/host_stub.h"
33 #include "remoting/protocol/network_settings.h"
34 #include "remoting/protocol/performance_tracker.h"
35 #include "remoting/protocol/transport_context.h"
36 #include "remoting/protocol/video_renderer.h"
37 #include "remoting/signaling/ftl_client_uuid_device_id_provider.h"
38 #include "remoting/signaling/ftl_signal_strategy.h"
39 #include "remoting/signaling/server_log_entry.h"
40 #include "services/network/public/cpp/shared_url_loader_factory.h"
41 #include "ui/events/keycodes/dom/keycode_converter.h"
42
43 namespace remoting {
44
45 namespace {
46
47 // Default DPI to assume for old clients that use notifyClientResolution.
48 const int kDefaultDPI = 96;
49
50 // Used by NormalizeclientResolution. See comment below.
51 const int kMinDimension = 640;
52
53 // Interval at which to log performance statistics, if enabled.
54 constexpr base::TimeDelta kPerfStatsInterval = base::TimeDelta::FromMinutes(1);
55
56 // Delay to destroy the signal strategy, so that the session-terminate event can
57 // still be sent out.
58 constexpr base::TimeDelta kDestroySignalingDelay =
59 base::TimeDelta::FromSeconds(2);
60
IsClientResolutionValid(int dips_width,int dips_height)61 bool IsClientResolutionValid(int dips_width, int dips_height) {
62 // This prevents sending resolution on a portrait mode small phone screen
63 // because resizing the remote desktop to portrait will mess with icons and
64 // such on the desktop and it probably isn't what the user wants.
65 return (dips_width >= dips_height) || (dips_width >= kMinDimension);
66 }
67
68 // Normalizes the resolution so that both dimensions are not smaller than
69 // kMinDimension.
NormalizeClientResolution(protocol::ClientResolution * resolution)70 void NormalizeClientResolution(protocol::ClientResolution* resolution) {
71 int min_dimension =
72 std::min(resolution->dips_width(), resolution->dips_height());
73 if (min_dimension >= kMinDimension) {
74 return;
75 }
76
77 // Always scale by integer to prevent blurry interpolation.
78 int scale = std::ceil(((float)kMinDimension) / min_dimension);
79 resolution->set_dips_width(resolution->dips_width() * scale);
80 resolution->set_dips_height(resolution->dips_height() * scale);
81 }
82
83 struct SessionContext {
84 base::WeakPtr<ChromotingSession::Delegate> delegate;
85 std::unique_ptr<protocol::AudioStub> audio_player;
86 std::unique_ptr<base::WeakPtrFactory<protocol::AudioStub>>
87 audio_player_weak_factory;
88 std::unique_ptr<protocol::CursorShapeStub> cursor_shape_stub;
89 std::unique_ptr<protocol::VideoRenderer> video_renderer;
90
91 ConnectToHostInfo info;
92 };
93
94 } // namespace
95
96 class ChromotingSession::Core : public ClientUserInterface,
97 public protocol::ClipboardStub,
98 public protocol::KeyboardLayoutStub {
99 public:
100 Core(ChromotingClientRuntime* runtime,
101 std::unique_ptr<ClientTelemetryLogger> logger,
102 std::unique_ptr<SessionContext> session_context);
103 ~Core() override;
104
105 void RequestPairing(const std::string& device_name);
106 void SendMouseEvent(int x,
107 int y,
108 protocol::MouseEvent_MouseButton button,
109 bool button_down);
110 void SendMouseWheelEvent(int delta_x, int delta_y);
111 void SendKeyEvent(int usb_key_code, bool key_down);
112 void SendTextEvent(const std::string& text);
113 void SendTouchEvent(const protocol::TouchEvent& touch_event);
114 void SendClientResolution(int dips_width, int dips_height, float scale);
115 void EnableVideoChannel(bool enable);
116 void SendClientMessage(const std::string& type, const std::string& data);
117
118 // This function is still valid after Invalidate() is called.
119 std::unique_ptr<FeedbackData> GetFeedbackData();
120
121 // Logs the disconnect event and invalidates the instance.
122 void Disconnect();
123
124 // ClientUserInterface implementation.
125 void OnConnectionState(protocol::ConnectionToHost::State state,
126 protocol::ErrorCode error) override;
127 void OnConnectionReady(bool ready) override;
128 void OnRouteChanged(const std::string& channel_name,
129 const protocol::TransportRoute& route) override;
130 void SetCapabilities(const std::string& capabilities) override;
131 void SetPairingResponse(const protocol::PairingResponse& response) override;
132 void DeliverHostMessage(const protocol::ExtensionMessage& message) override;
133 void SetDesktopSize(const webrtc::DesktopSize& size,
134 const webrtc::DesktopVector& dpi) override;
135 protocol::ClipboardStub* GetClipboardStub() override;
136 protocol::CursorShapeStub* GetCursorShapeStub() override;
137 protocol::KeyboardLayoutStub* GetKeyboardLayoutStub() override;
138
139 // ClipboardStub implementation.
140 void InjectClipboardEvent(const protocol::ClipboardEvent& event) override;
141
142 // KeyboardLayoutStub implementation.
143 void SetKeyboardLayout(const protocol::KeyboardLayout& layout) override;
144
145 base::WeakPtr<Core> GetWeakPtr();
146
147 private:
148 // Destroys the client and invalidates weak pointers. This doesn't destroy the
149 // instance itself.
150 void Invalidate();
151
152 void ConnectOnNetworkThread();
153 void LogPerfStats();
154
155 // Pops up a UI to fetch the PIN.
156 void FetchSecret(
157 bool pairing_supported,
158 const protocol::SecretFetchedCallback& secret_fetched_callback);
159 void HandleOnSecretFetched(const protocol::SecretFetchedCallback& callback,
160 const std::string secret);
161
162 // Pops up a UI to fetch the third party token.
163 void FetchThirdPartyToken(
164 const std::string& host_public_key,
165 const std::string& token_url,
166 const std::string& scopes,
167 const protocol::ThirdPartyTokenFetchedCallback& token_fetched_callback);
168 void HandleOnThirdPartyTokenFetched(
169 const protocol::ThirdPartyTokenFetchedCallback& callback,
170 const std::string& token,
171 const std::string& shared_secret);
172
ui_task_runner()173 scoped_refptr<AutoThreadTaskRunner> ui_task_runner() {
174 return runtime_->ui_task_runner();
175 }
176
network_task_runner()177 scoped_refptr<AutoThreadTaskRunner> network_task_runner() {
178 return runtime_->network_task_runner();
179 }
180
181 // |runtime_| and |logger_| are stored separately from |session_context_| so
182 // that they won't be destroyed after the core is invalidated.
183 ChromotingClientRuntime* const runtime_;
184 std::unique_ptr<ClientTelemetryLogger> logger_;
185
186 std::unique_ptr<SessionContext> session_context_;
187
188 std::unique_ptr<ClientContext> client_context_;
189 std::unique_ptr<protocol::PerformanceTracker> perf_tracker_;
190
191 // |signaling_| must outlive |client_|.
192 std::unique_ptr<SignalStrategy> signaling_;
193 std::unique_ptr<OAuthTokenGetter> token_getter_;
194 std::unique_ptr<ChromotingClient> client_;
195
196 // Empty string if client doesn't request for pairing.
197 std::string device_name_for_pairing_;
198
199 // The current session state.
200 protocol::ConnectionToHost::State session_state_ =
201 protocol::ConnectionToHost::INITIALIZING;
202
203 base::RepeatingTimer perf_stats_logging_timer_;
204
205 // weak_factory_.GetWeakPtr() creates new valid WeakPtrs after
206 // weak_factory_.InvalidateWeakPtrs() is called. We store and return
207 // |weak_ptr_| in GetWeakPtr() so that its copies are still invalidated once
208 // InvalidateWeakPtrs() is called.
209 base::WeakPtr<Core> weak_ptr_;
210 base::WeakPtrFactory<Core> weak_factory_{this};
211 DISALLOW_COPY_AND_ASSIGN(Core);
212 };
213
Core(ChromotingClientRuntime * runtime,std::unique_ptr<ClientTelemetryLogger> logger,std::unique_ptr<SessionContext> session_context)214 ChromotingSession::Core::Core(ChromotingClientRuntime* runtime,
215 std::unique_ptr<ClientTelemetryLogger> logger,
216 std::unique_ptr<SessionContext> session_context)
217 : runtime_(runtime),
218 logger_(std::move(logger)),
219 session_context_(std::move(session_context)) {
220 DCHECK(ui_task_runner()->BelongsToCurrentThread());
221 DCHECK(runtime_);
222 DCHECK(logger_);
223 DCHECK(session_context_);
224
225 weak_ptr_ = weak_factory_.GetWeakPtr();
226
227 network_task_runner()->PostTask(
228 FROM_HERE, base::BindOnce(&Core::ConnectOnNetworkThread, GetWeakPtr()));
229 }
230
~Core()231 ChromotingSession::Core::~Core() {
232 DCHECK(network_task_runner()->BelongsToCurrentThread());
233
234 // Make sure we log a close event if the session has not been disconnected
235 // yet.
236 Disconnect();
237 }
238
RequestPairing(const std::string & device_name)239 void ChromotingSession::Core::RequestPairing(const std::string& device_name) {
240 DCHECK(!device_name.empty());
241 DCHECK(network_task_runner()->BelongsToCurrentThread());
242 device_name_for_pairing_ = device_name;
243 }
244
SendMouseEvent(int x,int y,protocol::MouseEvent_MouseButton button,bool button_down)245 void ChromotingSession::Core::SendMouseEvent(
246 int x,
247 int y,
248 protocol::MouseEvent_MouseButton button,
249 bool button_down) {
250 DCHECK(network_task_runner()->BelongsToCurrentThread());
251 protocol::MouseEvent event;
252 event.set_x(x);
253 event.set_y(y);
254 event.set_button(button);
255 if (button != protocol::MouseEvent::BUTTON_UNDEFINED)
256 event.set_button_down(button_down);
257
258 client_->input_stub()->InjectMouseEvent(event);
259 }
260
SendMouseWheelEvent(int delta_x,int delta_y)261 void ChromotingSession::Core::SendMouseWheelEvent(int delta_x, int delta_y) {
262 DCHECK(network_task_runner()->BelongsToCurrentThread());
263 protocol::MouseEvent event;
264 event.set_wheel_delta_x(delta_x);
265 event.set_wheel_delta_y(delta_y);
266 client_->input_stub()->InjectMouseEvent(event);
267 }
268
SendKeyEvent(int usb_key_code,bool key_down)269 void ChromotingSession::Core::SendKeyEvent(int usb_key_code, bool key_down) {
270 DCHECK(network_task_runner()->BelongsToCurrentThread());
271 protocol::KeyEvent event;
272 event.set_usb_keycode(usb_key_code);
273 event.set_pressed(key_down);
274 client_->input_stub()->InjectKeyEvent(event);
275 }
276
SendTextEvent(const std::string & text)277 void ChromotingSession::Core::SendTextEvent(const std::string& text) {
278 DCHECK(network_task_runner()->BelongsToCurrentThread());
279 protocol::TextEvent event;
280 event.set_text(text);
281 client_->input_stub()->InjectTextEvent(event);
282 }
283
SendTouchEvent(const protocol::TouchEvent & touch_event)284 void ChromotingSession::Core::SendTouchEvent(
285 const protocol::TouchEvent& touch_event) {
286 DCHECK(network_task_runner()->BelongsToCurrentThread());
287 client_->input_stub()->InjectTouchEvent(touch_event);
288 }
289
SendClientResolution(int dips_width,int dips_height,float scale)290 void ChromotingSession::Core::SendClientResolution(int dips_width,
291 int dips_height,
292 float scale) {
293 DCHECK(network_task_runner()->BelongsToCurrentThread());
294 if (!IsClientResolutionValid(dips_width, dips_height)) {
295 return;
296 }
297
298 protocol::ClientResolution client_resolution;
299 client_resolution.set_dips_width(dips_width);
300 client_resolution.set_dips_height(dips_height);
301 client_resolution.set_x_dpi(scale * kDefaultDPI);
302 client_resolution.set_y_dpi(scale * kDefaultDPI);
303 NormalizeClientResolution(&client_resolution);
304
305 // Include the legacy width & height in physical pixels for use by older
306 // hosts.
307 client_resolution.set_width_deprecated(dips_width * scale);
308 client_resolution.set_height_deprecated(dips_height * scale);
309
310 client_->host_stub()->NotifyClientResolution(client_resolution);
311 }
312
EnableVideoChannel(bool enable)313 void ChromotingSession::Core::EnableVideoChannel(bool enable) {
314 DCHECK(network_task_runner()->BelongsToCurrentThread());
315 protocol::VideoControl video_control;
316 video_control.set_enable(enable);
317 client_->host_stub()->ControlVideo(video_control);
318 }
319
SendClientMessage(const std::string & type,const std::string & data)320 void ChromotingSession::Core::SendClientMessage(const std::string& type,
321 const std::string& data) {
322 DCHECK(network_task_runner()->BelongsToCurrentThread());
323 protocol::ExtensionMessage extension_message;
324 extension_message.set_type(type);
325 extension_message.set_data(data);
326 client_->host_stub()->DeliverClientMessage(extension_message);
327 }
328
GetFeedbackData()329 std::unique_ptr<FeedbackData> ChromotingSession::Core::GetFeedbackData() {
330 DCHECK(network_task_runner()->BelongsToCurrentThread());
331
332 auto data = std::make_unique<FeedbackData>();
333 data->FillWithChromotingEvent(logger_->current_session_state_event());
334 return data;
335 }
336
Disconnect()337 void ChromotingSession::Core::Disconnect() {
338 DCHECK(network_task_runner()->BelongsToCurrentThread());
339
340 // Do not log session state change if the connection is already closed.
341 if (session_state_ != protocol::ConnectionToHost::INITIALIZING &&
342 session_state_ != protocol::ConnectionToHost::FAILED &&
343 session_state_ != protocol::ConnectionToHost::CLOSED) {
344 ChromotingEvent::SessionState session_state_to_log;
345 if (session_state_ == protocol::ConnectionToHost::CONNECTED) {
346 session_state_to_log = ChromotingEvent::SessionState::CLOSED;
347 } else {
348 session_state_to_log = ChromotingEvent::SessionState::CONNECTION_CANCELED;
349 }
350 logger_->LogSessionStateChange(session_state_to_log,
351 ChromotingEvent::ConnectionError::NONE);
352 session_state_ = protocol::ConnectionToHost::CLOSED;
353
354 // Make sure we send a session-terminate to the host.
355 client_->Close();
356
357 Invalidate();
358 }
359 }
360
OnConnectionState(protocol::ConnectionToHost::State state,protocol::ErrorCode error)361 void ChromotingSession::Core::OnConnectionState(
362 protocol::ConnectionToHost::State state,
363 protocol::ErrorCode error) {
364 DCHECK(network_task_runner()->BelongsToCurrentThread());
365
366 if (state == protocol::ConnectionToHost::CONNECTED) {
367 perf_stats_logging_timer_.Start(
368 FROM_HERE, kPerfStatsInterval,
369 base::BindRepeating(&Core::LogPerfStats, GetWeakPtr()));
370
371 if (!device_name_for_pairing_.empty()) {
372 protocol::PairingRequest request;
373 request.set_client_name(device_name_for_pairing_);
374 client_->host_stub()->RequestPairing(request);
375 }
376 } else if (perf_stats_logging_timer_.IsRunning()) {
377 perf_stats_logging_timer_.Stop();
378 }
379
380 logger_->LogSessionStateChange(
381 ClientTelemetryLogger::TranslateState(state, session_state_),
382 ClientTelemetryLogger::TranslateError(error));
383
384 session_state_ = state;
385
386 ui_task_runner()->PostTask(
387 FROM_HERE, base::BindOnce(&ChromotingSession::Delegate::OnConnectionState,
388 session_context_->delegate, state, error));
389
390 if (state == protocol::ConnectionToHost::CLOSED ||
391 state == protocol::ConnectionToHost::FAILED) {
392 Invalidate();
393 }
394 }
395
OnConnectionReady(bool ready)396 void ChromotingSession::Core::OnConnectionReady(bool ready) {
397 // We ignore this message, since OnConnectionState tells us the same thing.
398 }
399
OnRouteChanged(const std::string & channel_name,const protocol::TransportRoute & route)400 void ChromotingSession::Core::OnRouteChanged(
401 const std::string& channel_name,
402 const protocol::TransportRoute& route) {
403 DCHECK(network_task_runner()->BelongsToCurrentThread());
404 std::string message = "Channel " + channel_name + " using " +
405 protocol::TransportRoute::GetTypeString(route.type) +
406 " connection.";
407 VLOG(1) << "Route: " << message;
408 logger_->SetTransportRoute(route);
409 }
410
SetCapabilities(const std::string & capabilities)411 void ChromotingSession::Core::SetCapabilities(const std::string& capabilities) {
412 DCHECK(network_task_runner()->BelongsToCurrentThread());
413 ui_task_runner()->PostTask(
414 FROM_HERE, base::BindOnce(&ChromotingSession::Delegate::SetCapabilities,
415 session_context_->delegate, capabilities));
416 }
417
SetPairingResponse(const protocol::PairingResponse & response)418 void ChromotingSession::Core::SetPairingResponse(
419 const protocol::PairingResponse& response) {
420 DCHECK(network_task_runner()->BelongsToCurrentThread());
421 ui_task_runner()->PostTask(
422 FROM_HERE,
423 base::BindOnce(&ChromotingSession::Delegate::CommitPairingCredentials,
424 session_context_->delegate, session_context_->info.host_id,
425 response.client_id(), response.shared_secret()));
426 }
427
DeliverHostMessage(const protocol::ExtensionMessage & message)428 void ChromotingSession::Core::DeliverHostMessage(
429 const protocol::ExtensionMessage& message) {
430 DCHECK(network_task_runner()->BelongsToCurrentThread());
431 ui_task_runner()->PostTask(
432 FROM_HERE,
433 base::BindOnce(&ChromotingSession::Delegate::HandleExtensionMessage,
434 session_context_->delegate, message.type(),
435 message.data()));
436 }
437
SetDesktopSize(const webrtc::DesktopSize & size,const webrtc::DesktopVector & dpi)438 void ChromotingSession::Core::SetDesktopSize(const webrtc::DesktopSize& size,
439 const webrtc::DesktopVector& dpi) {
440 // ChromotingSession's VideoRenderer gets size from the frames and it doesn't
441 // use DPI, so this call can be ignored.
442 }
443
GetClipboardStub()444 protocol::ClipboardStub* ChromotingSession::Core::GetClipboardStub() {
445 return this;
446 }
447
GetCursorShapeStub()448 protocol::CursorShapeStub* ChromotingSession::Core::GetCursorShapeStub() {
449 return session_context_->cursor_shape_stub.get();
450 }
451
GetKeyboardLayoutStub()452 protocol::KeyboardLayoutStub* ChromotingSession::Core::GetKeyboardLayoutStub() {
453 return this;
454 }
455
InjectClipboardEvent(const protocol::ClipboardEvent & event)456 void ChromotingSession::Core::InjectClipboardEvent(
457 const protocol::ClipboardEvent& event) {
458 NOTIMPLEMENTED();
459 }
460
SetKeyboardLayout(const protocol::KeyboardLayout & layout)461 void ChromotingSession::Core::SetKeyboardLayout(
462 const protocol::KeyboardLayout& layout) {
463 NOTIMPLEMENTED();
464 }
465
GetWeakPtr()466 base::WeakPtr<ChromotingSession::Core> ChromotingSession::Core::GetWeakPtr() {
467 return weak_ptr_;
468 }
469
Invalidate()470 void ChromotingSession::Core::Invalidate() {
471 DCHECK(network_task_runner()->BelongsToCurrentThread());
472
473 // Prevent all pending and future calls from ChromotingSession.
474 weak_factory_.InvalidateWeakPtrs();
475
476 client_.reset();
477 token_getter_.reset();
478 perf_tracker_.reset();
479 client_context_.reset();
480 session_context_.reset();
481
482 // Dirty hack to make sure session-terminate message is sent before
483 // |signaling_| gets deleted. W/o the message being sent, the other side will
484 // believe an error has occurred.
485 if (signaling_) {
486 signaling_->Disconnect();
487 network_task_runner()->PostDelayedTask(
488 FROM_HERE,
489 base::BindOnce(
490 [](std::unique_ptr<SignalStrategy> signaling) {
491 signaling.reset();
492 },
493 std::move(signaling_)),
494 kDestroySignalingDelay);
495 }
496 }
497
ConnectOnNetworkThread()498 void ChromotingSession::Core::ConnectOnNetworkThread() {
499 DCHECK(network_task_runner()->BelongsToCurrentThread());
500
501 if (session_context_->info.host_ftl_id.empty()) {
502 // Simulate a CONNECTING state to make sure it doesn't skew telemetry.
503 OnConnectionState(protocol::ConnectionToHost::State::CONNECTING,
504 protocol::OK);
505 OnConnectionState(protocol::ConnectionToHost::State::FAILED,
506 protocol::INCOMPATIBLE_PROTOCOL);
507 return;
508 }
509
510 jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop();
511
512 client_context_.reset(new ClientContext(network_task_runner()));
513 client_context_->Start();
514
515 perf_tracker_.reset(new protocol::PerformanceTracker());
516
517 session_context_->video_renderer->Initialize(*client_context_,
518 perf_tracker_.get());
519 logger_->SetHostInfo(
520 session_context_->info.host_version,
521 ChromotingEvent::ParseOsFromString(session_context_->info.host_os),
522 session_context_->info.host_os_version);
523
524 // TODO(yuweih): Ideally we should make ChromotingClient and all its
525 // sub-components (e.g. ConnectionToHost) take raw pointer instead of WeakPtr.
526 client_.reset(new ChromotingClient(
527 client_context_.get(), this, session_context_->video_renderer.get(),
528 session_context_->audio_player_weak_factory->GetWeakPtr()));
529
530 signaling_ = std::make_unique<FtlSignalStrategy>(
531 runtime_->CreateOAuthTokenGetter(), runtime_->url_loader_factory(),
532 std::make_unique<FtlClientUuidDeviceIdProvider>());
533 logger_->SetSignalStrategyType(ChromotingEvent::SignalStrategyType::FTL);
534
535 token_getter_ = runtime_->CreateOAuthTokenGetter();
536
537 scoped_refptr<protocol::TransportContext> transport_context =
538 new protocol::TransportContext(
539 std::make_unique<protocol::ChromiumPortAllocatorFactory>(),
540 runtime_->url_loader_factory(),
541 protocol::NetworkSettings(
542 protocol::NetworkSettings::NAT_TRAVERSAL_FULL),
543 protocol::TransportRole::CLIENT);
544
545 #if defined(ENABLE_WEBRTC_REMOTING_CLIENT)
546 if (session_context_->info.flags.find("useWebrtc") != std::string::npos) {
547 VLOG(0) << "Attempting to connect using WebRTC.";
548 std::unique_ptr<protocol::CandidateSessionConfig> protocol_config =
549 protocol::CandidateSessionConfig::CreateEmpty();
550 protocol_config->set_webrtc_supported(true);
551 protocol_config->set_ice_supported(false);
552 client_->set_protocol_config(std::move(protocol_config));
553 }
554 #endif // defined(ENABLE_WEBRTC_REMOTING_CLIENT)
555 if (session_context_->info.pairing_id.length() &&
556 session_context_->info.pairing_secret.length()) {
557 logger_->SetAuthMethod(ChromotingEvent::AuthMethod::PINLESS);
558 }
559
560 protocol::ClientAuthenticationConfig client_auth_config;
561 client_auth_config.host_id = session_context_->info.host_id;
562 client_auth_config.pairing_client_id = session_context_->info.pairing_id;
563 client_auth_config.pairing_secret = session_context_->info.pairing_secret;
564 client_auth_config.fetch_third_party_token_callback =
565 base::BindRepeating(&Core::FetchThirdPartyToken, GetWeakPtr(),
566 session_context_->info.host_pubkey);
567 client_auth_config.fetch_secret_callback =
568 base::BindRepeating(&Core::FetchSecret, GetWeakPtr());
569
570 client_->Start(signaling_.get(), client_auth_config, transport_context,
571 session_context_->info.host_ftl_id,
572 session_context_->info.capabilities);
573 }
574
LogPerfStats()575 void ChromotingSession::Core::LogPerfStats() {
576 DCHECK(network_task_runner()->BelongsToCurrentThread());
577
578 logger_->LogStatistics(*perf_tracker_);
579 }
580
FetchSecret(bool pairing_supported,const protocol::SecretFetchedCallback & secret_fetched_callback)581 void ChromotingSession::Core::FetchSecret(
582 bool pairing_supported,
583 const protocol::SecretFetchedCallback& secret_fetched_callback) {
584 DCHECK(network_task_runner()->BelongsToCurrentThread());
585
586 // TODO(yuweih): Use bindOnce once SecretFetchedCallback becomes OnceCallback.
587 auto secret_fetched_callback_for_ui_thread = base::BindRepeating(
588 [](scoped_refptr<AutoThreadTaskRunner> network_task_runner,
589 base::WeakPtr<ChromotingSession::Core> core,
590 const protocol::SecretFetchedCallback& callback,
591 const std::string& secret) {
592 DCHECK(!network_task_runner->BelongsToCurrentThread());
593 network_task_runner->PostTask(
594 FROM_HERE,
595 base::BindOnce(&ChromotingSession::Core::HandleOnSecretFetched,
596 core, callback, secret));
597 },
598 network_task_runner(), GetWeakPtr(), secret_fetched_callback);
599 ui_task_runner()->PostTask(
600 FROM_HERE, base::BindOnce(&ChromotingSession::Delegate::FetchSecret,
601 session_context_->delegate, pairing_supported,
602 secret_fetched_callback_for_ui_thread));
603 }
604
HandleOnSecretFetched(const protocol::SecretFetchedCallback & callback,const std::string secret)605 void ChromotingSession::Core::HandleOnSecretFetched(
606 const protocol::SecretFetchedCallback& callback,
607 const std::string secret) {
608 DCHECK(network_task_runner()->BelongsToCurrentThread());
609
610 logger_->SetAuthMethod(ChromotingEvent::AuthMethod::PIN);
611
612 callback.Run(secret);
613 }
614
FetchThirdPartyToken(const std::string & host_public_key,const std::string & token_url,const std::string & scopes,const protocol::ThirdPartyTokenFetchedCallback & token_fetched_callback)615 void ChromotingSession::Core::FetchThirdPartyToken(
616 const std::string& host_public_key,
617 const std::string& token_url,
618 const std::string& scopes,
619 const protocol::ThirdPartyTokenFetchedCallback& token_fetched_callback) {
620 DCHECK(network_task_runner()->BelongsToCurrentThread());
621
622 // TODO(yuweih): Use bindOnce once SecretFetchedCallback becomes OnceCallback.
623 auto token_fetched_callback_for_ui_thread = base::BindRepeating(
624 [](scoped_refptr<AutoThreadTaskRunner> network_task_runner,
625 base::WeakPtr<ChromotingSession::Core> core,
626 const protocol::ThirdPartyTokenFetchedCallback& callback,
627 const std::string& token, const std::string& shared_secret) {
628 DCHECK(!network_task_runner->BelongsToCurrentThread());
629 network_task_runner->PostTask(
630 FROM_HERE,
631 base::BindOnce(
632 &ChromotingSession::Core::HandleOnThirdPartyTokenFetched, core,
633 callback, token, shared_secret));
634 },
635 network_task_runner(), GetWeakPtr(), token_fetched_callback);
636
637 ui_task_runner()->PostTask(
638 FROM_HERE,
639 base::BindOnce(&ChromotingSession::Delegate::FetchThirdPartyToken,
640 session_context_->delegate, token_url, host_public_key,
641 scopes, token_fetched_callback_for_ui_thread));
642 }
643
HandleOnThirdPartyTokenFetched(const protocol::ThirdPartyTokenFetchedCallback & callback,const std::string & token,const std::string & shared_secret)644 void ChromotingSession::Core::HandleOnThirdPartyTokenFetched(
645 const protocol::ThirdPartyTokenFetchedCallback& callback,
646 const std::string& token,
647 const std::string& shared_secret) {
648 DCHECK(network_task_runner()->BelongsToCurrentThread());
649
650 logger_->SetAuthMethod(ChromotingEvent::AuthMethod::THIRD_PARTY);
651
652 callback.Run(token, shared_secret);
653 }
654
655 // ChromotingSession implementation.
656
ChromotingSession(base::WeakPtr<ChromotingSession::Delegate> delegate,std::unique_ptr<protocol::CursorShapeStub> cursor_shape_stub,std::unique_ptr<protocol::VideoRenderer> video_renderer,std::unique_ptr<protocol::AudioStub> audio_player,const ConnectToHostInfo & info)657 ChromotingSession::ChromotingSession(
658 base::WeakPtr<ChromotingSession::Delegate> delegate,
659 std::unique_ptr<protocol::CursorShapeStub> cursor_shape_stub,
660 std::unique_ptr<protocol::VideoRenderer> video_renderer,
661 std::unique_ptr<protocol::AudioStub> audio_player,
662 const ConnectToHostInfo& info)
663 : runtime_(ChromotingClientRuntime::GetInstance()) {
664 DCHECK(delegate);
665 DCHECK(cursor_shape_stub);
666 DCHECK(video_renderer);
667 DCHECK(audio_player);
668 DCHECK(runtime_->ui_task_runner()->BelongsToCurrentThread());
669
670 // logger is set when connection is started.
671 auto session_context = std::make_unique<SessionContext>();
672 session_context->delegate = delegate;
673 session_context->audio_player = std::move(audio_player);
674 session_context->audio_player_weak_factory =
675 std::make_unique<base::WeakPtrFactory<protocol::AudioStub>>(
676 session_context->audio_player.get());
677 session_context->cursor_shape_stub = std::move(cursor_shape_stub);
678 session_context->video_renderer = std::move(video_renderer);
679 session_context->info = info;
680
681 auto logger = std::make_unique<ClientTelemetryLogger>(
682 runtime_->log_writer(), ChromotingEvent::Mode::ME2ME,
683 info.session_entry_point);
684
685 core_ = std::make_unique<Core>(runtime_, std::move(logger),
686 std::move(session_context));
687 }
688
~ChromotingSession()689 ChromotingSession::~ChromotingSession() {
690 DCHECK(runtime_->ui_task_runner()->BelongsToCurrentThread());
691
692 runtime_->network_task_runner()->DeleteSoon(FROM_HERE, core_.release());
693 }
694
GetFeedbackData(GetFeedbackDataCallback callback) const695 void ChromotingSession::GetFeedbackData(
696 GetFeedbackDataCallback callback) const {
697 DCHECK(runtime_->ui_task_runner()->BelongsToCurrentThread());
698
699 // Bind to base::Unretained(core) instead of the WeakPtr so that we can still
700 // get the feedback data after the session is remotely disconnected.
701 base::PostTaskAndReplyWithResult(
702 runtime_->network_task_runner().get(), FROM_HERE,
703 base::BindOnce(&Core::GetFeedbackData, base::Unretained(core_.get())),
704 std::move(callback));
705 }
706
RequestPairing(const std::string & device_name)707 void ChromotingSession::RequestPairing(const std::string& device_name) {
708 RunCoreTaskOnNetworkThread(FROM_HERE, &Core::RequestPairing, device_name);
709 }
710
SendMouseEvent(int x,int y,protocol::MouseEvent_MouseButton button,bool button_down)711 void ChromotingSession::SendMouseEvent(int x,
712 int y,
713 protocol::MouseEvent_MouseButton button,
714 bool button_down) {
715 RunCoreTaskOnNetworkThread(FROM_HERE, &Core::SendMouseEvent, x, y, button,
716 button_down);
717 }
718
SendMouseWheelEvent(int delta_x,int delta_y)719 void ChromotingSession::SendMouseWheelEvent(int delta_x, int delta_y) {
720 RunCoreTaskOnNetworkThread(FROM_HERE, &Core::SendMouseWheelEvent, delta_x,
721 delta_y);
722 }
723
SendKeyEvent(int scan_code,int key_code,bool key_down)724 bool ChromotingSession::SendKeyEvent(int scan_code,
725 int key_code,
726 bool key_down) {
727 DCHECK(runtime_->ui_task_runner()->BelongsToCurrentThread());
728
729 // For software keyboards |scan_code| is set to 0, in which case the
730 // |key_code| is used instead.
731 uint32_t usb_key_code =
732 scan_code ? ui::KeycodeConverter::NativeKeycodeToUsbKeycode(scan_code)
733 : NativeDeviceKeycodeToUsbKeycode(key_code);
734 if (!usb_key_code) {
735 LOG(WARNING) << "Ignoring unknown key code: " << key_code
736 << " scan code: " << scan_code;
737 return false;
738 }
739 RunCoreTaskOnNetworkThread(FROM_HERE, &Core::SendKeyEvent, usb_key_code,
740 key_down);
741
742 return true;
743 }
744
SendTextEvent(const std::string & text)745 void ChromotingSession::SendTextEvent(const std::string& text) {
746 RunCoreTaskOnNetworkThread(FROM_HERE, &Core::SendTextEvent, text);
747 }
748
SendTouchEvent(const protocol::TouchEvent & touch_event)749 void ChromotingSession::SendTouchEvent(
750 const protocol::TouchEvent& touch_event) {
751 RunCoreTaskOnNetworkThread(FROM_HERE, &Core::SendTouchEvent, touch_event);
752 }
753
SendClientResolution(int dips_width,int dips_height,float scale)754 void ChromotingSession::SendClientResolution(int dips_width,
755 int dips_height,
756 float scale) {
757 RunCoreTaskOnNetworkThread(FROM_HERE, &Core::SendClientResolution, dips_width,
758 dips_height, scale);
759 }
760
EnableVideoChannel(bool enable)761 void ChromotingSession::EnableVideoChannel(bool enable) {
762 RunCoreTaskOnNetworkThread(FROM_HERE, &Core::EnableVideoChannel, enable);
763 }
764
SendClientMessage(const std::string & type,const std::string & data)765 void ChromotingSession::SendClientMessage(const std::string& type,
766 const std::string& data) {
767 RunCoreTaskOnNetworkThread(FROM_HERE, &Core::SendClientMessage, type, data);
768 }
769
770 template <typename Functor, typename... Args>
RunCoreTaskOnNetworkThread(const base::Location & from_here,Functor && core_functor,Args &&...args)771 void ChromotingSession::RunCoreTaskOnNetworkThread(
772 const base::Location& from_here,
773 Functor&& core_functor,
774 Args&&... args) {
775 DCHECK(runtime_->ui_task_runner()->BelongsToCurrentThread());
776
777 runtime_->network_task_runner()->PostTask(
778 FROM_HERE,
779 base::BindOnce(std::forward<Functor>(core_functor), core_->GetWeakPtr(),
780 std::forward<Args>(args)...));
781 }
782
783 } // namespace remoting
784