Printing: PDFs should only be fit to page if there is a size mismatch.
[chromium-blink-merge.git] / remoting / host / chromoting_host.cc
blob346e887fc46c48feeb636215fd889f0b6af92057
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 "base/message_loop/message_loop_proxy.h"
13 #include "build/build_config.h"
14 #include "jingle/glue/thread_wrapper.h"
15 #include "remoting/base/constants.h"
16 #include "remoting/base/logging.h"
17 #include "remoting/host/chromoting_host_context.h"
18 #include "remoting/host/desktop_environment.h"
19 #include "remoting/host/host_config.h"
20 #include "remoting/host/input_injector.h"
21 #include "remoting/host/video_frame_recorder.h"
22 #include "remoting/protocol/connection_to_client.h"
23 #include "remoting/protocol/client_stub.h"
24 #include "remoting/protocol/host_stub.h"
25 #include "remoting/protocol/input_stub.h"
26 #include "remoting/protocol/session_config.h"
28 using remoting::protocol::ConnectionToClient;
29 using remoting::protocol::InputStub;
31 namespace remoting {
33 namespace {
35 const net::BackoffEntry::Policy kDefaultBackoffPolicy = {
36 // Number of initial errors (in sequence) to ignore before applying
37 // exponential back-off rules.
40 // Initial delay for exponential back-off in ms.
41 2000,
43 // Factor by which the waiting time will be multiplied.
46 // Fuzzing percentage. ex: 10% will spread requests randomly
47 // between 90%-100% of the calculated time.
50 // Maximum amount of time we are willing to delay our request in ms.
51 -1,
53 // Time to keep an entry from being discarded even when it
54 // has no significant state, -1 to never discard.
55 -1,
57 // Don't use initial delay unless the last request was an error.
58 false,
61 } // namespace
63 ChromotingHost::ChromotingHost(
64 SignalStrategy* signal_strategy,
65 DesktopEnvironmentFactory* desktop_environment_factory,
66 scoped_ptr<protocol::SessionManager> session_manager,
67 scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner,
68 scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
69 scoped_refptr<base::SingleThreadTaskRunner> video_capture_task_runner,
70 scoped_refptr<base::SingleThreadTaskRunner> video_encode_task_runner,
71 scoped_refptr<base::SingleThreadTaskRunner> network_task_runner,
72 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
73 : desktop_environment_factory_(desktop_environment_factory),
74 session_manager_(session_manager.Pass()),
75 audio_task_runner_(audio_task_runner),
76 input_task_runner_(input_task_runner),
77 video_capture_task_runner_(video_capture_task_runner),
78 video_encode_task_runner_(video_encode_task_runner),
79 network_task_runner_(network_task_runner),
80 ui_task_runner_(ui_task_runner),
81 signal_strategy_(signal_strategy),
82 started_(false),
83 protocol_config_(protocol::CandidateSessionConfig::CreateDefault()),
84 login_backoff_(&kDefaultBackoffPolicy),
85 authenticating_client_(false),
86 reject_authenticating_client_(false),
87 enable_curtaining_(false),
88 weak_factory_(this) {
89 DCHECK(network_task_runner_->BelongsToCurrentThread());
90 DCHECK(signal_strategy);
92 jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop();
94 if (!desktop_environment_factory_->SupportsAudioCapture()) {
95 protocol_config_->DisableAudioChannel();
99 ChromotingHost::~ChromotingHost() {
100 DCHECK(CalledOnValidThread());
102 // Disconnect all of the clients.
103 while (!clients_.empty()) {
104 clients_.front()->DisconnectSession();
107 // Destroy the session manager to make sure that |signal_strategy_| does not
108 // have any listeners registered.
109 session_manager_.reset();
111 // Notify observers.
112 if (started_)
113 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, OnShutdown());
116 void ChromotingHost::Start(const std::string& host_owner_email) {
117 DCHECK(CalledOnValidThread());
118 DCHECK(!started_);
120 HOST_LOG << "Starting host";
121 started_ = true;
122 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
123 OnStart(host_owner_email));
125 // Start the SessionManager, supplying this ChromotingHost as the listener.
126 session_manager_->Init(signal_strategy_, this);
129 void ChromotingHost::AddStatusObserver(HostStatusObserver* observer) {
130 DCHECK(CalledOnValidThread());
131 status_observers_.AddObserver(observer);
134 void ChromotingHost::RemoveStatusObserver(HostStatusObserver* observer) {
135 DCHECK(CalledOnValidThread());
136 status_observers_.RemoveObserver(observer);
139 void ChromotingHost::AddExtension(scoped_ptr<HostExtension> extension) {
140 extensions_.push_back(extension.release());
143 void ChromotingHost::RejectAuthenticatingClient() {
144 DCHECK(authenticating_client_);
145 reject_authenticating_client_ = true;
148 void ChromotingHost::SetAuthenticatorFactory(
149 scoped_ptr<protocol::AuthenticatorFactory> authenticator_factory) {
150 DCHECK(CalledOnValidThread());
151 session_manager_->set_authenticator_factory(authenticator_factory.Pass());
154 void ChromotingHost::SetEnableCurtaining(bool enable) {
155 DCHECK(network_task_runner_->BelongsToCurrentThread());
157 if (enable_curtaining_ == enable)
158 return;
160 enable_curtaining_ = enable;
161 desktop_environment_factory_->SetEnableCurtaining(enable_curtaining_);
163 // Disconnect all existing clients because they might be running not
164 // curtained.
165 // TODO(alexeypa): fix this such that the curtain is applied to the not
166 // curtained sessions or disconnect only the client connected to not
167 // curtained sessions.
168 if (enable_curtaining_)
169 DisconnectAllClients();
172 void ChromotingHost::SetMaximumSessionDuration(
173 const base::TimeDelta& max_session_duration) {
174 max_session_duration_ = max_session_duration;
177 ////////////////////////////////////////////////////////////////////////////
178 // protocol::ClientSession::EventHandler implementation.
179 void ChromotingHost::OnSessionAuthenticating(ClientSession* client) {
180 // We treat each incoming connection as a failure to authenticate,
181 // and clear the backoff when a connection successfully
182 // authenticates. This allows the backoff to protect from parallel
183 // connection attempts as well as sequential ones.
184 if (login_backoff_.ShouldRejectRequest()) {
185 LOG(WARNING) << "Disconnecting client " << client->client_jid() << " due to"
186 " an overload of failed login attempts.";
187 client->DisconnectSession();
188 return;
190 login_backoff_.InformOfRequest(false);
193 bool ChromotingHost::OnSessionAuthenticated(ClientSession* client) {
194 DCHECK(CalledOnValidThread());
196 login_backoff_.Reset();
198 // Disconnect all other clients. |it| should be advanced before Disconnect()
199 // is called to avoid it becoming invalid when the client is removed from
200 // the list.
201 ClientList::iterator it = clients_.begin();
202 while (it != clients_.end()) {
203 ClientSession* other_client = *it++;
204 if (other_client != client)
205 other_client->DisconnectSession();
208 // Disconnects above must have destroyed all other clients.
209 DCHECK_EQ(clients_.size(), 1U);
211 // Notify observers that there is at least one authenticated client.
212 const std::string& jid = client->client_jid();
214 reject_authenticating_client_ = false;
216 authenticating_client_ = true;
217 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
218 OnClientAuthenticated(jid));
219 authenticating_client_ = false;
221 return !reject_authenticating_client_;
224 void ChromotingHost::OnSessionChannelsConnected(ClientSession* client) {
225 DCHECK(CalledOnValidThread());
227 // Notify observers.
228 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
229 OnClientConnected(client->client_jid()));
232 void ChromotingHost::OnSessionAuthenticationFailed(ClientSession* client) {
233 DCHECK(CalledOnValidThread());
235 // Notify observers.
236 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
237 OnAccessDenied(client->client_jid()));
240 void ChromotingHost::OnSessionClosed(ClientSession* client) {
241 DCHECK(CalledOnValidThread());
243 ClientList::iterator it = std::find(clients_.begin(), clients_.end(), client);
244 CHECK(it != clients_.end());
246 if (client->is_authenticated()) {
247 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
248 OnClientDisconnected(client->client_jid()));
251 clients_.erase(it);
252 delete client;
255 void ChromotingHost::OnSessionRouteChange(
256 ClientSession* session,
257 const std::string& channel_name,
258 const protocol::TransportRoute& route) {
259 DCHECK(CalledOnValidThread());
260 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
261 OnClientRouteChange(session->client_jid(), channel_name,
262 route));
265 void ChromotingHost::OnSessionManagerReady() {
266 DCHECK(CalledOnValidThread());
267 // Don't need to do anything here, just wait for incoming
268 // connections.
271 void ChromotingHost::OnIncomingSession(
272 protocol::Session* session,
273 protocol::SessionManager::IncomingSessionResponse* response) {
274 DCHECK(CalledOnValidThread());
276 if (!started_) {
277 *response = protocol::SessionManager::DECLINE;
278 return;
281 if (login_backoff_.ShouldRejectRequest()) {
282 LOG(WARNING) << "Rejecting connection due to"
283 " an overload of failed login attempts.";
284 *response = protocol::SessionManager::OVERLOAD;
285 return;
288 protocol::SessionConfig config;
289 if (!protocol_config_->Select(session->candidate_config(), &config)) {
290 LOG(WARNING) << "Rejecting connection from " << session->jid()
291 << " because no compatible configuration has been found.";
292 *response = protocol::SessionManager::INCOMPATIBLE;
293 return;
296 session->set_config(config);
298 *response = protocol::SessionManager::ACCEPT;
300 HOST_LOG << "Client connected: " << session->jid();
302 // Create a client object.
303 scoped_ptr<protocol::ConnectionToClient> connection(
304 new protocol::ConnectionToClient(session));
305 ClientSession* client = new ClientSession(
306 this,
307 audio_task_runner_,
308 input_task_runner_,
309 video_capture_task_runner_,
310 video_encode_task_runner_,
311 network_task_runner_,
312 ui_task_runner_,
313 connection.Pass(),
314 desktop_environment_factory_,
315 max_session_duration_,
316 pairing_registry_,
317 extensions_.get());
319 clients_.push_back(client);
322 void ChromotingHost::set_protocol_config(
323 scoped_ptr<protocol::CandidateSessionConfig> config) {
324 DCHECK(CalledOnValidThread());
325 DCHECK(config.get());
326 DCHECK(!started_);
327 protocol_config_ = config.Pass();
330 void ChromotingHost::DisconnectAllClients() {
331 DCHECK(CalledOnValidThread());
333 while (!clients_.empty()) {
334 size_t size = clients_.size();
335 clients_.front()->DisconnectSession();
336 CHECK_EQ(clients_.size(), size - 1);
340 } // namespace remoting