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.
4
5 #include "remoting/host/chromoting_host.h"
6
7 #include <algorithm>
8
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/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"
26
27 using remoting::protocol::ConnectionToClient;
28 using remoting::protocol::InputStub;
29
30 namespace remoting {
31
32 namespace {
33
34 const net::BackoffEntry::Policy kDefaultBackoffPolicy = {
35 // Number of initial errors (in sequence) to ignore before applying
36 // exponential back-off rules.
37 0,
38
39 // Initial delay for exponential back-off in ms.
40 2000,
41
42 // Factor by which the waiting time will be multiplied.
43 2,
44
45 // Fuzzing percentage. ex: 10% will spread requests randomly
46 // between 90%-100% of the calculated time.
47 0,
48
49 // Maximum amount of time we are willing to delay our request in ms.
50 -1,
51
52 // Time to keep an entry from being discarded even when it
53 // has no significant state, -1 to never discard.
54 -1,
55
56 // Don't use initial delay unless the last request was an error.
57 false,
58 };
59
60 } // namespace
61
ChromotingHost(SignalStrategy * signal_strategy,DesktopEnvironmentFactory * desktop_environment_factory,scoped_ptr<protocol::SessionManager> session_manager,scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner,scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,scoped_refptr<base::SingleThreadTaskRunner> video_capture_task_runner,scoped_refptr<base::SingleThreadTaskRunner> video_encode_task_runner,scoped_refptr<base::SingleThreadTaskRunner> network_task_runner,scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)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);
90
91 jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop();
92
93 if (!desktop_environment_factory_->SupportsAudioCapture()) {
94 protocol_config_->DisableAudioChannel();
95 }
96 }
97
~ChromotingHost()98 ChromotingHost::~ChromotingHost() {
99 DCHECK(CalledOnValidThread());
100
101 // Disconnect all of the clients.
102 while (!clients_.empty()) {
103 clients_.front()->DisconnectSession();
104 }
105
106 // Destroy the session manager to make sure that |signal_strategy_| does not
107 // have any listeners registered.
108 session_manager_.reset();
109
110 // Notify observers.
111 if (started_)
112 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, OnShutdown());
113 }
114
Start(const std::string & host_owner)115 void ChromotingHost::Start(const std::string& host_owner) {
116 DCHECK(CalledOnValidThread());
117 DCHECK(!started_);
118
119 HOST_LOG << "Starting host";
120 started_ = true;
121 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, OnStart(host_owner));
122
123 // Start the SessionManager, supplying this ChromotingHost as the listener.
124 session_manager_->Init(signal_strategy_, this);
125 }
126
AddStatusObserver(HostStatusObserver * observer)127 void ChromotingHost::AddStatusObserver(HostStatusObserver* observer) {
128 DCHECK(CalledOnValidThread());
129 status_observers_.AddObserver(observer);
130 }
131
RemoveStatusObserver(HostStatusObserver * observer)132 void ChromotingHost::RemoveStatusObserver(HostStatusObserver* observer) {
133 DCHECK(CalledOnValidThread());
134 status_observers_.RemoveObserver(observer);
135 }
136
AddExtension(scoped_ptr<HostExtension> extension)137 void ChromotingHost::AddExtension(scoped_ptr<HostExtension> extension) {
138 extensions_.push_back(extension.release());
139 }
140
RejectAuthenticatingClient()141 void ChromotingHost::RejectAuthenticatingClient() {
142 DCHECK(authenticating_client_);
143 reject_authenticating_client_ = true;
144 }
145
SetAuthenticatorFactory(scoped_ptr<protocol::AuthenticatorFactory> authenticator_factory)146 void ChromotingHost::SetAuthenticatorFactory(
147 scoped_ptr<protocol::AuthenticatorFactory> authenticator_factory) {
148 DCHECK(CalledOnValidThread());
149 session_manager_->set_authenticator_factory(authenticator_factory.Pass());
150 }
151
SetEnableCurtaining(bool enable)152 void ChromotingHost::SetEnableCurtaining(bool enable) {
153 DCHECK(network_task_runner_->BelongsToCurrentThread());
154
155 if (enable_curtaining_ == enable)
156 return;
157
158 enable_curtaining_ = enable;
159 desktop_environment_factory_->SetEnableCurtaining(enable_curtaining_);
160
161 // Disconnect all existing clients because they might be running not
162 // curtained.
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();
168 }
169
SetMaximumSessionDuration(const base::TimeDelta & max_session_duration)170 void ChromotingHost::SetMaximumSessionDuration(
171 const base::TimeDelta& max_session_duration) {
172 max_session_duration_ = max_session_duration;
173 }
174
175 ////////////////////////////////////////////////////////////////////////////
176 // protocol::ClientSession::EventHandler implementation.
OnSessionAuthenticating(ClientSession * client)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();
186 return;
187 }
188 login_backoff_.InformOfRequest(false);
189 }
190
OnSessionAuthenticated(ClientSession * client)191 bool ChromotingHost::OnSessionAuthenticated(ClientSession* client) {
192 DCHECK(CalledOnValidThread());
193
194 login_backoff_.Reset();
195
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
198 // the list.
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();
204 }
205
206 // Disconnects above must have destroyed all other clients.
207 DCHECK_EQ(clients_.size(), 1U);
208
209 // Notify observers that there is at least one authenticated client.
210 const std::string& jid = client->client_jid();
211
212 reject_authenticating_client_ = false;
213
214 authenticating_client_ = true;
215 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
216 OnClientAuthenticated(jid));
217 authenticating_client_ = false;
218
219 return !reject_authenticating_client_;
220 }
221
OnSessionChannelsConnected(ClientSession * client)222 void ChromotingHost::OnSessionChannelsConnected(ClientSession* client) {
223 DCHECK(CalledOnValidThread());
224
225 // Notify observers.
226 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
227 OnClientConnected(client->client_jid()));
228 }
229
OnSessionClientCapabilities(ClientSession * client)230 void ChromotingHost::OnSessionClientCapabilities(ClientSession* client) {
231 DCHECK(CalledOnValidThread());
232
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());
240 }
241 }
242
OnSessionAuthenticationFailed(ClientSession * client)243 void ChromotingHost::OnSessionAuthenticationFailed(ClientSession* client) {
244 DCHECK(CalledOnValidThread());
245
246 // Notify observers.
247 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
248 OnAccessDenied(client->client_jid()));
249 }
250
OnSessionClosed(ClientSession * client)251 void ChromotingHost::OnSessionClosed(ClientSession* client) {
252 DCHECK(CalledOnValidThread());
253
254 ClientList::iterator it = std::find(clients_.begin(), clients_.end(), client);
255 CHECK(it != clients_.end());
256
257 if (client->is_authenticated()) {
258 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
259 OnClientDisconnected(client->client_jid()));
260 }
261
262 clients_.erase(it);
263 delete client;
264 }
265
OnSessionSequenceNumber(ClientSession * session,int64 sequence_number)266 void ChromotingHost::OnSessionSequenceNumber(ClientSession* session,
267 int64 sequence_number) {
268 DCHECK(CalledOnValidThread());
269 }
270
OnSessionRouteChange(ClientSession * session,const std::string & channel_name,const protocol::TransportRoute & route)271 void ChromotingHost::OnSessionRouteChange(
272 ClientSession* session,
273 const std::string& channel_name,
274 const protocol::TransportRoute& route) {
275 DCHECK(CalledOnValidThread());
276 FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
277 OnClientRouteChange(session->client_jid(), channel_name,
278 route));
279 }
280
OnSessionManagerReady()281 void ChromotingHost::OnSessionManagerReady() {
282 DCHECK(CalledOnValidThread());
283 // Don't need to do anything here, just wait for incoming
284 // connections.
285 }
286
OnIncomingSession(protocol::Session * session,protocol::SessionManager::IncomingSessionResponse * response)287 void ChromotingHost::OnIncomingSession(
288 protocol::Session* session,
289 protocol::SessionManager::IncomingSessionResponse* response) {
290 DCHECK(CalledOnValidThread());
291
292 if (!started_) {
293 *response = protocol::SessionManager::DECLINE;
294 return;
295 }
296
297 if (login_backoff_.ShouldRejectRequest()) {
298 LOG(WARNING) << "Rejecting connection due to"
299 " an overload of failed login attempts.";
300 *response = protocol::SessionManager::OVERLOAD;
301 return;
302 }
303
304 protocol::SessionConfig config;
305 if (!protocol_config_->Select(session->candidate_config(), &config)) {
306 LOG(WARNING) << "Rejecting connection from " << session->jid()
307 << " because no compatible configuration has been found.";
308 *response = protocol::SessionManager::INCOMPATIBLE;
309 return;
310 }
311
312 session->set_config(config);
313
314 *response = protocol::SessionManager::ACCEPT;
315
316 HOST_LOG << "Client connected: " << session->jid();
317
318 // Create a client object.
319 scoped_ptr<protocol::ConnectionToClient> connection(
320 new protocol::ConnectionToClient(session));
321 ClientSession* client = new ClientSession(
322 this,
323 audio_task_runner_,
324 input_task_runner_,
325 video_capture_task_runner_,
326 video_encode_task_runner_,
327 network_task_runner_,
328 ui_task_runner_,
329 connection.Pass(),
330 desktop_environment_factory_,
331 max_session_duration_,
332 pairing_registry_);
333
334 // Registers capabilities provided by host extensions.
335 for (HostExtensionList::iterator extension = extensions_.begin();
336 extension != extensions_.end(); ++extension) {
337 client->AddHostCapabilities((*extension)->GetCapabilities());
338 }
339
340 clients_.push_back(client);
341 }
342
set_protocol_config(scoped_ptr<protocol::CandidateSessionConfig> config)343 void ChromotingHost::set_protocol_config(
344 scoped_ptr<protocol::CandidateSessionConfig> config) {
345 DCHECK(CalledOnValidThread());
346 DCHECK(config.get());
347 DCHECK(!started_);
348 protocol_config_ = config.Pass();
349 }
350
DisconnectAllClients()351 void ChromotingHost::DisconnectAllClients() {
352 DCHECK(CalledOnValidThread());
353
354 while (!clients_.empty()) {
355 size_t size = clients_.size();
356 clients_.front()->DisconnectSession();
357 CHECK_EQ(clients_.size(), size - 1);
358 }
359 }
360
361 } // namespace remoting
362