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/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