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