blob: 72985c29465cba4f4d39af6543f78c1aa33605e5 [file] [log] [blame]
[email protected]6bad55c2012-01-24 20:50:271// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]22aae952011-09-12 23:47:512// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]6c44b532012-02-24 21:57:445#include "remoting/protocol/jingle_session.h"
[email protected]22aae952011-09-12 23:47:516
7#include "base/bind.h"
8#include "base/rand_util.h"
9#include "base/stl_util.h"
10#include "base/string_number_conversions.h"
[email protected]137e7cd2012-02-26 00:28:0711#include "base/time.h"
[email protected]22aae952011-09-12 23:47:5112#include "remoting/base/constants.h"
[email protected]b39e1822011-11-04 01:00:4913#include "remoting/jingle_glue/iq_sender.h"
[email protected]f44538512011-11-30 04:43:1714#include "remoting/protocol/authenticator.h"
[email protected]e3c97a62012-02-09 03:52:2015#include "remoting/protocol/channel_authenticator.h"
[email protected]3e9187d02012-08-18 04:17:2316#include "remoting/protocol/channel_multiplexer.h"
[email protected]22aae952011-09-12 23:47:5117#include "remoting/protocol/content_description.h"
18#include "remoting/protocol/jingle_messages.h"
[email protected]6c44b532012-02-24 21:57:4419#include "remoting/protocol/jingle_session_manager.h"
[email protected]a2098232012-02-09 06:19:3320#include "remoting/protocol/session_config.h"
[email protected]22aae952011-09-12 23:47:5121#include "third_party/libjingle/source/talk/p2p/base/candidate.h"
22#include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
23
24using buzz::XmlElement;
25
26namespace remoting {
27namespace protocol {
28
29namespace {
30// Delay after candidate creation before sending transport-info
31// message. This is neccessary to be able to pack multiple candidates
32// into one transport-info messages. The value needs to be greater
33// than zero because ports are opened asynchronously in the browser
34// process.
35const int kTransportInfoSendDelayMs = 2;
[email protected]a2098232012-02-09 06:19:3336
[email protected]9eed82f2013-02-09 06:09:2737// How long we should wait for a response from the other end. This value is used
38// for all requests except |transport-info|.
39const int kDefaultMessageTimeout = 10;
[email protected]137e7cd2012-02-26 00:28:0740
[email protected]0dad65a2013-02-20 20:54:1241// Timeout for the transport-info messages.
42const int kTransportInfoTimeout = 10 * 60;
43
[email protected]3e9187d02012-08-18 04:17:2344// Name of the multiplexed channel.
45const char kMuxChannelName[] = "mux";
46
[email protected]204a9e32012-03-02 05:42:5847ErrorCode AuthRejectionReasonToErrorCode(
[email protected]a2098232012-02-09 06:19:3348 Authenticator::RejectionReason reason) {
49 switch (reason) {
50 case Authenticator::INVALID_CREDENTIALS:
[email protected]204a9e32012-03-02 05:42:5851 return AUTHENTICATION_FAILED;
[email protected]a2098232012-02-09 06:19:3352 case Authenticator::PROTOCOL_ERROR:
[email protected]204a9e32012-03-02 05:42:5853 return INCOMPATIBLE_PROTOCOL;
[email protected]a2098232012-02-09 06:19:3354 }
55 NOTREACHED();
[email protected]204a9e32012-03-02 05:42:5856 return UNKNOWN_ERROR;
[email protected]a2098232012-02-09 06:19:3357}
58
[email protected]22aae952011-09-12 23:47:5159} // namespace
60
[email protected]6c44b532012-02-24 21:57:4461JingleSession::JingleSession(JingleSessionManager* session_manager)
[email protected]22aae952011-09-12 23:47:5162 : session_manager_(session_manager),
[email protected]b1f94ee2012-07-12 21:56:4163 event_handler_(NULL),
[email protected]22aae952011-09-12 23:47:5164 state_(INITIALIZING),
[email protected]a2098232012-02-09 06:19:3365 error_(OK),
66 config_is_set_(false) {
[email protected]22aae952011-09-12 23:47:5167}
68
[email protected]6c44b532012-02-24 21:57:4469JingleSession::~JingleSession() {
[email protected]3e9187d02012-08-18 04:17:2370 channel_multiplexer_.reset();
[email protected]0dad65a2013-02-20 20:54:1271 STLDeleteContainerPointers(pending_requests_.begin(),
72 pending_requests_.end());
73 STLDeleteContainerPointers(transport_info_requests_.begin(),
74 transport_info_requests_.end());
[email protected]22aae952011-09-12 23:47:5175 STLDeleteContainerPairSecondPointers(channels_.begin(), channels_.end());
76 session_manager_->SessionDestroyed(this);
77}
78
[email protected]b1f94ee2012-07-12 21:56:4179void JingleSession::SetEventHandler(Session::EventHandler* event_handler) {
[email protected]22aae952011-09-12 23:47:5180 DCHECK(CalledOnValidThread());
[email protected]b1f94ee2012-07-12 21:56:4181 DCHECK(event_handler);
82 event_handler_ = event_handler;
[email protected]3cb66772012-01-25 00:30:5583}
84
[email protected]204a9e32012-03-02 05:42:5885ErrorCode JingleSession::error() {
[email protected]e3f03d02011-09-27 20:10:5186 DCHECK(CalledOnValidThread());
87 return error_;
88}
89
[email protected]6c44b532012-02-24 21:57:4490void JingleSession::StartConnection(
[email protected]22aae952011-09-12 23:47:5191 const std::string& peer_jid,
[email protected]5bf52312012-01-20 04:10:5292 scoped_ptr<Authenticator> authenticator,
[email protected]b1f94ee2012-07-12 21:56:4193 scoped_ptr<CandidateSessionConfig> config) {
[email protected]22aae952011-09-12 23:47:5194 DCHECK(CalledOnValidThread());
[email protected]5bf52312012-01-20 04:10:5295 DCHECK(authenticator.get());
[email protected]f44538512011-11-30 04:43:1796 DCHECK_EQ(authenticator->state(), Authenticator::MESSAGE_READY);
[email protected]22aae952011-09-12 23:47:5197
98 peer_jid_ = peer_jid;
[email protected]5bf52312012-01-20 04:10:5299 authenticator_ = authenticator.Pass();
100 candidate_config_ = config.Pass();
[email protected]22aae952011-09-12 23:47:51101
102 // Generate random session ID. There are usually not more than 1
103 // concurrent session per host, so a random 64-bit integer provides
104 // enough entropy. In the worst case connection will fail when two
105 // clients generate the same session ID concurrently.
106 session_id_ = base::Int64ToString(base::RandGenerator(kint64max));
107
108 // Send session-initiate message.
109 JingleMessage message(peer_jid_, JingleMessage::SESSION_INITIATE,
110 session_id_);
[email protected]a05c0d82a2012-02-29 01:19:25111 message.from = session_manager_->signal_strategy_->GetLocalJid();
[email protected]22aae952011-09-12 23:47:51112 message.description.reset(
[email protected]f44538512011-11-30 04:43:17113 new ContentDescription(candidate_config_->Clone(),
114 authenticator_->GetNextMessage()));
[email protected]0dad65a2013-02-20 20:54:12115 SendMessage(message);
[email protected]22aae952011-09-12 23:47:51116
117 SetState(CONNECTING);
118}
119
[email protected]6c44b532012-02-24 21:57:44120void JingleSession::InitializeIncomingConnection(
[email protected]a2098232012-02-09 06:19:33121 const JingleMessage& initiate_message,
122 scoped_ptr<Authenticator> authenticator) {
123 DCHECK(CalledOnValidThread());
124 DCHECK(initiate_message.description.get());
125 DCHECK(authenticator.get());
126 DCHECK_EQ(authenticator->state(), Authenticator::WAITING_MESSAGE);
127
128 peer_jid_ = initiate_message.from;
129 authenticator_ = authenticator.Pass();
130 session_id_ = initiate_message.sid;
131 candidate_config_ = initiate_message.description->config()->Clone();
132
[email protected]c22db292013-03-01 07:59:40133 SetState(ACCEPTING);
[email protected]a2098232012-02-09 06:19:33134}
135
[email protected]6c44b532012-02-24 21:57:44136void JingleSession::AcceptIncomingConnection(
[email protected]a2098232012-02-09 06:19:33137 const JingleMessage& initiate_message) {
138 DCHECK(config_is_set_);
139
140 // Process the first authentication message.
141 const buzz::XmlElement* first_auth_message =
142 initiate_message.description->authenticator_message();
143
144 if (!first_auth_message) {
145 CloseInternal(INCOMPATIBLE_PROTOCOL);
146 return;
147 }
148
149 DCHECK_EQ(authenticator_->state(), Authenticator::WAITING_MESSAGE);
[email protected]c22db292013-03-01 07:59:40150 // |authenticator_| is owned, so Unretained() is safe here.
151 authenticator_->ProcessMessage(first_auth_message, base::Bind(
152 &JingleSession::ContinueAcceptIncomingConnection,
153 base::Unretained(this)));
154}
155
156void JingleSession::ContinueAcceptIncomingConnection() {
157 DCHECK_NE(authenticator_->state(), Authenticator::PROCESSING_MESSAGE);
[email protected]a2098232012-02-09 06:19:33158 if (authenticator_->state() == Authenticator::REJECTED) {
[email protected]204a9e32012-03-02 05:42:58159 CloseInternal(AuthRejectionReasonToErrorCode(
[email protected]a2098232012-02-09 06:19:33160 authenticator_->rejection_reason()));
161 return;
162 }
163
164 // Send the session-accept message.
165 JingleMessage message(peer_jid_, JingleMessage::SESSION_ACCEPT,
166 session_id_);
167
168 scoped_ptr<buzz::XmlElement> auth_message;
169 if (authenticator_->state() == Authenticator::MESSAGE_READY)
170 auth_message = authenticator_->GetNextMessage();
171
172 message.description.reset(
173 new ContentDescription(CandidateSessionConfig::CreateFrom(config_),
174 auth_message.Pass()));
[email protected]0dad65a2013-02-20 20:54:12175 SendMessage(message);
[email protected]a2098232012-02-09 06:19:33176
177 // Update state.
178 SetState(CONNECTED);
179
180 if (authenticator_->state() == Authenticator::ACCEPTED) {
181 SetState(AUTHENTICATED);
182 } else {
183 DCHECK_EQ(authenticator_->state(), Authenticator::WAITING_MESSAGE);
184 }
185
186 return;
187}
188
[email protected]3e9187d02012-08-18 04:17:23189const std::string& JingleSession::jid() {
190 DCHECK(CalledOnValidThread());
191 return peer_jid_;
192}
193
194const CandidateSessionConfig* JingleSession::candidate_config() {
195 DCHECK(CalledOnValidThread());
196 return candidate_config_.get();
197}
198
199const SessionConfig& JingleSession::config() {
200 DCHECK(CalledOnValidThread());
201 return config_;
202}
203
204void JingleSession::set_config(const SessionConfig& config) {
205 DCHECK(CalledOnValidThread());
206 DCHECK(!config_is_set_);
207 config_ = config;
208 config_is_set_ = true;
209}
210
211ChannelFactory* JingleSession::GetTransportChannelFactory() {
212 DCHECK(CalledOnValidThread());
213 return this;
214}
215
216ChannelFactory* JingleSession::GetMultiplexedChannelFactory() {
217 DCHECK(CalledOnValidThread());
218 if (!channel_multiplexer_.get())
219 channel_multiplexer_.reset(new ChannelMultiplexer(this, kMuxChannelName));
220 return channel_multiplexer_.get();
221}
222
223void JingleSession::Close() {
224 DCHECK(CalledOnValidThread());
225
226 CloseInternal(OK);
227}
228
[email protected]6c44b532012-02-24 21:57:44229void JingleSession::CreateStreamChannel(
[email protected]22aae952011-09-12 23:47:51230 const std::string& name,
231 const StreamChannelCallback& callback) {
232 DCHECK(!channels_[name]);
233
[email protected]5bf52312012-01-20 04:10:52234 scoped_ptr<ChannelAuthenticator> channel_authenticator =
[email protected]f44538512011-11-30 04:43:17235 authenticator_->CreateChannelAuthenticator();
[email protected]e3c97a62012-02-09 03:52:20236 scoped_ptr<StreamTransport> channel =
237 session_manager_->transport_factory_->CreateStreamTransport();
[email protected]5f4ed93d2012-04-30 23:41:59238 channel->Initialize(name, this, channel_authenticator.Pass());
[email protected]e3c97a62012-02-09 03:52:20239 channel->Connect(callback);
240 channels_[name] = channel.release();
[email protected]22aae952011-09-12 23:47:51241}
242
[email protected]6c44b532012-02-24 21:57:44243void JingleSession::CreateDatagramChannel(
[email protected]22aae952011-09-12 23:47:51244 const std::string& name,
245 const DatagramChannelCallback& callback) {
[email protected]e3c97a62012-02-09 03:52:20246 DCHECK(!channels_[name]);
247
248 scoped_ptr<ChannelAuthenticator> channel_authenticator =
249 authenticator_->CreateChannelAuthenticator();
250 scoped_ptr<DatagramTransport> channel =
251 session_manager_->transport_factory_->CreateDatagramTransport();
[email protected]5f4ed93d2012-04-30 23:41:59252 channel->Initialize(name, this, channel_authenticator.Pass());
[email protected]e3c97a62012-02-09 03:52:20253 channel->Connect(callback);
254 channels_[name] = channel.release();
[email protected]22aae952011-09-12 23:47:51255}
256
[email protected]6c44b532012-02-24 21:57:44257void JingleSession::CancelChannelCreation(const std::string& name) {
[email protected]f2d6a0032011-11-17 00:48:12258 ChannelsMap::iterator it = channels_.find(name);
259 if (it != channels_.end() && !it->second->is_connected()) {
260 delete it->second;
261 DCHECK(!channels_[name]);
262 }
263}
264
[email protected]6c44b532012-02-24 21:57:44265void JingleSession::OnTransportCandidate(Transport* transport,
[email protected]e3c97a62012-02-09 03:52:20266 const cricket::Candidate& candidate) {
[email protected]8bb746372012-04-26 04:20:12267 pending_candidates_.push_back(JingleMessage::NamedCandidate(
268 transport->name(), candidate));
[email protected]e3c97a62012-02-09 03:52:20269
270 if (!transport_infos_timer_.IsRunning()) {
271 // Delay sending the new candidates in case we get more candidates
272 // that we can send in one message.
273 transport_infos_timer_.Start(
274 FROM_HERE, base::TimeDelta::FromMilliseconds(kTransportInfoSendDelayMs),
[email protected]6c44b532012-02-24 21:57:44275 this, &JingleSession::SendTransportInfo);
[email protected]e3c97a62012-02-09 03:52:20276 }
277}
278
[email protected]6c44b532012-02-24 21:57:44279void JingleSession::OnTransportRouteChange(Transport* transport,
[email protected]0b523232012-02-21 23:23:11280 const TransportRoute& route) {
[email protected]b1f94ee2012-07-12 21:56:41281 if (event_handler_)
282 event_handler_->OnSessionRouteChange(transport->name(), route);
[email protected]0b523232012-02-21 23:23:11283}
284
[email protected]a04494cb2012-07-23 05:00:32285void JingleSession::OnTransportReady(Transport* transport, bool ready) {
286 if (event_handler_)
287 event_handler_->OnSessionChannelReady(transport->name(), ready);
288}
289
[email protected]6c44b532012-02-24 21:57:44290void JingleSession::OnTransportDeleted(Transport* transport) {
[email protected]e3c97a62012-02-09 03:52:20291 ChannelsMap::iterator it = channels_.find(transport->name());
292 DCHECK_EQ(it->second, transport);
293 channels_.erase(it);
294}
295
[email protected]0dad65a2013-02-20 20:54:12296void JingleSession::SendMessage(const JingleMessage& message) {
[email protected]137e7cd2012-02-26 00:28:07297 scoped_ptr<IqRequest> request = session_manager_->iq_sender()->SendIq(
298 message.ToXml(),
299 base::Bind(&JingleSession::OnMessageResponse,
300 base::Unretained(this), message.action));
[email protected]0dad65a2013-02-20 20:54:12301 if (request) {
302 request->SetTimeout(base::TimeDelta::FromSeconds(kDefaultMessageTimeout));
303 pending_requests_.insert(request.release());
[email protected]137e7cd2012-02-26 00:28:07304 } else {
305 LOG(ERROR) << "Failed to send a "
306 << JingleMessage::GetActionName(message.action) << " message";
307 }
308}
309
310void JingleSession::OnMessageResponse(
311 JingleMessage::ActionType request_type,
312 IqRequest* request,
313 const buzz::XmlElement* response) {
[email protected]137e7cd2012-02-26 00:28:07314 std::string type_str = JingleMessage::GetActionName(request_type);
[email protected]137e7cd2012-02-26 00:28:07315
[email protected]0dad65a2013-02-20 20:54:12316 // Delete the request from the list of pending requests.
317 pending_requests_.erase(request);
318 delete request;
319
[email protected]9eed82f2013-02-09 06:09:27320 // |response| will be NULL if the request timed out.
[email protected]137e7cd2012-02-26 00:28:07321 if (!response) {
322 LOG(ERROR) << type_str << " request timed out.";
[email protected]204a9e32012-03-02 05:42:58323 CloseInternal(SIGNALING_TIMEOUT);
[email protected]0dad65a2013-02-20 20:54:12324 return;
[email protected]137e7cd2012-02-26 00:28:07325 } else {
[email protected]007b3f82013-04-09 08:46:45326 const std::string& type =
327 response->Attr(buzz::QName(std::string(), "type"));
[email protected]137e7cd2012-02-26 00:28:07328 if (type != "result") {
329 LOG(ERROR) << "Received error in response to " << type_str
330 << " message: \"" << response->Str()
331 << "\". Terminating the session.";
332
333 switch (request_type) {
334 case JingleMessage::SESSION_INFO:
335 // session-info is used for the new authentication protocol,
336 // and wasn't previously supported.
[email protected]204a9e32012-03-02 05:42:58337 CloseInternal(INCOMPATIBLE_PROTOCOL);
338 break;
[email protected]137e7cd2012-02-26 00:28:07339
340 default:
341 // TODO(sergeyu): There may be different reasons for error
342 // here. Parse the response stanza to find failure reason.
[email protected]204a9e32012-03-02 05:42:58343 CloseInternal(PEER_IS_OFFLINE);
[email protected]137e7cd2012-02-26 00:28:07344 }
345 }
346 }
[email protected]137e7cd2012-02-26 00:28:07347}
348
[email protected]0dad65a2013-02-20 20:54:12349void JingleSession::SendTransportInfo() {
350 JingleMessage message(peer_jid_, JingleMessage::TRANSPORT_INFO, session_id_);
351 message.candidates.swap(pending_candidates_);
352
353 scoped_ptr<IqRequest> request = session_manager_->iq_sender()->SendIq(
354 message.ToXml(),
355 base::Bind(&JingleSession::OnTransportInfoResponse,
356 base::Unretained(this)));
357 if (request) {
358 request->SetTimeout(base::TimeDelta::FromSeconds(kTransportInfoTimeout));
359 transport_info_requests_.push_back(request.release());
360 } else {
361 LOG(ERROR) << "Failed to send a transport-info message";
362 }
363}
364
365void JingleSession::OnTransportInfoResponse(IqRequest* request,
366 const buzz::XmlElement* response) {
367 DCHECK(!transport_info_requests_.empty());
368
369 // Consider transport-info requests sent before this one lost and delete
370 // corresponding IqRequest objects.
371 while (transport_info_requests_.front() != request) {
372 delete transport_info_requests_.front();
373 transport_info_requests_.pop_front();
374 }
375
376 // Delete the |request| itself.
377 DCHECK_EQ(request, transport_info_requests_.front());
378 delete request;
379 transport_info_requests_.pop_front();
380
381 // Ignore transport-info timeouts.
382 if (!response) {
383 LOG(ERROR) << "transport-info request has timed out.";
384 return;
385 }
386
[email protected]007b3f82013-04-09 08:46:45387 const std::string& type = response->Attr(buzz::QName(std::string(), "type"));
[email protected]0dad65a2013-02-20 20:54:12388 if (type != "result") {
389 LOG(ERROR) << "Received error in response to transport-info message: \""
390 << response->Str() << "\". Terminating the session.";
391 CloseInternal(PEER_IS_OFFLINE);
392 }
393}
394
[email protected]6c44b532012-02-24 21:57:44395void JingleSession::OnIncomingMessage(const JingleMessage& message,
[email protected]b0fffb02012-02-17 21:59:43396 const ReplyCallback& reply_callback) {
[email protected]22aae952011-09-12 23:47:51397 DCHECK(CalledOnValidThread());
398
399 if (message.from != peer_jid_) {
400 // Ignore messages received from a different Jid.
[email protected]b0fffb02012-02-17 21:59:43401 reply_callback.Run(JingleMessageReply::INVALID_SID);
[email protected]22aae952011-09-12 23:47:51402 return;
403 }
404
405 switch (message.action) {
406 case JingleMessage::SESSION_ACCEPT:
[email protected]b0fffb02012-02-17 21:59:43407 OnAccept(message, reply_callback);
[email protected]22aae952011-09-12 23:47:51408 break;
409
[email protected]1bc9c7c2011-12-14 00:13:39410 case JingleMessage::SESSION_INFO:
[email protected]b0fffb02012-02-17 21:59:43411 OnSessionInfo(message, reply_callback);
[email protected]1bc9c7c2011-12-14 00:13:39412 break;
413
[email protected]22aae952011-09-12 23:47:51414 case JingleMessage::TRANSPORT_INFO:
[email protected]b0fffb02012-02-17 21:59:43415 reply_callback.Run(JingleMessageReply::NONE);
[email protected]22aae952011-09-12 23:47:51416 ProcessTransportInfo(message);
417 break;
418
[email protected]22aae952011-09-12 23:47:51419 case JingleMessage::SESSION_TERMINATE:
[email protected]b0fffb02012-02-17 21:59:43420 OnTerminate(message, reply_callback);
[email protected]22aae952011-09-12 23:47:51421 break;
422
423 default:
[email protected]b0fffb02012-02-17 21:59:43424 reply_callback.Run(JingleMessageReply::UNEXPECTED_REQUEST);
[email protected]22aae952011-09-12 23:47:51425 }
426}
427
[email protected]6c44b532012-02-24 21:57:44428void JingleSession::OnAccept(const JingleMessage& message,
[email protected]b0fffb02012-02-17 21:59:43429 const ReplyCallback& reply_callback) {
[email protected]22aae952011-09-12 23:47:51430 if (state_ != CONNECTING) {
[email protected]b0fffb02012-02-17 21:59:43431 reply_callback.Run(JingleMessageReply::UNEXPECTED_REQUEST);
[email protected]22aae952011-09-12 23:47:51432 return;
433 }
434
[email protected]b0fffb02012-02-17 21:59:43435 reply_callback.Run(JingleMessageReply::NONE);
436
[email protected]f44538512011-11-30 04:43:17437 const buzz::XmlElement* auth_message =
438 message.description->authenticator_message();
439 if (!auth_message) {
440 DLOG(WARNING) << "Received session-accept without authentication message "
441 << auth_message->Str();
[email protected]a2098232012-02-09 06:19:33442 CloseInternal(INCOMPATIBLE_PROTOCOL);
[email protected]f44538512011-11-30 04:43:17443 return;
444 }
445
[email protected]22aae952011-09-12 23:47:51446 if (!InitializeConfigFromDescription(message.description.get())) {
[email protected]a2098232012-02-09 06:19:33447 CloseInternal(INCOMPATIBLE_PROTOCOL);
[email protected]22aae952011-09-12 23:47:51448 return;
449 }
450
[email protected]1bc9c7c2011-12-14 00:13:39451 // In case there is transport information in the accept message.
452 ProcessTransportInfo(message);
453
[email protected]22aae952011-09-12 23:47:51454 SetState(CONNECTED);
455
[email protected]c22db292013-03-01 07:59:40456 DCHECK(authenticator_->state() == Authenticator::WAITING_MESSAGE);
457 authenticator_->ProcessMessage(auth_message, base::Bind(
458 &JingleSession::ProcessAuthenticationStep,base::Unretained(this)));
[email protected]1bc9c7c2011-12-14 00:13:39459}
[email protected]0de37002011-12-06 07:30:16460
[email protected]6c44b532012-02-24 21:57:44461void JingleSession::OnSessionInfo(const JingleMessage& message,
[email protected]b0fffb02012-02-17 21:59:43462 const ReplyCallback& reply_callback) {
463 if (!message.info.get() ||
464 !Authenticator::IsAuthenticatorMessage(message.info.get())) {
465 reply_callback.Run(JingleMessageReply::UNSUPPORTED_INFO);
466 return;
[email protected]1bc9c7c2011-12-14 00:13:39467 }
[email protected]b0fffb02012-02-17 21:59:43468
469 if (state_ != CONNECTED ||
470 authenticator_->state() != Authenticator::WAITING_MESSAGE) {
471 LOG(WARNING) << "Received unexpected authenticator message "
472 << message.info->Str();
473 reply_callback.Run(JingleMessageReply::UNEXPECTED_REQUEST);
474 CloseInternal(INCOMPATIBLE_PROTOCOL);
475 return;
476 }
477
478 reply_callback.Run(JingleMessageReply::NONE);
479
[email protected]c22db292013-03-01 07:59:40480 authenticator_->ProcessMessage(message.info.get(), base::Bind(
481 &JingleSession::ProcessAuthenticationStep, base::Unretained(this)));
[email protected]22aae952011-09-12 23:47:51482}
483
[email protected]6c44b532012-02-24 21:57:44484void JingleSession::ProcessTransportInfo(const JingleMessage& message) {
[email protected]8bb746372012-04-26 04:20:12485 for (std::list<JingleMessage::NamedCandidate>::const_iterator it =
[email protected]22aae952011-09-12 23:47:51486 message.candidates.begin();
487 it != message.candidates.end(); ++it) {
[email protected]8bb746372012-04-26 04:20:12488 ChannelsMap::iterator channel = channels_.find(it->name);
[email protected]22aae952011-09-12 23:47:51489 if (channel == channels_.end()) {
[email protected]8bb746372012-04-26 04:20:12490 LOG(WARNING) << "Received candidate for unknown channel " << it->name;
[email protected]22aae952011-09-12 23:47:51491 continue;
492 }
[email protected]8bb746372012-04-26 04:20:12493 channel->second->AddRemoteCandidate(it->candidate);
[email protected]22aae952011-09-12 23:47:51494 }
495}
496
[email protected]6c44b532012-02-24 21:57:44497void JingleSession::OnTerminate(const JingleMessage& message,
[email protected]b0fffb02012-02-17 21:59:43498 const ReplyCallback& reply_callback) {
[email protected]c22db292013-03-01 07:59:40499 if (state_ != CONNECTING && state_ != ACCEPTING && state_ != CONNECTED &&
500 state_ != AUTHENTICATED) {
[email protected]a2098232012-02-09 06:19:33501 LOG(WARNING) << "Received unexpected session-terminate message.";
[email protected]b0fffb02012-02-17 21:59:43502 reply_callback.Run(JingleMessageReply::UNEXPECTED_REQUEST);
[email protected]22aae952011-09-12 23:47:51503 return;
504 }
505
[email protected]b0fffb02012-02-17 21:59:43506 reply_callback.Run(JingleMessageReply::NONE);
507
[email protected]a2098232012-02-09 06:19:33508 switch (message.reason) {
509 case JingleMessage::SUCCESS:
510 if (state_ == CONNECTING) {
511 error_ = SESSION_REJECTED;
512 } else {
513 error_ = OK;
514 }
515 break;
516 case JingleMessage::DECLINE:
517 error_ = AUTHENTICATION_FAILED;
518 break;
[email protected]a6b74c212012-03-27 02:38:11519 case JingleMessage::CANCEL:
[email protected]d82166882012-03-28 04:38:53520 error_ = HOST_OVERLOAD;
[email protected]a6b74c212012-03-27 02:38:11521 break;
[email protected]a2098232012-02-09 06:19:33522 case JingleMessage::GENERAL_ERROR:
523 error_ = CHANNEL_CONNECTION_ERROR;
524 break;
525 case JingleMessage::INCOMPATIBLE_PARAMETERS:
526 error_ = INCOMPATIBLE_PROTOCOL;
527 break;
528 default:
529 error_ = UNKNOWN_ERROR;
[email protected]455a61682011-11-12 01:45:19530 }
531
[email protected]a2098232012-02-09 06:19:33532 if (error_ != OK) {
533 SetState(FAILED);
[email protected]1bc9c7c2011-12-14 00:13:39534 } else {
[email protected]a2098232012-02-09 06:19:33535 SetState(CLOSED);
[email protected]1bc9c7c2011-12-14 00:13:39536 }
[email protected]22aae952011-09-12 23:47:51537}
538
[email protected]6c44b532012-02-24 21:57:44539bool JingleSession::InitializeConfigFromDescription(
[email protected]22aae952011-09-12 23:47:51540 const ContentDescription* description) {
541 DCHECK(description);
542
[email protected]22aae952011-09-12 23:47:51543 if (!description->config()->GetFinalConfig(&config_)) {
544 LOG(ERROR) << "session-accept does not specify configuration";
545 return false;
546 }
547 if (!candidate_config()->IsSupported(config_)) {
548 LOG(ERROR) << "session-accept specifies an invalid configuration";
549 return false;
550 }
551
552 return true;
553}
554
[email protected]6c44b532012-02-24 21:57:44555void JingleSession::ProcessAuthenticationStep() {
[email protected]c22db292013-03-01 07:59:40556 DCHECK(CalledOnValidThread());
[email protected]1bc9c7c2011-12-14 00:13:39557 DCHECK_EQ(state_, CONNECTED);
[email protected]c22db292013-03-01 07:59:40558 DCHECK_NE(authenticator_->state(), Authenticator::PROCESSING_MESSAGE);
[email protected]1bc9c7c2011-12-14 00:13:39559
560 if (authenticator_->state() == Authenticator::MESSAGE_READY) {
561 JingleMessage message(peer_jid_, JingleMessage::SESSION_INFO, session_id_);
[email protected]5bf52312012-01-20 04:10:52562 message.info = authenticator_->GetNextMessage();
[email protected]1bc9c7c2011-12-14 00:13:39563 DCHECK(message.info.get());
[email protected]0dad65a2013-02-20 20:54:12564 SendMessage(message);
[email protected]1bc9c7c2011-12-14 00:13:39565 }
566 DCHECK_NE(authenticator_->state(), Authenticator::MESSAGE_READY);
567
568 if (authenticator_->state() == Authenticator::ACCEPTED) {
569 SetState(AUTHENTICATED);
570 } else if (authenticator_->state() == Authenticator::REJECTED) {
[email protected]204a9e32012-03-02 05:42:58571 CloseInternal(AuthRejectionReasonToErrorCode(
[email protected]a2098232012-02-09 06:19:33572 authenticator_->rejection_reason()));
[email protected]1bc9c7c2011-12-14 00:13:39573 }
574}
575
[email protected]204a9e32012-03-02 05:42:58576void JingleSession::CloseInternal(ErrorCode error) {
[email protected]22aae952011-09-12 23:47:51577 DCHECK(CalledOnValidThread());
578
[email protected]c22db292013-03-01 07:59:40579 if (state_ == CONNECTING || state_ == ACCEPTING || state_ == CONNECTED ||
580 state_ == AUTHENTICATED) {
[email protected]a2098232012-02-09 06:19:33581 // Send session-terminate message with the appropriate error code.
582 JingleMessage::Reason reason;
583 switch (error) {
584 case OK:
585 reason = JingleMessage::SUCCESS;
586 break;
587 case SESSION_REJECTED:
588 case AUTHENTICATION_FAILED:
589 reason = JingleMessage::DECLINE;
590 break;
591 case INCOMPATIBLE_PROTOCOL:
592 reason = JingleMessage::INCOMPATIBLE_PARAMETERS;
593 break;
[email protected]d82166882012-03-28 04:38:53594 case HOST_OVERLOAD:
[email protected]a6b74c212012-03-27 02:38:11595 reason = JingleMessage::CANCEL;
596 break;
[email protected]a2098232012-02-09 06:19:33597 default:
598 reason = JingleMessage::GENERAL_ERROR;
599 }
600
601 JingleMessage message(peer_jid_, JingleMessage::SESSION_TERMINATE,
602 session_id_);
603 message.reason = reason;
[email protected]0dad65a2013-02-20 20:54:12604 SendMessage(message);
[email protected]a2098232012-02-09 06:19:33605 }
606
607 error_ = error;
608
[email protected]22aae952011-09-12 23:47:51609 if (state_ != FAILED && state_ != CLOSED) {
[email protected]a2098232012-02-09 06:19:33610 if (error != OK) {
[email protected]22aae952011-09-12 23:47:51611 SetState(FAILED);
[email protected]a2098232012-02-09 06:19:33612 } else {
[email protected]22aae952011-09-12 23:47:51613 SetState(CLOSED);
[email protected]a2098232012-02-09 06:19:33614 }
[email protected]22aae952011-09-12 23:47:51615 }
616}
617
[email protected]6c44b532012-02-24 21:57:44618void JingleSession::SetState(State new_state) {
[email protected]22aae952011-09-12 23:47:51619 DCHECK(CalledOnValidThread());
620
621 if (new_state != state_) {
622 DCHECK_NE(state_, CLOSED);
623 DCHECK_NE(state_, FAILED);
624
625 state_ = new_state;
[email protected]b1f94ee2012-07-12 21:56:41626 if (event_handler_)
627 event_handler_->OnSessionStateChange(new_state);
[email protected]22aae952011-09-12 23:47:51628 }
629}
630
631} // namespace protocol
632} // namespace remoting