Home | History | Annotate | Download | only in host
      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