- add sources.
[platform/framework/web/crosswalk.git] / src / remoting / host / chromoting_host.cc
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/logging.h"
12 #include "base/message_loop/message_loop_proxy.h"
13 #include "build/build_config.h"
14 #include "remoting/base/constants.h"
15 #include "remoting/host/chromoting_host_context.h"
16 #include "remoting/host/desktop_environment.h"
17 #include "remoting/host/host_config.h"
18 #include "remoting/host/input_injector.h"
19 #include "remoting/protocol/connection_to_client.h"
20 #include "remoting/protocol/client_stub.h"
21 #include "remoting/protocol/host_stub.h"
22 #include "remoting/protocol/input_stub.h"
23 #include "remoting/protocol/session_config.h"
24
25 using remoting::protocol::ConnectionToClient;
26 using remoting::protocol::InputStub;
27
28 namespace remoting {
29
30 namespace {
31
32 const net::BackoffEntry::Policy kDefaultBackoffPolicy = {
33   // Number of initial errors (in sequence) to ignore before applying
34   // exponential back-off rules.
35   0,
36
37   // Initial delay for exponential back-off in ms.
38   2000,
39
40   // Factor by which the waiting time will be multiplied.
41   2,
42
43   // Fuzzing percentage. ex: 10% will spread requests randomly
44   // between 90%-100% of the calculated time.
45   0,
46
47   // Maximum amount of time we are willing to delay our request in ms.
48   -1,
49
50   // Time to keep an entry from being discarded even when it
51   // has no significant state, -1 to never discard.
52   -1,
53
54   // Don't use initial delay unless the last request was an error.
55   false,
56 };
57
58 }  // namespace
59
60 ChromotingHost::ChromotingHost(
61     SignalStrategy* signal_strategy,
62     DesktopEnvironmentFactory* desktop_environment_factory,
63     scoped_ptr<protocol::SessionManager> session_manager,
64     scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner,
65     scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
66     scoped_refptr<base::SingleThreadTaskRunner> video_capture_task_runner,
67     scoped_refptr<base::SingleThreadTaskRunner> video_encode_task_runner,
68     scoped_refptr<base::SingleThreadTaskRunner> network_task_runner,
69     scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
70     : desktop_environment_factory_(desktop_environment_factory),
71       session_manager_(session_manager.Pass()),
72       audio_task_runner_(audio_task_runner),
73       input_task_runner_(input_task_runner),
74       video_capture_task_runner_(video_capture_task_runner),
75       video_encode_task_runner_(video_encode_task_runner),
76       network_task_runner_(network_task_runner),
77       ui_task_runner_(ui_task_runner),
78       signal_strategy_(signal_strategy),
79       started_(false),
80       protocol_config_(protocol::CandidateSessionConfig::CreateDefault()),
81       login_backoff_(&kDefaultBackoffPolicy),
82       authenticating_client_(false),
83       reject_authenticating_client_(false),
84       enable_curtaining_(false),
85       weak_factory_(this) {
86   DCHECK(network_task_runner_->BelongsToCurrentThread());
87   DCHECK(signal_strategy);
88
89   // VP9 encode is not yet supported.
90   protocol::CandidateSessionConfig::DisableVideoCodec(
91       protocol_config_.get(), protocol::ChannelConfig::CODEC_VP9);
92
93   if (!desktop_environment_factory_->SupportsAudioCapture()) {
94     protocol::CandidateSessionConfig::DisableAudioChannel(
95         protocol_config_.get());
96   }
97 }
98
99 ChromotingHost::~ChromotingHost() {
100   DCHECK(CalledOnValidThread());
101
102   // Disconnect all of the clients.
103   while (!clients_.empty()) {
104     clients_.front()->DisconnectSession();
105   }
106
107   // Destroy the session manager to make sure that |signal_strategy_| does not
108   // have any listeners registered.
109   session_manager_.reset();
110
111   // Notify observers.
112   if (started_)
113     FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, OnShutdown());
114 }
115
116 void ChromotingHost::Start(const std::string& host_owner) {
117   DCHECK(CalledOnValidThread());
118   DCHECK(!started_);
119
120   LOG(INFO) << "Starting host";
121   started_ = true;
122   FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, OnStart(host_owner));
123
124   // Start the SessionManager, supplying this ChromotingHost as the listener.
125   session_manager_->Init(signal_strategy_, this);
126 }
127
128 void ChromotingHost::AddStatusObserver(HostStatusObserver* observer) {
129   DCHECK(CalledOnValidThread());
130   status_observers_.AddObserver(observer);
131 }
132
133 void ChromotingHost::RemoveStatusObserver(HostStatusObserver* observer) {
134   DCHECK(CalledOnValidThread());
135   status_observers_.RemoveObserver(observer);
136 }
137
138 void ChromotingHost::RejectAuthenticatingClient() {
139   DCHECK(authenticating_client_);
140   reject_authenticating_client_ = true;
141 }
142
143 void ChromotingHost::SetAuthenticatorFactory(
144     scoped_ptr<protocol::AuthenticatorFactory> authenticator_factory) {
145   DCHECK(CalledOnValidThread());
146   session_manager_->set_authenticator_factory(authenticator_factory.Pass());
147 }
148
149 void ChromotingHost::SetEnableCurtaining(bool enable) {
150   DCHECK(network_task_runner_->BelongsToCurrentThread());
151
152   if (enable_curtaining_ == enable)
153     return;
154
155   enable_curtaining_ = enable;
156   desktop_environment_factory_->SetEnableCurtaining(enable_curtaining_);
157
158   // Disconnect all existing clients because they might be running not
159   // curtained.
160   // TODO(alexeypa): fix this such that the curtain is applied to the not
161   // curtained sessions or disconnect only the client connected to not
162   // curtained sessions.
163   if (enable_curtaining_)
164     DisconnectAllClients();
165 }
166
167 void ChromotingHost::SetMaximumSessionDuration(
168     const base::TimeDelta& max_session_duration) {
169   max_session_duration_ = max_session_duration;
170 }
171
172 ////////////////////////////////////////////////////////////////////////////
173 // protocol::ClientSession::EventHandler implementation.
174 bool ChromotingHost::OnSessionAuthenticated(ClientSession* client) {
175   DCHECK(CalledOnValidThread());
176
177   login_backoff_.Reset();
178
179   // Disconnect all other clients. |it| should be advanced before Disconnect()
180   // is called to avoid it becoming invalid when the client is removed from
181   // the list.
182   ClientList::iterator it = clients_.begin();
183   while (it != clients_.end()) {
184     ClientSession* other_client = *it++;
185     if (other_client != client)
186       other_client->DisconnectSession();
187   }
188
189   // Disconnects above must have destroyed all other clients.
190   DCHECK_EQ(clients_.size(), 1U);
191
192   // Notify observers that there is at least one authenticated client.
193   const std::string& jid = client->client_jid();
194
195   reject_authenticating_client_ = false;
196
197   authenticating_client_ = true;
198   FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
199                     OnClientAuthenticated(jid));
200   authenticating_client_ = false;
201
202   return !reject_authenticating_client_;
203 }
204
205 void ChromotingHost::OnSessionChannelsConnected(ClientSession* client) {
206   DCHECK(CalledOnValidThread());
207
208   // Notify observers.
209   FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
210                     OnClientConnected(client->client_jid()));
211 }
212
213 void ChromotingHost::OnSessionAuthenticationFailed(ClientSession* client) {
214   DCHECK(CalledOnValidThread());
215
216   // Notify observers.
217   FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
218                     OnAccessDenied(client->client_jid()));
219 }
220
221 void ChromotingHost::OnSessionClosed(ClientSession* client) {
222   DCHECK(CalledOnValidThread());
223
224   ClientList::iterator it = std::find(clients_.begin(), clients_.end(), client);
225   CHECK(it != clients_.end());
226
227   if (client->is_authenticated()) {
228     FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
229                       OnClientDisconnected(client->client_jid()));
230   }
231
232   clients_.erase(it);
233   delete client;
234 }
235
236 void ChromotingHost::OnSessionSequenceNumber(ClientSession* session,
237                                              int64 sequence_number) {
238   DCHECK(CalledOnValidThread());
239 }
240
241 void ChromotingHost::OnSessionRouteChange(
242     ClientSession* session,
243     const std::string& channel_name,
244     const protocol::TransportRoute& route) {
245   DCHECK(CalledOnValidThread());
246   FOR_EACH_OBSERVER(HostStatusObserver, status_observers_,
247                     OnClientRouteChange(session->client_jid(), channel_name,
248                                         route));
249 }
250
251 void ChromotingHost::OnSessionManagerReady() {
252   DCHECK(CalledOnValidThread());
253   // Don't need to do anything here, just wait for incoming
254   // connections.
255 }
256
257 void ChromotingHost::OnIncomingSession(
258       protocol::Session* session,
259       protocol::SessionManager::IncomingSessionResponse* response) {
260   DCHECK(CalledOnValidThread());
261
262   if (!started_) {
263     *response = protocol::SessionManager::DECLINE;
264     return;
265   }
266
267   if (login_backoff_.ShouldRejectRequest()) {
268     *response = protocol::SessionManager::OVERLOAD;
269     return;
270   }
271
272   // We treat each incoming connection as a failure to authenticate,
273   // and clear the backoff when a connection successfully
274   // authenticates. This allows the backoff to protect from parallel
275   // connection attempts as well as sequential ones.
276   login_backoff_.InformOfRequest(false);
277
278   protocol::SessionConfig config;
279   if (!protocol_config_->Select(session->candidate_config(), &config)) {
280     LOG(WARNING) << "Rejecting connection from " << session->jid()
281                  << " because no compatible configuration has been found.";
282     *response = protocol::SessionManager::INCOMPATIBLE;
283     return;
284   }
285
286   session->set_config(config);
287
288   *response = protocol::SessionManager::ACCEPT;
289
290   LOG(INFO) << "Client connected: " << session->jid();
291
292   // Create a client object.
293   scoped_ptr<protocol::ConnectionToClient> connection(
294       new protocol::ConnectionToClient(session));
295   ClientSession* client = new ClientSession(
296       this,
297       audio_task_runner_,
298       input_task_runner_,
299       video_capture_task_runner_,
300       video_encode_task_runner_,
301       network_task_runner_,
302       ui_task_runner_,
303       connection.Pass(),
304       desktop_environment_factory_,
305       max_session_duration_,
306       pairing_registry_);
307   clients_.push_back(client);
308 }
309
310 void ChromotingHost::set_protocol_config(
311     scoped_ptr<protocol::CandidateSessionConfig> config) {
312   DCHECK(CalledOnValidThread());
313   DCHECK(config.get());
314   DCHECK(!started_);
315   protocol_config_ = config.Pass();
316 }
317
318 void ChromotingHost::DisconnectAllClients() {
319   DCHECK(CalledOnValidThread());
320
321   while (!clients_.empty()) {
322     size_t size = clients_.size();
323     clients_.front()->DisconnectSession();
324     CHECK_EQ(clients_.size(), size - 1);
325   }
326 }
327
328 }  // namespace remoting