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     case Session::AUTHENTICATING:
    116       handler_->OnConnectionAuthenticating(this);
    117       break;
    118     case Session::AUTHENTICATED:
    119       // Initialize channels.
    120       control_dispatcher_.reset(new HostControlDispatcher());
    121       control_dispatcher_->Init(
    122           session_.get(), session_->config().control_config(),
    123           base::Bind(&ConnectionToClient::OnChannelInitialized,
    124                      base::Unretained(this)));
    125       control_dispatcher_->set_clipboard_stub(clipboard_stub_);
    126       control_dispatcher_->set_host_stub(host_stub_);
    127 
    128       event_dispatcher_.reset(new HostEventDispatcher());
    129       event_dispatcher_->Init(
    130           session_.get(), session_->config().event_config(),
    131           base::Bind(&ConnectionToClient::OnChannelInitialized,
    132                      base::Unretained(this)));
    133       event_dispatcher_->set_input_stub(input_stub_);
    134       event_dispatcher_->set_sequence_number_callback(base::Bind(
    135           &ConnectionToClient::UpdateSequenceNumber, base::Unretained(this)));
    136 
    137       video_writer_ = VideoWriter::Create(session_->config());
    138       video_writer_->Init(session_.get(), base::Bind(
    139           &ConnectionToClient::OnChannelInitialized, base::Unretained(this)));
    140 
    141       audio_writer_ = AudioWriter::Create(session_->config());
    142       if (audio_writer_.get()) {
    143         audio_writer_->Init(
    144             session_.get(), session_->config().audio_config(),
    145             base::Bind(&ConnectionToClient::OnChannelInitialized,
    146                        base::Unretained(this)));
    147       }
    148 
    149       // Notify the handler after initializing the channels, so that
    150       // ClientSession can get a client clipboard stub.
    151       handler_->OnConnectionAuthenticated(this);
    152       break;
    153 
    154     case Session::CLOSED:
    155       Close(OK);
    156       break;
    157 
    158     case Session::FAILED:
    159       Close(session_->error());
    160       break;
    161   }
    162 }
    163 
    164 void ConnectionToClient::OnSessionRouteChange(
    165     const std::string& channel_name,
    166     const TransportRoute& route) {
    167   handler_->OnRouteChange(this, channel_name, route);
    168 }
    169 
    170 void ConnectionToClient::OnChannelInitialized(bool successful) {
    171   DCHECK(CalledOnValidThread());
    172 
    173   if (!successful) {
    174     LOG(ERROR) << "Failed to connect a channel";
    175     Close(CHANNEL_CONNECTION_ERROR);
    176     return;
    177   }
    178 
    179   NotifyIfChannelsReady();
    180 }
    181 
    182 void ConnectionToClient::NotifyIfChannelsReady() {
    183   DCHECK(CalledOnValidThread());
    184 
    185   if (!control_dispatcher_.get() || !control_dispatcher_->is_connected())
    186     return;
    187   if (!event_dispatcher_.get() || !event_dispatcher_->is_connected())
    188     return;
    189   if (!video_writer_.get() || !video_writer_->is_connected())
    190     return;
    191   if ((!audio_writer_.get() || !audio_writer_->is_connected()) &&
    192       session_->config().is_audio_enabled()) {
    193     return;
    194   }
    195   handler_->OnConnectionChannelsConnected(this);
    196 }
    197 
    198 void ConnectionToClient::Close(ErrorCode error) {
    199   CloseChannels();
    200   handler_->OnConnectionClosed(this, error);
    201 }
    202 
    203 void ConnectionToClient::CloseChannels() {
    204   control_dispatcher_.reset();
    205   event_dispatcher_.reset();
    206   video_writer_.reset();
    207   audio_writer_.reset();
    208 }
    209 
    210 }  // namespace protocol
    211 }  // namespace remoting
    212