1cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// found in the LICENSE file.
4cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "remoting/ios/bridge/client_instance.h"
6cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
7cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/bind.h"
8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/logging.h"
9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/synchronization/waitable_event.h"
10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "net/socket/client_socket_factory.h"
11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "remoting/base/url_request_context.h"
12cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "remoting/client/audio_player.h"
13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "remoting/client/plugin/delegating_signal_strategy.h"
14cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "remoting/ios/bridge/client_proxy.h"
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "remoting/jingle_glue/chromium_port_allocator.h"
16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "remoting/protocol/host_stub.h"
17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "remoting/protocol/libjingle_transport_factory.h"
18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)namespace {
20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char* const kXmppServer = "talk.google.com";
21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const int kXmppPort = 5222;
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const bool kXmppUseTls = true;
23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void DoNothing() {}
25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}  // namespace
26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)namespace remoting {
28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)ClientInstance::ClientInstance(const base::WeakPtr<ClientProxy>& proxy,
30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                               const std::string& username,
31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                               const std::string& auth_token,
32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                               const std::string& host_jid,
33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                               const std::string& host_id,
34cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                               const std::string& host_pubkey,
35cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                               const std::string& pairing_id,
36cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                               const std::string& pairing_secret)
37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    : proxyToClient_(proxy), host_id_(host_id), create_pairing_(false) {
38cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
39cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!base::MessageLoop::current()) {
40cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    VLOG(1) << "Starting main message loop";
41cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    ui_loop_ = new base::MessageLoopForUI();
42cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    ui_loop_->Attach();
43cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } else {
44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    VLOG(1) << "Using existing main message loop";
45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    ui_loop_ = base::MessageLoopForUI::current();
46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  VLOG(1) << "Spawning additional threads";
49cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
50cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // |ui_loop_| runs on the main thread, so |ui_task_runner_| will run on the
51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // main thread.  We can not kill the main thread when the message loop becomes
52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // idle so the callback function does nothing (as opposed to the typical
53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // base::MessageLoop::QuitClosure())
54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ui_task_runner_ = new AutoThreadTaskRunner(ui_loop_->message_loop_proxy(),
55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                             base::Bind(&::DoNothing));
56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  network_task_runner_ = AutoThread::CreateWithType(
58cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      "native_net", ui_task_runner_, base::MessageLoop::TYPE_IO);
59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  url_requester_ = new URLRequestContextGetter(network_task_runner_);
61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  client_context_.reset(new ClientContext(network_task_runner_));
63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
64cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(ui_task_runner_->BelongsToCurrentThread());
65cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Initialize XMPP config.
67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  xmpp_config_.host = kXmppServer;
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  xmpp_config_.port = kXmppPort;
69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  xmpp_config_.use_tls = kXmppUseTls;
70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  xmpp_config_.username = username;
71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  xmpp_config_.auth_token = auth_token;
72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  xmpp_config_.auth_service = "oauth2";
73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Initialize ClientConfig.
75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  client_config_.host_jid = host_jid;
76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  client_config_.host_public_key = host_pubkey;
77cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  client_config_.authentication_tag = host_id_;
78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  client_config_.client_pairing_id = pairing_id;
79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  client_config_.client_paired_secret = pairing_secret;
80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  client_config_.authentication_methods.push_back(
81cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      protocol::AuthenticationMethod::FromString("spake2_pair"));
82cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  client_config_.authentication_methods.push_back(
83cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      protocol::AuthenticationMethod::FromString("spake2_hmac"));
84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  client_config_.authentication_methods.push_back(
85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      protocol::AuthenticationMethod::FromString("spake2_plain"));
86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)ClientInstance::~ClientInstance() {}
89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::Start() {
91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(ui_task_runner_->BelongsToCurrentThread());
92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Creates a reference to |this|, so don't want to bind during constructor
94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  client_config_.fetch_secret_callback =
95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      base::Bind(&ClientInstance::FetchSecret, this);
96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  view_.reset(new FrameConsumerBridge(
98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      base::Bind(&ClientProxy::RedrawCanvas, proxyToClient_)));
99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // |consumer_proxy| must be created on the UI thread to proxy calls from the
101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // network or decode thread to the UI thread, but ownership will belong to a
102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // SoftwareVideoRenderer which runs on the network thread.
103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_refptr<FrameConsumerProxy> consumer_proxy =
104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      new FrameConsumerProxy(ui_task_runner_, view_->AsWeakPtr());
105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Post a task to start connection
107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::WaitableEvent done_event(true, false);
108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  network_task_runner_->PostTask(
109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      FROM_HERE,
110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      base::Bind(&ClientInstance::ConnectToHostOnNetworkThread,
111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 this,
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 consumer_proxy,
113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 base::Bind(&base::WaitableEvent::Signal,
114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                            base::Unretained(&done_event))));
115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Wait until initialization completes before continuing
116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  done_event.Wait();
117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::Cleanup() {
120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(ui_task_runner_->BelongsToCurrentThread());
121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  client_config_.fetch_secret_callback.Reset();  // Release ref to this
123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // |view_| must be destroyed on the UI thread before the producer is gone.
124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  view_.reset();
125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::WaitableEvent done_event(true, false);
127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  network_task_runner_->PostTask(
128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      FROM_HERE,
129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      base::Bind(&ClientInstance::DisconnectFromHostOnNetworkThread,
130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 this,
131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 base::Bind(&base::WaitableEvent::Signal,
132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                            base::Unretained(&done_event))));
133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Wait until we are fully disconnected before continuing
134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  done_event.Wait();
135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
136cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
137cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// HOST attempts to continue automatically with previously supplied credentials,
138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// if it can't it requests the user's PIN.
139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::FetchSecret(
140cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    bool pairable,
141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const protocol::SecretFetchedCallback& callback) {
142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!ui_task_runner_->BelongsToCurrentThread()) {
143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    ui_task_runner_->PostTask(
144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        FROM_HERE,
145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        base::Bind(&ClientInstance::FetchSecret, this, pairable, callback));
146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  pin_callback_ = callback;
150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (proxyToClient_) {
152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (!client_config_.client_pairing_id.empty()) {
153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      // We attempted to connect using an existing pairing that was rejected.
154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      // Unless we forget about the stale credentials, we'll continue trying
155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      // them.
156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      VLOG(1) << "Deleting rejected pairing credentials";
157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      proxyToClient_->CommitPairingCredentials(host_id_, "", "");
159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    proxyToClient_->DisplayAuthenticationPrompt(pairable);
161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
164cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::ProvideSecret(const std::string& pin,
165cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                   bool create_pairing) {
166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(ui_task_runner_->BelongsToCurrentThread());
167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  create_pairing_ = create_pairing;
168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Before this function can complete, FetchSecret must be called
170cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(!pin_callback_.is_null());
171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  network_task_runner_->PostTask(FROM_HERE, base::Bind(pin_callback_, pin));
172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::PerformMouseAction(
175cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const webrtc::DesktopVector& position,
176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const webrtc::DesktopVector& wheel_delta,
177cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    int /* protocol::MouseEvent_MouseButton */ whichButton,
178cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    bool button_down) {
179cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!network_task_runner_->BelongsToCurrentThread()) {
180cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    network_task_runner_->PostTask(
181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        FROM_HERE,
182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        base::Bind(&ClientInstance::PerformMouseAction,
183cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                   this,
184cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                   position,
185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                   wheel_delta,
186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                   whichButton,
187cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                   button_down));
188cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
189cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
190cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
191cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  protocol::MouseEvent_MouseButton mButton;
192cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
193cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Button must be within the bounds of the MouseEvent_MouseButton enum.
194cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  switch (whichButton) {
195cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    case protocol::MouseEvent_MouseButton::MouseEvent_MouseButton_BUTTON_LEFT:
196cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      mButton =
197cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          protocol::MouseEvent_MouseButton::MouseEvent_MouseButton_BUTTON_LEFT;
198cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      break;
199cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    case protocol::MouseEvent_MouseButton::MouseEvent_MouseButton_BUTTON_MAX:
200cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      mButton =
201cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          protocol::MouseEvent_MouseButton::MouseEvent_MouseButton_BUTTON_MAX;
202cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      break;
203cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    case protocol::MouseEvent_MouseButton::MouseEvent_MouseButton_BUTTON_MIDDLE:
204cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      mButton = protocol::MouseEvent_MouseButton::
205cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          MouseEvent_MouseButton_BUTTON_MIDDLE;
206cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      break;
207cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    case protocol::MouseEvent_MouseButton::MouseEvent_MouseButton_BUTTON_RIGHT:
208cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      mButton =
209cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          protocol::MouseEvent_MouseButton::MouseEvent_MouseButton_BUTTON_RIGHT;
210cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      break;
211cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    case protocol::MouseEvent_MouseButton::
212cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        MouseEvent_MouseButton_BUTTON_UNDEFINED:
213cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      mButton = protocol::MouseEvent_MouseButton::
214cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          MouseEvent_MouseButton_BUTTON_UNDEFINED;
215cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      break;
216cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    default:
217cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      LOG(FATAL) << "Invalid constant for MouseEvent_MouseButton";
218cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      mButton = protocol::MouseEvent_MouseButton::
219cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          MouseEvent_MouseButton_BUTTON_UNDEFINED;
220cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      break;
221cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
222cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
223cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  protocol::MouseEvent action;
224cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  action.set_x(position.x());
225cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  action.set_y(position.y());
226cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  action.set_wheel_delta_x(wheel_delta.x());
227cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  action.set_wheel_delta_y(wheel_delta.y());
228cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  action.set_button(mButton);
229cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (mButton != protocol::MouseEvent::BUTTON_UNDEFINED)
230cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    action.set_button_down(button_down);
231cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
232cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  connection_->input_stub()->InjectMouseEvent(action);
233cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
234cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
235cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::PerformKeyboardAction(int key_code, bool key_down) {
236cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!network_task_runner_->BelongsToCurrentThread()) {
237cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    network_task_runner_->PostTask(
238cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        FROM_HERE,
239cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        base::Bind(
240cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            &ClientInstance::PerformKeyboardAction, this, key_code, key_down));
241cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
242cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
243cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
244cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  protocol::KeyEvent action;
245cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  action.set_usb_keycode(key_code);
246cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  action.set_pressed(key_down);
247cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  connection_->input_stub()->InjectKeyEvent(action);
248cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
249cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
250cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::OnConnectionState(protocol::ConnectionToHost::State state,
251cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                       protocol::ErrorCode error) {
252cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!ui_task_runner_->BelongsToCurrentThread()) {
253cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    ui_task_runner_->PostTask(
254cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        FROM_HERE,
255cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        base::Bind(&ClientInstance::OnConnectionState, this, state, error));
256cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
257cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
258cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
259cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  //     TODO (aboone) This functionality is not scheduled for QA yet.
260cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  //  if (create_pairing_ && state == protocol::ConnectionToHost::CONNECTED) {
261cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  //    VLOG(1) << "Attempting to pair with host";
262cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  //    protocol::PairingRequest request;
263cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  //    request.set_client_name("iOS");
264cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  //    connection_->host_stub()->RequestPairing(request);
265cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  //  }
266cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
267cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (proxyToClient_)
268cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    proxyToClient_->ReportConnectionStatus(state, error);
269cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
270cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
271cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::OnConnectionReady(bool ready) {
272cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // We ignore this message, since OnConnectionState tells us the same thing.
273cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
274cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
275cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::OnRouteChanged(const std::string& channel_name,
276cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                    const protocol::TransportRoute& route) {
277cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  VLOG(1) << "Using " << protocol::TransportRoute::GetTypeString(route.type)
278cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          << " connection for " << channel_name << " channel";
279cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
280cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
281cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::SetCapabilities(const std::string& capabilities) {
282cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(video_renderer_);
283cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(connection_);
284cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(connection_->state() == protocol::ConnectionToHost::CONNECTED);
285cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  video_renderer_->Initialize(connection_->config());
286cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
287cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
288cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::SetPairingResponse(
289cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const protocol::PairingResponse& response) {
290cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!ui_task_runner_->BelongsToCurrentThread()) {
291cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    ui_task_runner_->PostTask(
292cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        FROM_HERE,
293cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        base::Bind(&ClientInstance::SetPairingResponse, this, response));
294cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
295cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
296cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
297cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  VLOG(1) << "Successfully established pairing with host";
298cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
299cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (proxyToClient_)
300cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    proxyToClient_->CommitPairingCredentials(
301cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        host_id_, response.client_id(), response.shared_secret());
302cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
303cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
304cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::DeliverHostMessage(
305cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const protocol::ExtensionMessage& message) {
306cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  NOTIMPLEMENTED();
307cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
308cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
309cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Returning interface of protocol::ClipboardStub
310cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)protocol::ClipboardStub* ClientInstance::GetClipboardStub() { return this; }
311cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
312cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Returning interface of protocol::CursorShapeStub
313cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)protocol::CursorShapeStub* ClientInstance::GetCursorShapeStub() { return this; }
314cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
315cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>
316cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)ClientInstance::GetTokenFetcher(const std::string& host_public_key) {
317cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Returns null when third-party authentication is unsupported.
318cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>();
319cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
320cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
321cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::InjectClipboardEvent(
322cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const protocol::ClipboardEvent& event) {
323cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  NOTIMPLEMENTED();
324cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
325cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
326cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::SetCursorShape(const protocol::CursorShapeInfo& shape) {
327cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!ui_task_runner_->BelongsToCurrentThread()) {
328cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    ui_task_runner_->PostTask(
329cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        FROM_HERE, base::Bind(&ClientInstance::SetCursorShape, this, shape));
330cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
331cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
332cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (proxyToClient_)
333cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    proxyToClient_->UpdateCursorShape(shape);
334cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
335cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
336cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::ConnectToHostOnNetworkThread(
337cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    scoped_refptr<FrameConsumerProxy> consumer_proxy,
338cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const base::Closure& done) {
339cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(network_task_runner_->BelongsToCurrentThread());
340cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
341cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  client_context_->Start();
342cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
343cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  video_renderer_.reset(
344cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      new SoftwareVideoRenderer(client_context_->main_task_runner(),
345cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                client_context_->decode_task_runner(),
346cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                consumer_proxy));
347cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
348cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  view_->Initialize(video_renderer_.get());
349cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
350cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  connection_.reset(new protocol::ConnectionToHost(true));
351cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
352cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  client_.reset(new ChromotingClient(client_config_,
353cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                     client_context_.get(),
354cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                     connection_.get(),
355cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                     this,
356cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                     video_renderer_.get(),
357cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                     scoped_ptr<AudioPlayer>()));
358cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
359cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  signaling_.reset(
360cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      new XmppSignalStrategy(net::ClientSocketFactory::GetDefaultFactory(),
361cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                             url_requester_,
362cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                             xmpp_config_));
363cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
364cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  NetworkSettings network_settings(NetworkSettings::NAT_TRAVERSAL_ENABLED);
365cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
366cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<ChromiumPortAllocator> port_allocator(
367cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ChromiumPortAllocator::Create(url_requester_, network_settings));
368cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
369cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<protocol::TransportFactory> transport_factory(
370cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      new protocol::LibjingleTransportFactory(
371cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          signaling_.get(),
372cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          port_allocator.PassAs<cricket::HttpPortAllocatorBase>(),
373cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          network_settings));
374cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
375cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  client_->Start(signaling_.get(), transport_factory.Pass());
376cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
377cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!done.is_null())
378cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    done.Run();
379cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
380cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
381cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ClientInstance::DisconnectFromHostOnNetworkThread(
382cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const base::Closure& done) {
383cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(network_task_runner_->BelongsToCurrentThread());
384cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
385cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  host_id_.clear();
386cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
387cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // |client_| must be torn down before |signaling_|.
388cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  connection_.reset();
389cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  client_.reset();
390cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  signaling_.reset();
391cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  video_renderer_.reset();
392cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  client_context_->Stop();
393cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!done.is_null())
394cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    done.Run();
395cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
396cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
397cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}  // namespace remoting
398