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/message_loop/message_loop_proxy.h" 12 #include "build/build_config.h" 13 #include "remoting/base/constants.h" 14 #include "remoting/base/logging.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 HOST_LOG << "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 HOST_LOG << "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 329