Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / remoting / host / chromoting_host.cc
blobd0b2bfcd6173ce295112a53cfccbd38bb3abed55
1 // Copyright (c) 2012 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.
5 #include "remoting/host/chromoting_host.h"
7 #include <algorithm>
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/command_line.h"
12 #include "build/build_config.h"
13 #include "jingle/glue/thread_wrapper.h"
14 #include "remoting/base/constants.h"
15 #include "remoting/base/logging.h"
16 #include "remoting/host/chromoting_host_context.h"
17 #include "remoting/host/desktop_environment.h"
18 #include "remoting/host/host_config.h"
19 #include "remoting/host/input_injector.h"
20 #include "remoting/host/video_frame_recorder.h"
21 #include "remoting/protocol/connection_to_client.h"
22 #include "remoting/protocol/client_stub.h"
23 #include "remoting/protocol/host_stub.h"
24 #include "remoting/protocol/input_stub.h"
25 #include "remoting/protocol/session_config.h"
27 using remoting::protocol::ConnectionToClient;
28 using remoting::protocol::InputStub;
30 namespace remoting {
32 namespace {
34 const net::BackoffEntry::Policy kDefaultBackoffPolicy = {
35 // Number of initial errors (in sequence) to ignore before applying
36 // exponential back-off rules.
39 // Initial delay for exponential back-off in ms.
40 2000,
42 // Factor by which the waiting time will be multiplied.
45 // Fuzzing percentage. ex: 10% will spread requests randomly
46 // between 90%-100% of the calculated time.
49 // Maximum amount of time we are willing to delay our request in ms.
50 -1,
52 // Time to keep an entry from being discarded even when it
53 // has no significant state, -1 to never discard.
54 -1,
56 // Don't use initial delay unless the last request was an error.
57 false,
60 } // namespace
62 ChromotingHost::ChromotingHost(
63 SignalStrategy* signal_strategy,
64 DesktopEnvironmentFactory* desktop_environment_factory,
65 scoped_ptr<protocol::SessionManager> session_manager,
66 scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner,
67 scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
68 scoped_refptr<base::SingleThreadTaskRunner> video_capture_task_runner,
69 scoped_refptr<base::SingleThreadTaskRunner> video_encode_task_runner,
70 scoped_refptr<base::SingleThreadTaskRunner> network_task_runner,
71 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
72 : desktop_environment_factory_(desktop_environment_factory),
73 session_manager_(session_manager.Pass()),
74 audio_task_runner_(audio_task_runner),
75 input_task_runner_(input_task_runner),
76 video_capture_task_runner_(video_capture_task_runner),
77 video_encode_task_runner_(video_encode_task_runner),
78 network_task_runner_(network_task_runner),
79 ui_task_runner_(ui_task_runner),
80 signal_strategy_(signal_strategy),
81 started_(false),
82 protocol_config_(protocol::CandidateSessionConfig::CreateDefault()),
83 login_backoff_(&kDefaultBackoffPolicy),
84 authenticating_client_(false),
85 reject_authenticating_client_(false),
86 enable_curtaining_(false),
87 weak_factory_(this) {
88 DCHECK(network_task_runner_->BelongsToCurrentThread());
89 DCHECK(signal_strategy);
91 jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop();
93 if (!desktop_environment_factory_->SupportsAudioCapture()) {
94 protocol_config_->DisableAudioChannel();
98 ChromotingHost::~ChromotingHost() {
99 DCHECK(CalledOnValidThread());
101 // Disconnect all of the clients.
102 while (!clients_.empty()) {
103 clients_.front()->DisconnectSession();
106 // Destroy the session manager to make sure that |signal_strategy_| does not
107 // have any listeners registered.
108 session_manager_.reset();
110 // Notify observers.
111 if (started_)
112 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, OnShutdown());
115 void ChromotingHost::Start(const std::string& host_owner_email) {
116 DCHECK(CalledOnValidThread());
117 DCHECK(!started_);
119 HOST_LOG << "Starting host";
120 started_ = true;
121 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
122 OnStart(host_owner_email));
124 // Start the SessionManager, supplying this ChromotingHost as the listener.
125 session_manager_->Init(signal_strategy_, this);
128 void ChromotingHost::AddStatusObserver(HostStatusObserver* observer) {
129 DCHECK(CalledOnValidThread());
130 status_observers_.AddObserver(observer);
133 void ChromotingHost::RemoveStatusObserver(HostStatusObserver* observer) {
134 DCHECK(CalledOnValidThread());
135 status_observers_.RemoveObserver(observer);
138 void ChromotingHost::AddExtension(scoped_ptr<HostExtension> extension) {
139 extensions_.push_back(extension.release());
142 void ChromotingHost::RejectAuthenticatingClient() {
143 DCHECK(authenticating_client_);
144 reject_authenticating_client_ = true;
147 void ChromotingHost::SetAuthenticatorFactory(
148 scoped_ptr<protocol::AuthenticatorFactory> authenticator_factory) {
149 DCHECK(CalledOnValidThread());
150 session_manager_->set_authenticator_factory(authenticator_factory.Pass());
153 void ChromotingHost::SetEnableCurtaining(bool enable) {
154 DCHECK(network_task_runner_->BelongsToCurrentThread());
156 if (enable_curtaining_ == enable)
157 return;
159 enable_curtaining_ = enable;
160 desktop_environment_factory_->SetEnableCurtaining(enable_curtaining_);
162 // Disconnect all existing clients because they might be running not
163 // curtained.
164 // TODO(alexeypa): fix this such that the curtain is applied to the not
165 // curtained sessions or disconnect only the client connected to not
166 // curtained sessions.
167 if (enable_curtaining_)
168 DisconnectAllClients();
171 void ChromotingHost::SetMaximumSessionDuration(
172 const base::TimeDelta& max_session_duration) {
173 max_session_duration_ = max_session_duration;
176 ////////////////////////////////////////////////////////////////////////////
177 // protocol::ClientSession::EventHandler implementation.
178 void ChromotingHost::OnSessionAuthenticating(ClientSession* client) {
179 // We treat each incoming connection as a failure to authenticate,
180 // and clear the backoff when a connection successfully
181 // authenticates. This allows the backoff to protect from parallel
182 // connection attempts as well as sequential ones.
183 if (login_backoff_.ShouldRejectRequest()) {
184 LOG(WARNING) << "Disconnecting client " << client->client_jid() << " due to"
185 " an overload of failed login attempts.";
186 client->DisconnectSession();
187 return;
189 login_backoff_.InformOfRequest(false);
192 bool ChromotingHost::OnSessionAuthenticated(ClientSession* client) {
193 DCHECK(CalledOnValidThread());
195 login_backoff_.Reset();
197 // Disconnect all other clients. |it| should be advanced before Disconnect()
198 // is called to avoid it becoming invalid when the client is removed from
199 // the list.
200 ClientList::iterator it = clients_.begin();
201 while (it != clients_.end()) {
202 ClientSession* other_client = *it++;
203 if (other_client != client)
204 other_client->DisconnectSession();
207 // Disconnects above must have destroyed all other clients.
208 DCHECK_EQ(clients_.size(), 1U);
210 // Notify observers that there is at least one authenticated client.
211 const std::string& jid = client->client_jid();
213 reject_authenticating_client_ = false;
215 authenticating_client_ = true;
216 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
217 OnClientAuthenticated(jid));
218 authenticating_client_ = false;
220 return !reject_authenticating_client_;
223 void ChromotingHost::OnSessionChannelsConnected(ClientSession* client) {
224 DCHECK(CalledOnValidThread());
226 // Notify observers.
227 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
228 OnClientConnected(client->client_jid()));
231 void ChromotingHost::OnSessionAuthenticationFailed(ClientSession* client) {
232 DCHECK(CalledOnValidThread());
234 // Notify observers.
235 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
236 OnAccessDenied(client->client_jid()));
239 void ChromotingHost::OnSessionClosed(ClientSession* client) {
240 DCHECK(CalledOnValidThread());
242 ClientList::iterator it = std::find(clients_.begin(), clients_.end(), client);
243 CHECK(it != clients_.end());
245 if (client->is_authenticated()) {
246 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
247 OnClientDisconnected(client->client_jid()));
250 clients_.erase(it);
251 delete client;
254 void ChromotingHost::OnSessionRouteChange(
255 ClientSession* session,
256 const std::string& channel_name,
257 const protocol::TransportRoute& route) {
258 DCHECK(CalledOnValidThread());
259 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
260 OnClientRouteChange(session->client_jid(), channel_name,
261 route));
264 void ChromotingHost::OnSessionManagerReady() {
265 DCHECK(CalledOnValidThread());
266 // Don't need to do anything here, just wait for incoming
267 // connections.
270 void ChromotingHost::OnIncomingSession(
271 protocol::Session* session,
272 protocol::SessionManager::IncomingSessionResponse* response) {
273 DCHECK(CalledOnValidThread());
275 if (!started_) {
276 *response = protocol::SessionManager::DECLINE;
277 return;
280 if (login_backoff_.ShouldRejectRequest()) {
281 LOG(WARNING) << "Rejecting connection due to"
282 " an overload of failed login attempts.";
283 *response = protocol::SessionManager::OVERLOAD;
284 return;
287 scoped_ptr<protocol::SessionConfig> config =
288 protocol::SessionConfig::SelectCommon(session->candidate_config(),
289 protocol_config_.get());
290 if (!config) {
291 LOG(WARNING) << "Rejecting connection from " << session->jid()
292 << " because no compatible configuration has been found.";
293 *response = protocol::SessionManager::INCOMPATIBLE;
294 return;
297 session->set_config(config.Pass());
299 *response = protocol::SessionManager::ACCEPT;
301 HOST_LOG << "Client connected: " << session->jid();
303 // Create a client object.
304 scoped_ptr<protocol::ConnectionToClient> connection(
305 new protocol::ConnectionToClient(session));
306 ClientSession* client = new ClientSession(
307 this,
308 audio_task_runner_,
309 input_task_runner_,
310 video_capture_task_runner_,
311 video_encode_task_runner_,
312 network_task_runner_,
313 ui_task_runner_,
314 connection.Pass(),
315 desktop_environment_factory_,
316 max_session_duration_,
317 pairing_registry_,
318 extensions_.get());
320 clients_.push_back(client);
323 void ChromotingHost::set_protocol_config(
324 scoped_ptr<protocol::CandidateSessionConfig> config) {
325 DCHECK(CalledOnValidThread());
326 DCHECK(config.get());
327 DCHECK(!started_);
328 protocol_config_ = config.Pass();
331 void ChromotingHost::DisconnectAllClients() {
332 DCHECK(CalledOnValidThread());
334 while (!clients_.empty()) {
335 size_t size = clients_.size();
336 clients_.front()->DisconnectSession();
337 CHECK_EQ(clients_.size(), size - 1);
341 } // namespace remoting