MD Downloads: prevent search text from overlapping with the cancel search (X)
[chromium-blink-merge.git] / remoting / protocol / connection_to_host_impl.cc
blobd238679053c29333d2cc2e2bc67d30a3131c4bcf
1 // Copyright 2015 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.
5 #include "remoting/protocol/connection_to_host_impl.h"
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/location.h"
10 #include "remoting/base/constants.h"
11 #include "remoting/protocol/audio_reader.h"
12 #include "remoting/protocol/audio_stub.h"
13 #include "remoting/protocol/auth_util.h"
14 #include "remoting/protocol/authenticator.h"
15 #include "remoting/protocol/client_control_dispatcher.h"
16 #include "remoting/protocol/client_event_dispatcher.h"
17 #include "remoting/protocol/client_stub.h"
18 #include "remoting/protocol/client_video_dispatcher.h"
19 #include "remoting/protocol/clipboard_stub.h"
20 #include "remoting/protocol/errors.h"
21 #include "remoting/protocol/jingle_session_manager.h"
22 #include "remoting/protocol/transport.h"
23 #include "remoting/protocol/video_stub.h"
25 namespace remoting {
26 namespace protocol {
28 ConnectionToHostImpl::ConnectionToHostImpl()
29 : event_callback_(nullptr),
30 client_stub_(nullptr),
31 clipboard_stub_(nullptr),
32 audio_stub_(nullptr),
33 signal_strategy_(nullptr),
34 state_(INITIALIZING),
35 error_(OK) {}
37 ConnectionToHostImpl::~ConnectionToHostImpl() {
38 CloseChannels();
40 if (session_.get())
41 session_.reset();
43 if (session_manager_.get())
44 session_manager_.reset();
46 if (signal_strategy_)
47 signal_strategy_->RemoveListener(this);
50 #define RETURN_STRING_LITERAL(x) \
51 case x: \
52 return #x;
54 const char* ConnectionToHost::StateToString(State state) {
55 switch (state) {
56 RETURN_STRING_LITERAL(INITIALIZING);
57 RETURN_STRING_LITERAL(CONNECTING);
58 RETURN_STRING_LITERAL(AUTHENTICATED);
59 RETURN_STRING_LITERAL(CONNECTED);
60 RETURN_STRING_LITERAL(CLOSED);
61 RETURN_STRING_LITERAL(FAILED);
63 NOTREACHED();
64 return nullptr;
67 void ConnectionToHostImpl::Connect(
68 SignalStrategy* signal_strategy,
69 scoped_ptr<TransportFactory> transport_factory,
70 scoped_ptr<Authenticator> authenticator,
71 const std::string& host_jid,
72 HostEventCallback* event_callback) {
73 DCHECK(client_stub_);
74 DCHECK(clipboard_stub_);
75 DCHECK(monitored_video_stub_);
77 // Initialize default |candidate_config_| if set_candidate_config() wasn't
78 // called.
79 if (!candidate_config_)
80 candidate_config_ = CandidateSessionConfig::CreateDefault();
81 if (!audio_stub_)
82 candidate_config_->DisableAudioChannel();
84 signal_strategy_ = signal_strategy;
85 event_callback_ = event_callback;
86 authenticator_ = authenticator.Pass();
88 // Save jid of the host. The actual connection is created later after
89 // |signal_strategy_| is connected.
90 host_jid_ = host_jid;
92 signal_strategy_->AddListener(this);
93 signal_strategy_->Connect();
95 session_manager_.reset(new JingleSessionManager(transport_factory.Pass()));
96 session_manager_->set_protocol_config(candidate_config_->Clone());
97 session_manager_->Init(signal_strategy_, this);
99 SetState(CONNECTING, OK);
102 void ConnectionToHostImpl::set_candidate_config(
103 scoped_ptr<CandidateSessionConfig> config) {
104 DCHECK_EQ(state_, INITIALIZING);
106 candidate_config_ = config.Pass();
109 const SessionConfig& ConnectionToHostImpl::config() {
110 return session_->config();
113 ClipboardStub* ConnectionToHostImpl::clipboard_forwarder() {
114 return &clipboard_forwarder_;
117 HostStub* ConnectionToHostImpl::host_stub() {
118 // TODO(wez): Add a HostFilter class, equivalent to input filter.
119 return control_dispatcher_.get();
122 InputStub* ConnectionToHostImpl::input_stub() {
123 return &event_forwarder_;
126 void ConnectionToHostImpl::set_client_stub(ClientStub* client_stub) {
127 client_stub_ = client_stub;
130 void ConnectionToHostImpl::set_clipboard_stub(ClipboardStub* clipboard_stub) {
131 clipboard_stub_ = clipboard_stub;
134 void ConnectionToHostImpl::set_video_stub(VideoStub* video_stub) {
135 DCHECK(video_stub);
136 monitored_video_stub_.reset(new MonitoredVideoStub(
137 video_stub, base::TimeDelta::FromSeconds(
138 MonitoredVideoStub::kConnectivityCheckDelaySeconds),
139 base::Bind(&ConnectionToHostImpl::OnVideoChannelStatus,
140 base::Unretained(this))));
143 void ConnectionToHostImpl::set_audio_stub(AudioStub* audio_stub) {
144 audio_stub_ = audio_stub;
147 void ConnectionToHostImpl::OnSignalStrategyStateChange(
148 SignalStrategy::State state) {
149 DCHECK(CalledOnValidThread());
150 DCHECK(event_callback_);
152 if (state == SignalStrategy::CONNECTED) {
153 VLOG(1) << "Connected as: " << signal_strategy_->GetLocalJid();
154 } else if (state == SignalStrategy::DISCONNECTED) {
155 VLOG(1) << "Connection closed.";
156 CloseOnError(SIGNALING_ERROR);
160 bool ConnectionToHostImpl::OnSignalStrategyIncomingStanza(
161 const buzz::XmlElement* stanza) {
162 return false;
165 void ConnectionToHostImpl::OnSessionManagerReady() {
166 DCHECK(CalledOnValidThread());
168 // After SessionManager is initialized we can try to connect to the host.
169 session_ = session_manager_->Connect(host_jid_, authenticator_.Pass());
170 session_->SetEventHandler(this);
173 void ConnectionToHostImpl::OnIncomingSession(
174 Session* session,
175 SessionManager::IncomingSessionResponse* response) {
176 DCHECK(CalledOnValidThread());
177 // Client always rejects incoming sessions.
178 *response = SessionManager::DECLINE;
181 void ConnectionToHostImpl::OnSessionStateChange(Session::State state) {
182 DCHECK(CalledOnValidThread());
183 DCHECK(event_callback_);
185 switch (state) {
186 case Session::INITIALIZING:
187 case Session::CONNECTING:
188 case Session::ACCEPTING:
189 case Session::CONNECTED:
190 case Session::AUTHENTICATING:
191 // Don't care about these events.
192 break;
194 case Session::AUTHENTICATED:
195 SetState(AUTHENTICATED, OK);
197 control_dispatcher_.reset(new ClientControlDispatcher());
198 control_dispatcher_->Init(session_.get(),
199 session_->config().control_config(), this);
200 control_dispatcher_->set_client_stub(client_stub_);
201 control_dispatcher_->set_clipboard_stub(clipboard_stub_);
203 event_dispatcher_.reset(new ClientEventDispatcher());
204 event_dispatcher_->Init(session_.get(), session_->config().event_config(),
205 this);
207 video_dispatcher_.reset(
208 new ClientVideoDispatcher(monitored_video_stub_.get()));
209 video_dispatcher_->Init(session_.get(), session_->config().video_config(),
210 this);
212 if (session_->config().is_audio_enabled()) {
213 audio_reader_.reset(new AudioReader(audio_stub_));
214 audio_reader_->Init(session_.get(), session_->config().audio_config(),
215 this);
217 break;
219 case Session::CLOSED:
220 CloseChannels();
221 SetState(CLOSED, OK);
222 break;
224 case Session::FAILED:
225 // If we were connected then treat signaling timeout error as if
226 // the connection was closed by the peer.
228 // TODO(sergeyu): This logic belongs to the webapp, but we
229 // currently don't expose this error code to the webapp, and it
230 // would be hard to add it because client plugin and webapp
231 // versions may not be in sync. It should be easy to do after we
232 // are finished moving the client plugin to NaCl.
233 if (state_ == CONNECTED && session_->error() == SIGNALING_TIMEOUT) {
234 CloseChannels();
235 SetState(CLOSED, OK);
236 } else {
237 CloseOnError(session_->error());
239 break;
243 void ConnectionToHostImpl::OnSessionRouteChange(const std::string& channel_name,
244 const TransportRoute& route) {
245 event_callback_->OnRouteChanged(channel_name, route);
248 void ConnectionToHostImpl::OnChannelInitialized(
249 ChannelDispatcherBase* channel_dispatcher) {
250 NotifyIfChannelsReady();
253 void ConnectionToHostImpl::OnChannelError(
254 ChannelDispatcherBase* channel_dispatcher,
255 ErrorCode error) {
256 LOG(ERROR) << "Failed to connect channel " << channel_dispatcher;
257 CloseOnError(CHANNEL_CONNECTION_ERROR);
258 return;
261 void ConnectionToHostImpl::OnVideoChannelStatus(bool active) {
262 event_callback_->OnConnectionReady(active);
265 ConnectionToHost::State ConnectionToHostImpl::state() const {
266 return state_;
269 void ConnectionToHostImpl::NotifyIfChannelsReady() {
270 if (!control_dispatcher_.get() || !control_dispatcher_->is_connected())
271 return;
272 if (!event_dispatcher_.get() || !event_dispatcher_->is_connected())
273 return;
274 if (!video_dispatcher_.get() || !video_dispatcher_->is_connected())
275 return;
276 if ((!audio_reader_.get() || !audio_reader_->is_connected()) &&
277 session_->config().is_audio_enabled()) {
278 return;
280 if (state_ != AUTHENTICATED)
281 return;
283 // Start forwarding clipboard and input events.
284 clipboard_forwarder_.set_clipboard_stub(control_dispatcher_.get());
285 event_forwarder_.set_input_stub(event_dispatcher_.get());
286 SetState(CONNECTED, OK);
289 void ConnectionToHostImpl::CloseOnError(ErrorCode error) {
290 CloseChannels();
291 SetState(FAILED, error);
294 void ConnectionToHostImpl::CloseChannels() {
295 control_dispatcher_.reset();
296 event_dispatcher_.reset();
297 clipboard_forwarder_.set_clipboard_stub(nullptr);
298 event_forwarder_.set_input_stub(nullptr);
299 video_dispatcher_.reset();
300 audio_reader_.reset();
303 void ConnectionToHostImpl::SetState(State state, ErrorCode error) {
304 DCHECK(CalledOnValidThread());
305 // |error| should be specified only when |state| is set to FAILED.
306 DCHECK(state == FAILED || error == OK);
308 if (state != state_) {
309 state_ = state;
310 error_ = error;
311 event_callback_->OnConnectionState(state_, error_);
315 } // namespace protocol
316 } // namespace remoting