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