• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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