telemetry: Support custom 'out' directory
[chromium-blink-merge.git] / remoting / protocol / connection_to_host.cc
blob4b4fc893f793a268f83183e54e07548179b58c04
1 // Copyright (c) 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.
5 #include "remoting/protocol/connection_to_host.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/jingle_glue/signal_strategy.h"
12 #include "remoting/protocol/audio_reader.h"
13 #include "remoting/protocol/audio_stub.h"
14 #include "remoting/protocol/auth_util.h"
15 #include "remoting/protocol/authenticator.h"
16 #include "remoting/protocol/client_control_dispatcher.h"
17 #include "remoting/protocol/client_event_dispatcher.h"
18 #include "remoting/protocol/client_stub.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_reader.h"
24 #include "remoting/protocol/video_stub.h"
25 #include "remoting/protocol/util.h"
27 namespace remoting {
28 namespace protocol {
30 ConnectionToHost::ConnectionToHost(
31 bool allow_nat_traversal)
32 : allow_nat_traversal_(allow_nat_traversal),
33 event_callback_(NULL),
34 client_stub_(NULL),
35 clipboard_stub_(NULL),
36 video_stub_(NULL),
37 audio_stub_(NULL),
38 signal_strategy_(NULL),
39 state_(INITIALIZING),
40 error_(OK) {
43 ConnectionToHost::~ConnectionToHost() {
44 CloseChannels();
46 if (session_.get())
47 session_.reset();
49 if (session_manager_.get())
50 session_manager_.reset();
52 if (signal_strategy_)
53 signal_strategy_->RemoveListener(this);
56 ClipboardStub* ConnectionToHost::clipboard_stub() {
57 return &clipboard_forwarder_;
60 HostStub* ConnectionToHost::host_stub() {
61 // TODO(wez): Add a HostFilter class, equivalent to input filter.
62 return control_dispatcher_.get();
65 InputStub* ConnectionToHost::input_stub() {
66 return &event_forwarder_;
69 void ConnectionToHost::Connect(SignalStrategy* signal_strategy,
70 const std::string& host_jid,
71 const std::string& host_public_key,
72 scoped_ptr<TransportFactory> transport_factory,
73 scoped_ptr<Authenticator> authenticator,
74 HostEventCallback* event_callback,
75 ClientStub* client_stub,
76 ClipboardStub* clipboard_stub,
77 VideoStub* video_stub,
78 AudioStub* audio_stub) {
79 signal_strategy_ = signal_strategy;
80 event_callback_ = event_callback;
81 client_stub_ = client_stub;
82 clipboard_stub_ = clipboard_stub;
83 video_stub_ = video_stub;
84 audio_stub_ = audio_stub;
85 authenticator_ = authenticator.Pass();
87 // Save jid of the host. The actual connection is created later after
88 // |signal_strategy_| is connected.
89 host_jid_ = host_jid;
90 host_public_key_ = host_public_key;
92 signal_strategy_->AddListener(this);
93 signal_strategy_->Connect();
95 session_manager_.reset(new JingleSessionManager(
96 transport_factory.Pass(), allow_nat_traversal_));
97 session_manager_->Init(signal_strategy_, this);
99 SetState(CONNECTING, OK);
102 const SessionConfig& ConnectionToHost::config() {
103 return session_->config();
106 void ConnectionToHost::OnSignalStrategyStateChange(
107 SignalStrategy::State state) {
108 DCHECK(CalledOnValidThread());
109 DCHECK(event_callback_);
111 if (state == SignalStrategy::CONNECTED) {
112 VLOG(1) << "Connected as: " << signal_strategy_->GetLocalJid();
113 } else if (state == SignalStrategy::DISCONNECTED) {
114 VLOG(1) << "Connection closed.";
115 CloseOnError(SIGNALING_ERROR);
119 bool ConnectionToHost::OnSignalStrategyIncomingStanza(
120 const buzz::XmlElement* stanza) {
121 return false;
124 void ConnectionToHost::OnSessionManagerReady() {
125 DCHECK(CalledOnValidThread());
127 // After SessionManager is initialized we can try to connect to the host.
128 scoped_ptr<CandidateSessionConfig> candidate_config =
129 CandidateSessionConfig::CreateDefault();
130 if (!audio_stub_)
131 CandidateSessionConfig::DisableAudioChannel(candidate_config.get());
133 session_ = session_manager_->Connect(
134 host_jid_, authenticator_.Pass(), candidate_config.Pass());
135 session_->SetEventHandler(this);
138 void ConnectionToHost::OnIncomingSession(
139 Session* session,
140 SessionManager::IncomingSessionResponse* response) {
141 DCHECK(CalledOnValidThread());
142 // Client always rejects incoming sessions.
143 *response = SessionManager::DECLINE;
146 void ConnectionToHost::OnSessionStateChange(
147 Session::State state) {
148 DCHECK(CalledOnValidThread());
149 DCHECK(event_callback_);
151 switch (state) {
152 case Session::INITIALIZING:
153 case Session::CONNECTING:
154 case Session::ACCEPTING:
155 case Session::CONNECTED:
156 // Don't care about these events.
157 break;
159 case Session::AUTHENTICATED:
160 SetState(AUTHENTICATED, OK);
162 control_dispatcher_.reset(new ClientControlDispatcher());
163 control_dispatcher_->Init(
164 session_.get(), session_->config().control_config(),
165 base::Bind(&ConnectionToHost::OnChannelInitialized,
166 base::Unretained(this)));
167 control_dispatcher_->set_client_stub(client_stub_);
168 control_dispatcher_->set_clipboard_stub(clipboard_stub_);
170 event_dispatcher_.reset(new ClientEventDispatcher());
171 event_dispatcher_->Init(
172 session_.get(), session_->config().event_config(),
173 base::Bind(&ConnectionToHost::OnChannelInitialized,
174 base::Unretained(this)));
176 video_reader_ = VideoReader::Create(session_->config());
177 video_reader_->Init(session_.get(), video_stub_, base::Bind(
178 &ConnectionToHost::OnChannelInitialized, base::Unretained(this)));
180 audio_reader_ = AudioReader::Create(session_->config());
181 if (audio_reader_.get()) {
182 audio_reader_->Init(
183 session_.get(), session_->config().audio_config(),
184 base::Bind(&ConnectionToHost::OnChannelInitialized,
185 base::Unretained(this)));
186 audio_reader_->set_audio_stub(audio_stub_);
188 break;
190 case Session::CLOSED:
191 CloseChannels();
192 SetState(CLOSED, OK);
193 break;
195 case Session::FAILED:
196 // If we were connected then treat signaling timeout error as if
197 // the connection was closed by the peer.
199 // TODO(sergeyu): This logic belongs to the webapp, but we
200 // currently don't expose this error code to the webapp, and it
201 // would be hard to add it because client plugin and webapp
202 // versions may not be in sync. It should be easy to do after we
203 // are finished moving the client plugin to NaCl.
204 if (state_ == CONNECTED && session_->error() == SIGNALING_TIMEOUT) {
205 CloseChannels();
206 SetState(CLOSED, OK);
207 } else {
208 CloseOnError(session_->error());
210 break;
214 void ConnectionToHost::OnSessionRouteChange(const std::string& channel_name,
215 const TransportRoute& route) {
216 LOG(INFO) << "Using " << TransportRoute::GetTypeString(route.type)
217 << " connection for " << channel_name << " channel";
220 void ConnectionToHost::OnSessionChannelReady(const std::string& channel_name,
221 bool ready) {
222 if (ready) {
223 not_ready_channels_.erase(channel_name);
224 } else if (!ready) {
225 not_ready_channels_.insert(channel_name);
228 event_callback_->OnConnectionReady(not_ready_channels_.empty());
231 ConnectionToHost::State ConnectionToHost::state() const {
232 return state_;
235 void ConnectionToHost::OnChannelInitialized(bool successful) {
236 if (!successful) {
237 LOG(ERROR) << "Failed to connect video channel";
238 CloseOnError(CHANNEL_CONNECTION_ERROR);
239 return;
242 NotifyIfChannelsReady();
245 void ConnectionToHost::NotifyIfChannelsReady() {
246 if (!control_dispatcher_.get() || !control_dispatcher_->is_connected())
247 return;
248 if (!event_dispatcher_.get() || !event_dispatcher_->is_connected())
249 return;
250 if (!video_reader_.get() || !video_reader_->is_connected())
251 return;
252 if ((!audio_reader_.get() || !audio_reader_->is_connected()) &&
253 session_->config().is_audio_enabled()) {
254 return;
256 if (state_ != AUTHENTICATED)
257 return;
259 // Start forwarding clipboard and input events.
260 clipboard_forwarder_.set_clipboard_stub(control_dispatcher_.get());
261 event_forwarder_.set_input_stub(event_dispatcher_.get());
262 SetState(CONNECTED, OK);
265 void ConnectionToHost::CloseOnError(ErrorCode error) {
266 CloseChannels();
267 SetState(FAILED, error);
270 void ConnectionToHost::CloseChannels() {
271 control_dispatcher_.reset();
272 event_dispatcher_.reset();
273 clipboard_forwarder_.set_clipboard_stub(NULL);
274 event_forwarder_.set_input_stub(NULL);
275 video_reader_.reset();
276 audio_reader_.reset();
279 void ConnectionToHost::SetState(State state, ErrorCode error) {
280 DCHECK(CalledOnValidThread());
281 // |error| should be specified only when |state| is set to FAILED.
282 DCHECK(state == FAILED || error == OK);
284 if (state != state_) {
285 state_ = state;
286 error_ = error;
287 event_callback_->OnConnectionState(state_, error_);
291 } // namespace protocol
292 } // namespace remoting