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"
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"
28 ConnectionToHostImpl::ConnectionToHostImpl()
29 : event_callback_(nullptr),
30 client_stub_(nullptr),
31 clipboard_stub_(nullptr),
33 signal_strategy_(nullptr),
37 ConnectionToHostImpl::~ConnectionToHostImpl() {
43 if (session_manager_
.get())
44 session_manager_
.reset();
47 signal_strategy_
->RemoveListener(this);
50 #define RETURN_STRING_LITERAL(x) \
54 const char* ConnectionToHost::StateToString(State 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
);
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
) {
74 DCHECK(clipboard_stub_
);
75 DCHECK(monitored_video_stub_
);
77 // Initialize default |candidate_config_| if set_candidate_config() wasn't
79 if (!candidate_config_
)
80 candidate_config_
= CandidateSessionConfig::CreateDefault();
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.
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
) {
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
) {
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(
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_
);
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.
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(),
207 video_dispatcher_
.reset(
208 new ClientVideoDispatcher(monitored_video_stub_
.get()));
209 video_dispatcher_
->Init(session_
.get(), session_
->config().video_config(),
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(),
219 case Session::CLOSED
:
221 SetState(CLOSED
, OK
);
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
) {
235 SetState(CLOSED
, OK
);
237 CloseOnError(session_
->error());
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
,
256 LOG(ERROR
) << "Failed to connect channel " << channel_dispatcher
;
257 CloseOnError(CHANNEL_CONNECTION_ERROR
);
261 void ConnectionToHostImpl::OnVideoChannelStatus(bool active
) {
262 event_callback_
->OnConnectionReady(active
);
265 ConnectionToHost::State
ConnectionToHostImpl::state() const {
269 void ConnectionToHostImpl::NotifyIfChannelsReady() {
270 if (!control_dispatcher_
.get() || !control_dispatcher_
->is_connected())
272 if (!event_dispatcher_
.get() || !event_dispatcher_
->is_connected())
274 if (!video_dispatcher_
.get() || !video_dispatcher_
->is_connected())
276 if ((!audio_reader_
.get() || !audio_reader_
->is_connected()) &&
277 session_
->config().is_audio_enabled()) {
280 if (state_
!= AUTHENTICATED
)
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
) {
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_
) {
311 event_callback_
->OnConnectionState(state_
, error_
);
315 } // namespace protocol
316 } // namespace remoting