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