Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(23)

Side by Side Diff: remoting/protocol/jingle_session.cc

Issue 9452038: Implement timeouts for IQ requests. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix release build Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « remoting/protocol/jingle_session.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "remoting/protocol/jingle_session.h" 5 #include "remoting/protocol/jingle_session.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/rand_util.h" 8 #include "base/rand_util.h"
9 #include "base/stl_util.h" 9 #include "base/stl_util.h"
10 #include "base/string_number_conversions.h" 10 #include "base/string_number_conversions.h"
11 #include "base/time.h"
11 #include "remoting/base/constants.h" 12 #include "remoting/base/constants.h"
12 #include "remoting/jingle_glue/iq_sender.h" 13 #include "remoting/jingle_glue/iq_sender.h"
13 #include "remoting/protocol/authenticator.h" 14 #include "remoting/protocol/authenticator.h"
14 #include "remoting/protocol/channel_authenticator.h" 15 #include "remoting/protocol/channel_authenticator.h"
15 #include "remoting/protocol/content_description.h" 16 #include "remoting/protocol/content_description.h"
16 #include "remoting/protocol/jingle_messages.h" 17 #include "remoting/protocol/jingle_messages.h"
17 #include "remoting/protocol/jingle_session_manager.h" 18 #include "remoting/protocol/jingle_session_manager.h"
18 #include "remoting/protocol/session_config.h" 19 #include "remoting/protocol/session_config.h"
19 #include "third_party/libjingle/source/talk/p2p/base/candidate.h" 20 #include "third_party/libjingle/source/talk/p2p/base/candidate.h"
20 #include "third_party/libjingle/source/talk/xmllite/xmlelement.h" 21 #include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
21 22
22 using buzz::XmlElement; 23 using buzz::XmlElement;
23 24
24 namespace remoting { 25 namespace remoting {
25 namespace protocol { 26 namespace protocol {
26 27
27 namespace { 28 namespace {
28 // Delay after candidate creation before sending transport-info 29 // Delay after candidate creation before sending transport-info
29 // message. This is neccessary to be able to pack multiple candidates 30 // message. This is neccessary to be able to pack multiple candidates
30 // into one transport-info messages. The value needs to be greater 31 // into one transport-info messages. The value needs to be greater
31 // than zero because ports are opened asynchronously in the browser 32 // than zero because ports are opened asynchronously in the browser
32 // process. 33 // process.
33 const int kTransportInfoSendDelayMs = 2; 34 const int kTransportInfoSendDelayMs = 2;
34 35
36 // How long we should wait for a response from the other end. This
37 // value is used for all requests include |session-initiate| and
38 // |transport-info|.
39 const int kMessageResponseTimeoutSeconds = 10;
40
35 Session::Error AuthRejectionReasonToError( 41 Session::Error AuthRejectionReasonToError(
36 Authenticator::RejectionReason reason) { 42 Authenticator::RejectionReason reason) {
37 switch (reason) { 43 switch (reason) {
38 case Authenticator::INVALID_CREDENTIALS: 44 case Authenticator::INVALID_CREDENTIALS:
39 return Session::AUTHENTICATION_FAILED; 45 return Session::AUTHENTICATION_FAILED;
40 case Authenticator::PROTOCOL_ERROR: 46 case Authenticator::PROTOCOL_ERROR:
41 return Session::INCOMPATIBLE_PROTOCOL; 47 return Session::INCOMPATIBLE_PROTOCOL;
42 } 48 }
43 NOTREACHED(); 49 NOTREACHED();
44 return Session::UNKNOWN_ERROR; 50 return Session::UNKNOWN_ERROR;
45 } 51 }
46 52
47 } // namespace 53 } // namespace
48 54
49 JingleSession::JingleSession(JingleSessionManager* session_manager) 55 JingleSession::JingleSession(JingleSessionManager* session_manager)
50 : session_manager_(session_manager), 56 : session_manager_(session_manager),
51 state_(INITIALIZING), 57 state_(INITIALIZING),
52 error_(OK), 58 error_(OK),
53 config_is_set_(false) { 59 config_is_set_(false) {
54 } 60 }
55 61
56 JingleSession::~JingleSession() { 62 JingleSession::~JingleSession() {
63 STLDeleteContainerPointers(pending_requests_.begin(),
64 pending_requests_.end());
57 STLDeleteContainerPairSecondPointers(channels_.begin(), channels_.end()); 65 STLDeleteContainerPairSecondPointers(channels_.begin(), channels_.end());
58 session_manager_->SessionDestroyed(this); 66 session_manager_->SessionDestroyed(this);
59 } 67 }
60 68
61 void JingleSession::SetStateChangeCallback( 69 void JingleSession::SetStateChangeCallback(
62 const StateChangeCallback& callback) { 70 const StateChangeCallback& callback) {
63 DCHECK(CalledOnValidThread()); 71 DCHECK(CalledOnValidThread());
64 DCHECK(!callback.is_null()); 72 DCHECK(!callback.is_null());
65 state_change_callback_ = callback; 73 state_change_callback_ = callback;
66 } 74 }
(...skipping 28 matching lines...) Expand all
95 // enough entropy. In the worst case connection will fail when two 103 // enough entropy. In the worst case connection will fail when two
96 // clients generate the same session ID concurrently. 104 // clients generate the same session ID concurrently.
97 session_id_ = base::Int64ToString(base::RandGenerator(kint64max)); 105 session_id_ = base::Int64ToString(base::RandGenerator(kint64max));
98 106
99 // Send session-initiate message. 107 // Send session-initiate message.
100 JingleMessage message(peer_jid_, JingleMessage::SESSION_INITIATE, 108 JingleMessage message(peer_jid_, JingleMessage::SESSION_INITIATE,
101 session_id_); 109 session_id_);
102 message.description.reset( 110 message.description.reset(
103 new ContentDescription(candidate_config_->Clone(), 111 new ContentDescription(candidate_config_->Clone(),
104 authenticator_->GetNextMessage())); 112 authenticator_->GetNextMessage()));
105 initiate_request_ = session_manager_->iq_sender()->SendIq( 113 SendMessage(message);
106 message.ToXml(),
107 base::Bind(&JingleSession::OnSessionInitiateResponse,
108 base::Unretained(this)));
109 114
110 SetState(CONNECTING); 115 SetState(CONNECTING);
111 } 116 }
112 117
113 void JingleSession::InitializeIncomingConnection( 118 void JingleSession::InitializeIncomingConnection(
114 const JingleMessage& initiate_message, 119 const JingleMessage& initiate_message,
115 scoped_ptr<Authenticator> authenticator) { 120 scoped_ptr<Authenticator> authenticator) {
116 DCHECK(CalledOnValidThread()); 121 DCHECK(CalledOnValidThread());
117 DCHECK(initiate_message.description.get()); 122 DCHECK(initiate_message.description.get());
118 DCHECK(authenticator.get()); 123 DCHECK(authenticator.get());
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
151 JingleMessage message(peer_jid_, JingleMessage::SESSION_ACCEPT, 156 JingleMessage message(peer_jid_, JingleMessage::SESSION_ACCEPT,
152 session_id_); 157 session_id_);
153 158
154 scoped_ptr<buzz::XmlElement> auth_message; 159 scoped_ptr<buzz::XmlElement> auth_message;
155 if (authenticator_->state() == Authenticator::MESSAGE_READY) 160 if (authenticator_->state() == Authenticator::MESSAGE_READY)
156 auth_message = authenticator_->GetNextMessage(); 161 auth_message = authenticator_->GetNextMessage();
157 162
158 message.description.reset( 163 message.description.reset(
159 new ContentDescription(CandidateSessionConfig::CreateFrom(config_), 164 new ContentDescription(CandidateSessionConfig::CreateFrom(config_),
160 auth_message.Pass())); 165 auth_message.Pass()));
161 initiate_request_ = session_manager_->iq_sender()->SendIq( 166 SendMessage(message);
162 message.ToXml(),
163 base::Bind(&JingleSession::OnSessionInitiateResponse,
164 base::Unretained(this)));
165 167
166 // Update state. 168 // Update state.
167 SetState(CONNECTED); 169 SetState(CONNECTED);
168 170
169 if (authenticator_->state() == Authenticator::ACCEPTED) { 171 if (authenticator_->state() == Authenticator::ACCEPTED) {
170 SetState(AUTHENTICATED); 172 SetState(AUTHENTICATED);
171 } else { 173 } else {
172 DCHECK_EQ(authenticator_->state(), Authenticator::WAITING_MESSAGE); 174 DCHECK_EQ(authenticator_->state(), Authenticator::WAITING_MESSAGE);
173 } 175 }
174 176
175 return; 177 return;
176 } 178 }
177 179
178 void JingleSession::OnSessionInitiateResponse(
179 const buzz::XmlElement* response) {
180 const std::string& type = response->Attr(buzz::QName("", "type"));
181 if (type != "result") {
182 LOG(ERROR) << "Received error in response to session-initiate message: \""
183 << response->Str()
184 << "\". Terminating the session.";
185
186 // TODO(sergeyu): There may be different reasons for error
187 // here. Parse the response stanza to find failure reason.
188 CloseInternal(PEER_IS_OFFLINE);
189 }
190 }
191
192 void JingleSession::CreateStreamChannel( 180 void JingleSession::CreateStreamChannel(
193 const std::string& name, 181 const std::string& name,
194 const StreamChannelCallback& callback) { 182 const StreamChannelCallback& callback) {
195 DCHECK(!channels_[name]); 183 DCHECK(!channels_[name]);
196 184
197 scoped_ptr<ChannelAuthenticator> channel_authenticator = 185 scoped_ptr<ChannelAuthenticator> channel_authenticator =
198 authenticator_->CreateChannelAuthenticator(); 186 authenticator_->CreateChannelAuthenticator();
199 scoped_ptr<StreamTransport> channel = 187 scoped_ptr<StreamTransport> channel =
200 session_manager_->transport_factory_->CreateStreamTransport(); 188 session_manager_->transport_factory_->CreateStreamTransport();
201 channel->Initialize(name, session_manager_->transport_config_, 189 channel->Initialize(name, session_manager_->transport_config_,
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
275 route.local_address); 263 route.local_address);
276 } 264 }
277 } 265 }
278 266
279 void JingleSession::OnTransportDeleted(Transport* transport) { 267 void JingleSession::OnTransportDeleted(Transport* transport) {
280 ChannelsMap::iterator it = channels_.find(transport->name()); 268 ChannelsMap::iterator it = channels_.find(transport->name());
281 DCHECK_EQ(it->second, transport); 269 DCHECK_EQ(it->second, transport);
282 channels_.erase(it); 270 channels_.erase(it);
283 } 271 }
284 272
273 void JingleSession::SendMessage(const JingleMessage& message) {
274 scoped_ptr<IqRequest> request = session_manager_->iq_sender()->SendIq(
275 message.ToXml(),
276 base::Bind(&JingleSession::OnMessageResponse,
277 base::Unretained(this), message.action));
278 if (request.get()) {
279 request->SetTimeout(
280 base::TimeDelta::FromSeconds(kMessageResponseTimeoutSeconds));
281 pending_requests_.push_back(request.release());
282 } else {
283 LOG(ERROR) << "Failed to send a "
284 << JingleMessage::GetActionName(message.action) << " message";
285 }
286 }
287
288 void JingleSession::OnMessageResponse(
289 JingleMessage::ActionType request_type,
290 IqRequest* request,
291 const buzz::XmlElement* response) {
292 Error error = OK;
293
294 std::string type_str = JingleMessage::GetActionName(request_type);
295
296 if (!response) {
297 LOG(ERROR) << type_str << " request timed out.";
298 // Most likely the session-initiate timeout indicates a problem
299 // with the signaling.
300 error = UNKNOWN_ERROR;
301 } else {
302 const std::string& type = response->Attr(buzz::QName("", "type"));
303 if (type != "result") {
304 LOG(ERROR) << "Received error in response to " << type_str
305 << " message: \"" << response->Str()
306 << "\". Terminating the session.";
307
308 switch (request_type) {
309 case JingleMessage::SESSION_INFO:
310 // session-info is used for the new authentication protocol,
311 // and wasn't previously supported.
312 error = INCOMPATIBLE_PROTOCOL;
313
314 default:
315 // TODO(sergeyu): There may be different reasons for error
316 // here. Parse the response stanza to find failure reason.
317 error = PEER_IS_OFFLINE;
318 }
319 }
320 }
321
322 CleanupPendingRequests(request);
323
324 if (error != OK) {
325 CloseInternal(error);
326 }
327 }
328
329 void JingleSession::CleanupPendingRequests(IqRequest* request) {
330 DCHECK(!pending_requests_.empty());
331 DCHECK(request);
332
333 // This method is called whenever a response to |request| is
334 // received. Here we delete that request and all requests that were
335 // sent before it. The idea here is that if we send messages A, B
336 // and C and then suddenly receive response to C then it means that
337 // either A and B messages or the corresponding response messages
338 // were somehow lost. E.g. that may happen when the client switches
339 // from one network to another. The best way to handle that case is
340 // to ignore errors and timeouts for A and B by deleting the
341 // corresponding IqRequest objects.
342 while (!pending_requests_.empty() && pending_requests_.front() != request) {
343 delete pending_requests_.front();
344 pending_requests_.pop_front();
345 }
346
347 // Delete the |request| itself.
348 DCHECK_EQ(request, pending_requests_.front());
349 delete request;
350 if (!pending_requests_.empty())
351 pending_requests_.pop_front();
352 }
353
285 void JingleSession::OnIncomingMessage(const JingleMessage& message, 354 void JingleSession::OnIncomingMessage(const JingleMessage& message,
286 const ReplyCallback& reply_callback) { 355 const ReplyCallback& reply_callback) {
287 DCHECK(CalledOnValidThread()); 356 DCHECK(CalledOnValidThread());
288 357
289 if (message.from != peer_jid_) { 358 if (message.from != peer_jid_) {
290 // Ignore messages received from a different Jid. 359 // Ignore messages received from a different Jid.
291 reply_callback.Run(JingleMessageReply::INVALID_SID); 360 reply_callback.Run(JingleMessageReply::INVALID_SID);
292 return; 361 return;
293 } 362 }
294 363
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
444 return true; 513 return true;
445 } 514 }
446 515
447 void JingleSession::ProcessAuthenticationStep() { 516 void JingleSession::ProcessAuthenticationStep() {
448 DCHECK_EQ(state_, CONNECTED); 517 DCHECK_EQ(state_, CONNECTED);
449 518
450 if (authenticator_->state() == Authenticator::MESSAGE_READY) { 519 if (authenticator_->state() == Authenticator::MESSAGE_READY) {
451 JingleMessage message(peer_jid_, JingleMessage::SESSION_INFO, session_id_); 520 JingleMessage message(peer_jid_, JingleMessage::SESSION_INFO, session_id_);
452 message.info = authenticator_->GetNextMessage(); 521 message.info = authenticator_->GetNextMessage();
453 DCHECK(message.info.get()); 522 DCHECK(message.info.get());
454 523 SendMessage(message);
455 session_info_request_ = session_manager_->iq_sender()->SendIq(
456 message.ToXml(), base::Bind(
457 &JingleSession::OnSessionInfoResponse,
458 base::Unretained(this)));
459 } 524 }
460 DCHECK_NE(authenticator_->state(), Authenticator::MESSAGE_READY); 525 DCHECK_NE(authenticator_->state(), Authenticator::MESSAGE_READY);
461 526
462 if (authenticator_->state() == Authenticator::ACCEPTED) { 527 if (authenticator_->state() == Authenticator::ACCEPTED) {
463 SetState(AUTHENTICATED); 528 SetState(AUTHENTICATED);
464 } else if (authenticator_->state() == Authenticator::REJECTED) { 529 } else if (authenticator_->state() == Authenticator::REJECTED) {
465 CloseInternal(AuthRejectionReasonToError( 530 CloseInternal(AuthRejectionReasonToError(
466 authenticator_->rejection_reason())); 531 authenticator_->rejection_reason()));
467 } 532 }
468 } 533 }
469 534
470 void JingleSession::OnSessionInfoResponse(const buzz::XmlElement* response) {
471 const std::string& type = response->Attr(buzz::QName("", "type"));
472 if (type != "result") {
473 LOG(ERROR) << "Received error in response to session-info message: \""
474 << response->Str()
475 << "\". Terminating the session.";
476 CloseInternal(INCOMPATIBLE_PROTOCOL);
477 }
478 }
479
480 void JingleSession::OnTransportInfoResponse(const buzz::XmlElement* response) {
481 const std::string& type = response->Attr(buzz::QName("", "type"));
482 if (type != "result") {
483 LOG(ERROR) << "Received error in response to session-initiate message: \""
484 << response->Str()
485 << "\". Terminating the session.";
486
487 if (state_ == CONNECTING) {
488 CloseInternal(PEER_IS_OFFLINE);
489 } else {
490 // Host has disconnected without sending session-terminate message.
491 CloseInternal(OK);
492 }
493 }
494 }
495
496 void JingleSession::SendTransportInfo() { 535 void JingleSession::SendTransportInfo() {
497 JingleMessage message(peer_jid_, JingleMessage::TRANSPORT_INFO, session_id_); 536 JingleMessage message(peer_jid_, JingleMessage::TRANSPORT_INFO, session_id_);
498 message.candidates.swap(pending_candidates_); 537 message.candidates.swap(pending_candidates_);
499 transport_info_request_ = session_manager_->iq_sender()->SendIq( 538 SendMessage(message);
500 message.ToXml(), base::Bind(
501 &JingleSession::OnTransportInfoResponse,
502 base::Unretained(this)));
503 } 539 }
504 540
505
506 void JingleSession::CloseInternal(Error error) { 541 void JingleSession::CloseInternal(Error error) {
507 DCHECK(CalledOnValidThread()); 542 DCHECK(CalledOnValidThread());
508 543
509 if (state_ == CONNECTING || state_ == CONNECTED || state_ == AUTHENTICATED) { 544 if (state_ == CONNECTING || state_ == CONNECTED || state_ == AUTHENTICATED) {
510 // Send session-terminate message with the appropriate error code. 545 // Send session-terminate message with the appropriate error code.
511 JingleMessage::Reason reason; 546 JingleMessage::Reason reason;
512 switch (error) { 547 switch (error) {
513 case OK: 548 case OK:
514 reason = JingleMessage::SUCCESS; 549 reason = JingleMessage::SUCCESS;
515 break; 550 break;
516 case SESSION_REJECTED: 551 case SESSION_REJECTED:
517 case AUTHENTICATION_FAILED: 552 case AUTHENTICATION_FAILED:
518 reason = JingleMessage::DECLINE; 553 reason = JingleMessage::DECLINE;
519 break; 554 break;
520 case INCOMPATIBLE_PROTOCOL: 555 case INCOMPATIBLE_PROTOCOL:
521 reason = JingleMessage::INCOMPATIBLE_PARAMETERS; 556 reason = JingleMessage::INCOMPATIBLE_PARAMETERS;
522 break; 557 break;
523 default: 558 default:
524 reason = JingleMessage::GENERAL_ERROR; 559 reason = JingleMessage::GENERAL_ERROR;
525 } 560 }
526 561
527 JingleMessage message(peer_jid_, JingleMessage::SESSION_TERMINATE, 562 JingleMessage message(peer_jid_, JingleMessage::SESSION_TERMINATE,
528 session_id_); 563 session_id_);
529 message.reason = reason; 564 message.reason = reason;
530 session_manager_->iq_sender()->SendIq( 565 SendMessage(message);
531 message.ToXml(), IqSender::ReplyCallback());
532 } 566 }
533 567
534 error_ = error; 568 error_ = error;
535 569
536 if (state_ != FAILED && state_ != CLOSED) { 570 if (state_ != FAILED && state_ != CLOSED) {
537 if (error != OK) { 571 if (error != OK) {
538 SetState(FAILED); 572 SetState(FAILED);
539 } else { 573 } else {
540 SetState(CLOSED); 574 SetState(CLOSED);
541 } 575 }
542 } 576 }
543 } 577 }
544 578
545 void JingleSession::SetState(State new_state) { 579 void JingleSession::SetState(State new_state) {
546 DCHECK(CalledOnValidThread()); 580 DCHECK(CalledOnValidThread());
547 581
548 if (new_state != state_) { 582 if (new_state != state_) {
549 DCHECK_NE(state_, CLOSED); 583 DCHECK_NE(state_, CLOSED);
550 DCHECK_NE(state_, FAILED); 584 DCHECK_NE(state_, FAILED);
551 585
552 state_ = new_state; 586 state_ = new_state;
553 if (!state_change_callback_.is_null()) 587 if (!state_change_callback_.is_null())
554 state_change_callback_.Run(new_state); 588 state_change_callback_.Run(new_state);
555 } 589 }
556 } 590 }
557 591
558 } // namespace protocol 592 } // namespace protocol
559 } // namespace remoting 593 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/protocol/jingle_session.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698