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 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 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 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 127 void ChromotingHost::AddStatusObserver(HostStatusObserver* observer) { 128 DCHECK(CalledOnValidThread()); 129 status_observers_.AddObserver(observer); 130 } 131 132 void ChromotingHost::RemoveStatusObserver(HostStatusObserver* observer) { 133 DCHECK(CalledOnValidThread()); 134 status_observers_.RemoveObserver(observer); 135 } 136 137 void ChromotingHost::AddExtension(scoped_ptr<HostExtension> extension) { 138 extensions_.push_back(extension.release()); 139 } 140 141 void ChromotingHost::RejectAuthenticatingClient() { 142 DCHECK(authenticating_client_); 143 reject_authenticating_client_ = true; 144 } 145 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 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 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. 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 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 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 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 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 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 266 void ChromotingHost::OnSessionSequenceNumber(ClientSession* session, 267 int64 sequence_number) { 268 DCHECK(CalledOnValidThread()); 269 } 270 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 281 void ChromotingHost::OnSessionManagerReady() { 282 DCHECK(CalledOnValidThread()); 283 // Don't need to do anything here, just wait for incoming 284 // connections. 285 } 286 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 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 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