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
ConnectionToClient(protocol::Session * session)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
~ConnectionToClient()30 ConnectionToClient::~ConnectionToClient() {
31 }
32
SetEventHandler(EventHandler * event_handler)33 void ConnectionToClient::SetEventHandler(EventHandler* event_handler) {
34 DCHECK(CalledOnValidThread());
35 handler_ = event_handler;
36 }
37
session()38 protocol::Session* ConnectionToClient::session() {
39 DCHECK(CalledOnValidThread());
40 return session_.get();
41 }
42
Disconnect()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
UpdateSequenceNumber(int64 sequence_number)53 void ConnectionToClient::UpdateSequenceNumber(int64 sequence_number) {
54 DCHECK(CalledOnValidThread());
55 handler_->OnSequenceNumberUpdated(this, sequence_number);
56 }
57
video_stub()58 VideoStub* ConnectionToClient::video_stub() {
59 DCHECK(CalledOnValidThread());
60 return video_dispatcher_.get();
61 }
62
audio_stub()63 AudioStub* ConnectionToClient::audio_stub() {
64 DCHECK(CalledOnValidThread());
65 return audio_writer_.get();
66 }
67
68 // Return pointer to ClientStub.
client_stub()69 ClientStub* ConnectionToClient::client_stub() {
70 DCHECK(CalledOnValidThread());
71 return control_dispatcher_.get();
72 }
73
set_clipboard_stub(protocol::ClipboardStub * clipboard_stub)74 void ConnectionToClient::set_clipboard_stub(
75 protocol::ClipboardStub* clipboard_stub) {
76 DCHECK(CalledOnValidThread());
77 clipboard_stub_ = clipboard_stub;
78 }
79
clipboard_stub()80 ClipboardStub* ConnectionToClient::clipboard_stub() {
81 DCHECK(CalledOnValidThread());
82 return clipboard_stub_;
83 }
84
set_host_stub(protocol::HostStub * host_stub)85 void ConnectionToClient::set_host_stub(protocol::HostStub* host_stub) {
86 DCHECK(CalledOnValidThread());
87 host_stub_ = host_stub;
88 }
89
host_stub()90 HostStub* ConnectionToClient::host_stub() {
91 DCHECK(CalledOnValidThread());
92 return host_stub_;
93 }
94
set_input_stub(protocol::InputStub * input_stub)95 void ConnectionToClient::set_input_stub(protocol::InputStub* input_stub) {
96 DCHECK(CalledOnValidThread());
97 input_stub_ = input_stub;
98 }
99
input_stub()100 InputStub* ConnectionToClient::input_stub() {
101 DCHECK(CalledOnValidThread());
102 return input_stub_;
103 }
104
OnSessionStateChange(Session::State state)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
OnSessionRouteChange(const std::string & channel_name,const TransportRoute & route)167 void ConnectionToClient::OnSessionRouteChange(
168 const std::string& channel_name,
169 const TransportRoute& route) {
170 handler_->OnRouteChange(this, channel_name, route);
171 }
172
OnChannelInitialized(bool successful)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
NotifyIfChannelsReady()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
Close(ErrorCode error)201 void ConnectionToClient::Close(ErrorCode error) {
202 CloseChannels();
203 handler_->OnConnectionClosed(this, error);
204 }
205
CloseChannels()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