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"
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/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
;
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.
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.
52 // Time to keep an entry from being discarded even when it
53 // has no significant state, -1 to never discard.
56 // Don't use initial delay unless the last request was an error.
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
),
82 protocol_config_(protocol::CandidateSessionConfig::CreateDefault()),
83 login_backoff_(&kDefaultBackoffPolicy
),
84 authenticating_client_(false),
85 reject_authenticating_client_(false),
86 enable_curtaining_(false),
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();
112 FOR_EACH_OBSERVER(HostStatusObserver
, status_observers_
, OnShutdown());
115 void ChromotingHost::Start(const std::string
& host_owner
) {
116 DCHECK(CalledOnValidThread());
119 HOST_LOG
<< "Starting host";
121 FOR_EACH_OBSERVER(HostStatusObserver
, status_observers_
, OnStart(host_owner
));
123 // Start the SessionManager, supplying this ChromotingHost as the listener.
124 session_manager_
->Init(signal_strategy_
, this);
127 void ChromotingHost::AddStatusObserver(HostStatusObserver
* observer
) {
128 DCHECK(CalledOnValidThread());
129 status_observers_
.AddObserver(observer
);
132 void ChromotingHost::RemoveStatusObserver(HostStatusObserver
* observer
) {
133 DCHECK(CalledOnValidThread());
134 status_observers_
.RemoveObserver(observer
);
137 void ChromotingHost::AddExtension(scoped_ptr
<HostExtension
> extension
) {
138 extensions_
.push_back(extension
.release());
141 void ChromotingHost::RejectAuthenticatingClient() {
142 DCHECK(authenticating_client_
);
143 reject_authenticating_client_
= true;
146 void ChromotingHost::SetAuthenticatorFactory(
147 scoped_ptr
<protocol::AuthenticatorFactory
> authenticator_factory
) {
148 DCHECK(CalledOnValidThread());
149 session_manager_
->set_authenticator_factory(authenticator_factory
.Pass());
152 void ChromotingHost::SetEnableCurtaining(bool enable
) {
153 DCHECK(network_task_runner_
->BelongsToCurrentThread());
155 if (enable_curtaining_
== enable
)
158 enable_curtaining_
= enable
;
159 desktop_environment_factory_
->SetEnableCurtaining(enable_curtaining_
);
161 // Disconnect all existing clients because they might be running not
163 // TODO(alexeypa): fix this such that the curtain is applied to the not
164 // curtained sessions or disconnect only the client connected to not
165 // curtained sessions.
166 if (enable_curtaining_
)
167 DisconnectAllClients();
170 void ChromotingHost::SetMaximumSessionDuration(
171 const base::TimeDelta
& max_session_duration
) {
172 max_session_duration_
= max_session_duration
;
175 ////////////////////////////////////////////////////////////////////////////
176 // protocol::ClientSession::EventHandler implementation.
177 void ChromotingHost::OnSessionAuthenticating(ClientSession
* client
) {
178 // We treat each incoming connection as a failure to authenticate,
179 // and clear the backoff when a connection successfully
180 // authenticates. This allows the backoff to protect from parallel
181 // connection attempts as well as sequential ones.
182 if (login_backoff_
.ShouldRejectRequest()) {
183 LOG(WARNING
) << "Disconnecting client " << client
->client_jid() << " due to"
184 " an overload of failed login attempts.";
185 client
->DisconnectSession();
188 login_backoff_
.InformOfRequest(false);
191 bool ChromotingHost::OnSessionAuthenticated(ClientSession
* client
) {
192 DCHECK(CalledOnValidThread());
194 login_backoff_
.Reset();
196 // Disconnect all other clients. |it| should be advanced before Disconnect()
197 // is called to avoid it becoming invalid when the client is removed from
199 ClientList::iterator it
= clients_
.begin();
200 while (it
!= clients_
.end()) {
201 ClientSession
* other_client
= *it
++;
202 if (other_client
!= client
)
203 other_client
->DisconnectSession();
206 // Disconnects above must have destroyed all other clients.
207 DCHECK_EQ(clients_
.size(), 1U);
209 // Notify observers that there is at least one authenticated client.
210 const std::string
& jid
= client
->client_jid();
212 reject_authenticating_client_
= false;
214 authenticating_client_
= true;
215 FOR_EACH_OBSERVER(HostStatusObserver
, status_observers_
,
216 OnClientAuthenticated(jid
));
217 authenticating_client_
= false;
219 return !reject_authenticating_client_
;
222 void ChromotingHost::OnSessionChannelsConnected(ClientSession
* client
) {
223 DCHECK(CalledOnValidThread());
226 FOR_EACH_OBSERVER(HostStatusObserver
, status_observers_
,
227 OnClientConnected(client
->client_jid()));
230 void ChromotingHost::OnSessionClientCapabilities(ClientSession
* client
) {
231 DCHECK(CalledOnValidThread());
233 // Create extension sessions from each registered extension for this client.
234 for (HostExtensionList::iterator extension
= extensions_
.begin();
235 extension
!= extensions_
.end(); ++extension
) {
236 scoped_ptr
<HostExtensionSession
> extension_session
=
237 (*extension
)->CreateExtensionSession(client
);
238 if (extension_session
)
239 client
->AddExtensionSession(extension_session
.Pass());
243 void ChromotingHost::OnSessionAuthenticationFailed(ClientSession
* client
) {
244 DCHECK(CalledOnValidThread());
247 FOR_EACH_OBSERVER(HostStatusObserver
, status_observers_
,
248 OnAccessDenied(client
->client_jid()));
251 void ChromotingHost::OnSessionClosed(ClientSession
* client
) {
252 DCHECK(CalledOnValidThread());
254 ClientList::iterator it
= std::find(clients_
.begin(), clients_
.end(), client
);
255 CHECK(it
!= clients_
.end());
257 if (client
->is_authenticated()) {
258 FOR_EACH_OBSERVER(HostStatusObserver
, status_observers_
,
259 OnClientDisconnected(client
->client_jid()));
266 void ChromotingHost::OnSessionRouteChange(
267 ClientSession
* session
,
268 const std::string
& channel_name
,
269 const protocol::TransportRoute
& route
) {
270 DCHECK(CalledOnValidThread());
271 FOR_EACH_OBSERVER(HostStatusObserver
, status_observers_
,
272 OnClientRouteChange(session
->client_jid(), channel_name
,
276 void ChromotingHost::OnSessionManagerReady() {
277 DCHECK(CalledOnValidThread());
278 // Don't need to do anything here, just wait for incoming
282 void ChromotingHost::OnIncomingSession(
283 protocol::Session
* session
,
284 protocol::SessionManager::IncomingSessionResponse
* response
) {
285 DCHECK(CalledOnValidThread());
288 *response
= protocol::SessionManager::DECLINE
;
292 if (login_backoff_
.ShouldRejectRequest()) {
293 LOG(WARNING
) << "Rejecting connection due to"
294 " an overload of failed login attempts.";
295 *response
= protocol::SessionManager::OVERLOAD
;
299 protocol::SessionConfig config
;
300 if (!protocol_config_
->Select(session
->candidate_config(), &config
)) {
301 LOG(WARNING
) << "Rejecting connection from " << session
->jid()
302 << " because no compatible configuration has been found.";
303 *response
= protocol::SessionManager::INCOMPATIBLE
;
307 session
->set_config(config
);
309 *response
= protocol::SessionManager::ACCEPT
;
311 HOST_LOG
<< "Client connected: " << session
->jid();
313 // Create a client object.
314 scoped_ptr
<protocol::ConnectionToClient
> connection(
315 new protocol::ConnectionToClient(session
));
316 ClientSession
* client
= new ClientSession(
320 video_capture_task_runner_
,
321 video_encode_task_runner_
,
322 network_task_runner_
,
325 desktop_environment_factory_
,
326 max_session_duration_
,
329 // Registers capabilities provided by host extensions.
330 for (HostExtensionList::iterator extension
= extensions_
.begin();
331 extension
!= extensions_
.end(); ++extension
) {
332 client
->AddHostCapabilities((*extension
)->GetCapabilities());
335 clients_
.push_back(client
);
338 void ChromotingHost::set_protocol_config(
339 scoped_ptr
<protocol::CandidateSessionConfig
> config
) {
340 DCHECK(CalledOnValidThread());
341 DCHECK(config
.get());
343 protocol_config_
= config
.Pass();
346 void ChromotingHost::DisconnectAllClients() {
347 DCHECK(CalledOnValidThread());
349 while (!clients_
.empty()) {
350 size_t size
= clients_
.size();
351 clients_
.front()->DisconnectSession();
352 CHECK_EQ(clients_
.size(), size
- 1);
356 } // namespace remoting