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