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