Home | History | Annotate | Download | only in protocol
      1 // Copyright 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/protocol/connection_to_client.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/location.h"
      9 #include "base/message_loop/message_loop_proxy.h"
     10 #include "net/base/io_buffer.h"
     11 #include "remoting/protocol/clipboard_stub.h"
     12 #include "remoting/protocol/host_control_dispatcher.h"
     13 #include "remoting/protocol/host_event_dispatcher.h"
     14 #include "remoting/protocol/host_stub.h"
     15 #include "remoting/protocol/host_video_dispatcher.h"
     16 #include "remoting/protocol/input_stub.h"
     17 
     18 namespace remoting {
     19 namespace protocol {
     20 
     21 ConnectionToClient::ConnectionToClient(protocol::Session* session)
     22     : handler_(NULL),
     23       clipboard_stub_(NULL),
     24       host_stub_(NULL),
     25       input_stub_(NULL),
     26       session_(session) {
     27   session_->SetEventHandler(this);
     28 }
     29 
     30 ConnectionToClient::~ConnectionToClient() {
     31 }
     32 
     33 void ConnectionToClient::SetEventHandler(EventHandler* event_handler) {
     34   DCHECK(CalledOnValidThread());
     35   handler_ = event_handler;
     36 }
     37 
     38 protocol::Session* ConnectionToClient::session() {
     39   DCHECK(CalledOnValidThread());
     40   return session_.get();
     41 }
     42 
     43 void ConnectionToClient::Disconnect() {
     44   DCHECK(CalledOnValidThread());
     45 
     46   CloseChannels();
     47 
     48   // This should trigger OnConnectionClosed() event and this object
     49   // may be destroyed as the result.
     50   session_->Close();
     51 }
     52 
     53 void ConnectionToClient::UpdateSequenceNumber(int64 sequence_number) {
     54   DCHECK(CalledOnValidThread());
     55   handler_->OnSequenceNumberUpdated(this, sequence_number);
     56 }
     57 
     58 VideoStub* ConnectionToClient::video_stub() {
     59   DCHECK(CalledOnValidThread());
     60   return video_dispatcher_.get();
     61 }
     62 
     63 AudioStub* ConnectionToClient::audio_stub() {
     64   DCHECK(CalledOnValidThread());
     65   return audio_writer_.get();
     66 }
     67 
     68 // Return pointer to ClientStub.
     69 ClientStub* ConnectionToClient::client_stub() {
     70   DCHECK(CalledOnValidThread());
     71   return control_dispatcher_.get();
     72 }
     73 
     74 void ConnectionToClient::set_clipboard_stub(
     75     protocol::ClipboardStub* clipboard_stub) {
     76   DCHECK(CalledOnValidThread());
     77   clipboard_stub_ = clipboard_stub;
     78 }
     79 
     80 ClipboardStub* ConnectionToClient::clipboard_stub() {
     81   DCHECK(CalledOnValidThread());
     82   return clipboard_stub_;
     83 }
     84 
     85 void ConnectionToClient::set_host_stub(protocol::HostStub* host_stub) {
     86   DCHECK(CalledOnValidThread());
     87   host_stub_ = host_stub;
     88 }
     89 
     90 HostStub* ConnectionToClient::host_stub() {
     91   DCHECK(CalledOnValidThread());
     92   return host_stub_;
     93 }
     94 
     95 void ConnectionToClient::set_input_stub(protocol::InputStub* input_stub) {
     96   DCHECK(CalledOnValidThread());
     97   input_stub_ = input_stub;
     98 }
     99 
    100 InputStub* ConnectionToClient::input_stub() {
    101   DCHECK(CalledOnValidThread());
    102   return input_stub_;
    103 }
    104 
    105 void ConnectionToClient::OnSessionStateChange(Session::State state) {
    106   DCHECK(CalledOnValidThread());
    107 
    108   DCHECK(handler_);
    109   switch(state) {
    110     case Session::INITIALIZING:
    111     case Session::CONNECTING:
    112     case Session::ACCEPTING:
    113     case Session::CONNECTED:
    114       // Don't care about these events.
    115       break;
    116     case Session::AUTHENTICATING:
    117       handler_->OnConnectionAuthenticating(this);
    118       break;
    119     case Session::AUTHENTICATED:
    120       // Initialize channels.
    121       control_dispatcher_.reset(new HostControlDispatcher());
    122       control_dispatcher_->Init(
    123           session_.get(), session_->config().control_config(),
    124           base::Bind(&ConnectionToClient::OnChannelInitialized,
    125                      base::Unretained(this)));
    126       control_dispatcher_->set_clipboard_stub(clipboard_stub_);
    127       control_dispatcher_->set_host_stub(host_stub_);
    128 
    129       event_dispatcher_.reset(new HostEventDispatcher());
    130       event_dispatcher_->Init(
    131           session_.get(), session_->config().event_config(),
    132           base::Bind(&ConnectionToClient::OnChannelInitialized,
    133                      base::Unretained(this)));
    134       event_dispatcher_->set_input_stub(input_stub_);
    135       event_dispatcher_->set_sequence_number_callback(base::Bind(
    136           &ConnectionToClient::UpdateSequenceNumber, base::Unretained(this)));
    137 
    138       video_dispatcher_.reset(new HostVideoDispatcher());
    139       video_dispatcher_->Init(
    140           session_.get(), session_->config().video_config(),
    141           base::Bind(&ConnectionToClient::OnChannelInitialized,
    142                      base::Unretained(this)));
    143 
    144       audio_writer_ = AudioWriter::Create(session_->config());
    145       if (audio_writer_.get()) {
    146         audio_writer_->Init(
    147             session_.get(), session_->config().audio_config(),
    148             base::Bind(&ConnectionToClient::OnChannelInitialized,
    149                        base::Unretained(this)));
    150       }
    151 
    152       // Notify the handler after initializing the channels, so that
    153       // ClientSession can get a client clipboard stub.
    154       handler_->OnConnectionAuthenticated(this);
    155       break;
    156 
    157     case Session::CLOSED:
    158       Close(OK);
    159       break;
    160 
    161     case Session::FAILED:
    162       Close(session_->error());
    163       break;
    164   }
    165 }
    166 
    167 void ConnectionToClient::OnSessionRouteChange(
    168     const std::string& channel_name,
    169     const TransportRoute& route) {
    170   handler_->OnRouteChange(this, channel_name, route);
    171 }
    172 
    173 void ConnectionToClient::OnChannelInitialized(bool successful) {
    174   DCHECK(CalledOnValidThread());
    175 
    176   if (!successful) {
    177     LOG(ERROR) << "Failed to connect a channel";
    178     Close(CHANNEL_CONNECTION_ERROR);
    179     return;
    180   }
    181 
    182   NotifyIfChannelsReady();
    183 }
    184 
    185 void ConnectionToClient::NotifyIfChannelsReady() {
    186   DCHECK(CalledOnValidThread());
    187 
    188   if (!control_dispatcher_.get() || !control_dispatcher_->is_connected())
    189     return;
    190   if (!event_dispatcher_.get() || !event_dispatcher_->is_connected())
    191     return;
    192   if (!video_dispatcher_.get() || !video_dispatcher_->is_connected())
    193     return;
    194   if ((!audio_writer_.get() || !audio_writer_->is_connected()) &&
    195       session_->config().is_audio_enabled()) {
    196     return;
    197   }
    198   handler_->OnConnectionChannelsConnected(this);
    199 }
    200 
    201 void ConnectionToClient::Close(ErrorCode error) {
    202   CloseChannels();
    203   handler_->OnConnectionClosed(this, error);
    204 }
    205 
    206 void ConnectionToClient::CloseChannels() {
    207   control_dispatcher_.reset();
    208   event_dispatcher_.reset();
    209   video_dispatcher_.reset();
    210   audio_writer_.reset();
    211 }
    212 
    213 }  // namespace protocol
    214 }  // namespace remoting
    215