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

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: - Created 8 years, 10 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
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"
(...skipping 14 matching lines...) Expand all
25 namespace protocol { 25 namespace protocol {
26 26
27 namespace { 27 namespace {
28 // Delay after candidate creation before sending transport-info 28 // Delay after candidate creation before sending transport-info
29 // message. This is neccessary to be able to pack multiple candidates 29 // message. This is neccessary to be able to pack multiple candidates
30 // into one transport-info messages. The value needs to be greater 30 // into one transport-info messages. The value needs to be greater
31 // than zero because ports are opened asynchronously in the browser 31 // than zero because ports are opened asynchronously in the browser
32 // process. 32 // process.
33 const int kTransportInfoSendDelayMs = 2; 33 const int kTransportInfoSendDelayMs = 2;
34 34
35 // How long we should wait for a response from the other end. This
36 // value is used for all requests include |session-initiate| and
37 // |transport-info|.
38 const int kMessageResponseTimeoutSeconds = 10;
39
35 Session::Error AuthRejectionReasonToError( 40 Session::Error AuthRejectionReasonToError(
36 Authenticator::RejectionReason reason) { 41 Authenticator::RejectionReason reason) {
37 switch (reason) { 42 switch (reason) {
38 case Authenticator::INVALID_CREDENTIALS: 43 case Authenticator::INVALID_CREDENTIALS:
39 return Session::AUTHENTICATION_FAILED; 44 return Session::AUTHENTICATION_FAILED;
40 case Authenticator::PROTOCOL_ERROR: 45 case Authenticator::PROTOCOL_ERROR:
41 return Session::INCOMPATIBLE_PROTOCOL; 46 return Session::INCOMPATIBLE_PROTOCOL;
42 } 47 }
43 NOTREACHED(); 48 NOTREACHED();
44 return Session::UNKNOWN_ERROR; 49 return Session::UNKNOWN_ERROR;
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
95 // enough entropy. In the worst case connection will fail when two 100 // enough entropy. In the worst case connection will fail when two
96 // clients generate the same session ID concurrently. 101 // clients generate the same session ID concurrently.
97 session_id_ = base::Int64ToString(base::RandGenerator(kint64max)); 102 session_id_ = base::Int64ToString(base::RandGenerator(kint64max));
98 103
99 // Send session-initiate message. 104 // Send session-initiate message.
100 JingleMessage message(peer_jid_, JingleMessage::SESSION_INITIATE, 105 JingleMessage message(peer_jid_, JingleMessage::SESSION_INITIATE,
101 session_id_); 106 session_id_);
102 message.description.reset( 107 message.description.reset(
103 new ContentDescription(candidate_config_->Clone(), 108 new ContentDescription(candidate_config_->Clone(),
104 authenticator_->GetNextMessage())); 109 authenticator_->GetNextMessage()));
105 initiate_request_ = session_manager_->iq_sender()->SendIq( 110 SendMessage(message);
106 message.ToXml(),
107 base::Bind(&JingleSession::OnSessionInitiateResponse,
108 base::Unretained(this)));
109 111
110 SetState(CONNECTING); 112 SetState(CONNECTING);
111 } 113 }
112 114
113 void JingleSession::InitializeIncomingConnection( 115 void JingleSession::InitializeIncomingConnection(
114 const JingleMessage& initiate_message, 116 const JingleMessage& initiate_message,
115 scoped_ptr<Authenticator> authenticator) { 117 scoped_ptr<Authenticator> authenticator) {
116 DCHECK(CalledOnValidThread()); 118 DCHECK(CalledOnValidThread());
117 DCHECK(initiate_message.description.get()); 119 DCHECK(initiate_message.description.get());
118 DCHECK(authenticator.get()); 120 DCHECK(authenticator.get());
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
151 JingleMessage message(peer_jid_, JingleMessage::SESSION_ACCEPT, 153 JingleMessage message(peer_jid_, JingleMessage::SESSION_ACCEPT,
152 session_id_); 154 session_id_);
153 155
154 scoped_ptr<buzz::XmlElement> auth_message; 156 scoped_ptr<buzz::XmlElement> auth_message;
155 if (authenticator_->state() == Authenticator::MESSAGE_READY) 157 if (authenticator_->state() == Authenticator::MESSAGE_READY)
156 auth_message = authenticator_->GetNextMessage(); 158 auth_message = authenticator_->GetNextMessage();
157 159
158 message.description.reset( 160 message.description.reset(
159 new ContentDescription(CandidateSessionConfig::CreateFrom(config_), 161 new ContentDescription(CandidateSessionConfig::CreateFrom(config_),
160 auth_message.Pass())); 162 auth_message.Pass()));
161 initiate_request_ = session_manager_->iq_sender()->SendIq( 163 SendMessage(message);
162 message.ToXml(),
163 base::Bind(&JingleSession::OnSessionInitiateResponse,
164 base::Unretained(this)));
165 164
166 // Update state. 165 // Update state.
167 SetState(CONNECTED); 166 SetState(CONNECTED);
168 167
169 if (authenticator_->state() == Authenticator::ACCEPTED) { 168 if (authenticator_->state() == Authenticator::ACCEPTED) {
170 SetState(AUTHENTICATED); 169 SetState(AUTHENTICATED);
171 } else { 170 } else {
172 DCHECK_EQ(authenticator_->state(), Authenticator::WAITING_MESSAGE); 171 DCHECK_EQ(authenticator_->state(), Authenticator::WAITING_MESSAGE);
173 } 172 }
174 173
175 return; 174 return;
176 } 175 }
177 176
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( 177 void JingleSession::CreateStreamChannel(
193 const std::string& name, 178 const std::string& name,
194 const StreamChannelCallback& callback) { 179 const StreamChannelCallback& callback) {
195 DCHECK(!channels_[name]); 180 DCHECK(!channels_[name]);
196 181
197 scoped_ptr<ChannelAuthenticator> channel_authenticator = 182 scoped_ptr<ChannelAuthenticator> channel_authenticator =
198 authenticator_->CreateChannelAuthenticator(); 183 authenticator_->CreateChannelAuthenticator();
199 scoped_ptr<StreamTransport> channel = 184 scoped_ptr<StreamTransport> channel =
200 session_manager_->transport_factory_->CreateStreamTransport(); 185 session_manager_->transport_factory_->CreateStreamTransport();
201 channel->Initialize(name, session_manager_->transport_config_, 186 channel->Initialize(name, session_manager_->transport_config_,
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
275 route.local_address); 260 route.local_address);
276 } 261 }
277 } 262 }
278 263
279 void JingleSession::OnTransportDeleted(Transport* transport) { 264 void JingleSession::OnTransportDeleted(Transport* transport) {
280 ChannelsMap::iterator it = channels_.find(transport->name()); 265 ChannelsMap::iterator it = channels_.find(transport->name());
281 DCHECK_EQ(it->second, transport); 266 DCHECK_EQ(it->second, transport);
282 channels_.erase(it); 267 channels_.erase(it);
283 } 268 }
284 269
270 void JingleSession::SendMessage(const JingleMessage& message) {
271 scoped_ptr<IqRequest> request = session_manager_->iq_sender()->SendIq(
272 message.ToXml(),
273 base::Bind(&JingleSession::OnIqMessageResponse,
274 base::Unretained(this), message.action));
275 if (request.get()) {
276 request->SetTimeout(
277 base::TimeDelta::FromSeconds(kMessageResponseTimeoutSeconds));
278 pending_requests_.push_back(request.release());
279 }
simonmorris 2012/02/24 00:11:31 Log an error if request.get() is NULL?
Sergey Ulanov 2012/02/24 21:56:31 Done.
280 }
281
285 void JingleSession::OnIncomingMessage(const JingleMessage& message, 282 void JingleSession::OnIncomingMessage(const JingleMessage& message,
286 const ReplyCallback& reply_callback) { 283 const ReplyCallback& reply_callback) {
287 DCHECK(CalledOnValidThread()); 284 DCHECK(CalledOnValidThread());
288 285
289 if (message.from != peer_jid_) { 286 if (message.from != peer_jid_) {
290 // Ignore messages received from a different Jid. 287 // Ignore messages received from a different Jid.
291 reply_callback.Run(JingleMessageReply::INVALID_SID); 288 reply_callback.Run(JingleMessageReply::INVALID_SID);
292 return; 289 return;
293 } 290 }
294 291
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
444 return true; 441 return true;
445 } 442 }
446 443
447 void JingleSession::ProcessAuthenticationStep() { 444 void JingleSession::ProcessAuthenticationStep() {
448 DCHECK_EQ(state_, CONNECTED); 445 DCHECK_EQ(state_, CONNECTED);
449 446
450 if (authenticator_->state() == Authenticator::MESSAGE_READY) { 447 if (authenticator_->state() == Authenticator::MESSAGE_READY) {
451 JingleMessage message(peer_jid_, JingleMessage::SESSION_INFO, session_id_); 448 JingleMessage message(peer_jid_, JingleMessage::SESSION_INFO, session_id_);
452 message.info = authenticator_->GetNextMessage(); 449 message.info = authenticator_->GetNextMessage();
453 DCHECK(message.info.get()); 450 DCHECK(message.info.get());
454 451 SendMessage(message);
455 session_info_request_ = session_manager_->iq_sender()->SendIq(
456 message.ToXml(), base::Bind(
457 &JingleSession::OnSessionInfoResponse,
458 base::Unretained(this)));
459 } 452 }
460 DCHECK_NE(authenticator_->state(), Authenticator::MESSAGE_READY); 453 DCHECK_NE(authenticator_->state(), Authenticator::MESSAGE_READY);
461 454
462 if (authenticator_->state() == Authenticator::ACCEPTED) { 455 if (authenticator_->state() == Authenticator::ACCEPTED) {
463 SetState(AUTHENTICATED); 456 SetState(AUTHENTICATED);
464 } else if (authenticator_->state() == Authenticator::REJECTED) { 457 } else if (authenticator_->state() == Authenticator::REJECTED) {
465 CloseInternal(AuthRejectionReasonToError( 458 CloseInternal(AuthRejectionReasonToError(
466 authenticator_->rejection_reason())); 459 authenticator_->rejection_reason()));
467 } 460 }
468 } 461 }
469 462
470 void JingleSession::OnSessionInfoResponse(const buzz::XmlElement* response) { 463 void JingleSession::OnIqMessageResponse(
471 const std::string& type = response->Attr(buzz::QName("", "type")); 464 JingleMessage::ActionType request_type,
472 if (type != "result") { 465 IqRequest* request,
473 LOG(ERROR) << "Received error in response to session-info message: \"" 466 const buzz::XmlElement* response) {
474 << response->Str() 467 Error error = OK;
475 << "\". Terminating the session."; 468
476 CloseInternal(INCOMPATIBLE_PROTOCOL); 469 std::string type_str = JingleMessage::GetActionName(request_type);
470
471 if (!response) {
472 LOG(ERROR) << type_str << " request timed out.";
473 // Most likely the session-initiate timeout indicates a problem
474 // with the signaling.
475 error = UNKNOWN_ERROR;
476 } else {
477 const std::string& type = response->Attr(buzz::QName("", "type"));
478 if (type != "result") {
479 LOG(ERROR) << "Received error in response to " << type_str
480 << " message: \"" << response->Str()
481 << "\". Terminating the session.";
482
483 switch (request_type) {
484 case JingleMessage::SESSION_INFO:
485 // session-info is used for the new authentication protocol,
486 // and wasn't previously supported.
487 error = INCOMPATIBLE_PROTOCOL;
488
489 default:
490 // TODO(sergeyu): There may be different reasons for error
491 // here. Parse the response stanza to find failure reason.
492 error = PEER_IS_OFFLINE;
493 }
494 }
495 }
496
497 CleanupPendingRequests(request);
498
499 if (error != OK) {
500 CloseInternal(error);
477 } 501 }
478 } 502 }
479 503
480 void JingleSession::OnTransportInfoResponse(const buzz::XmlElement* response) { 504 void JingleSession::CleanupPendingRequests(IqRequest* request) {
481 const std::string& type = response->Attr(buzz::QName("", "type")); 505 DCHECK(!pending_requests_.empty());
482 if (type != "result") { 506 DCHECK(request);
483 LOG(ERROR) << "Received error in response to session-initiate message: \""
484 << response->Str()
485 << "\". Terminating the session.";
486 507
487 if (state_ == CONNECTING) { 508 // This method is called whenever a response to |request| is
488 CloseInternal(PEER_IS_OFFLINE); 509 // received. Here we delete that request and all requests that were
489 } else { 510 // sent before it.
simonmorris 2012/02/24 00:11:31 Why delete all requests sent before the given requ
Sergey Ulanov 2012/02/24 21:56:31 The logic here is that if we send messages A, B an
simonmorris 2012/02/24 22:32:51 The simple thing to do is just let A and B timeout
Sergey Ulanov 2012/02/25 00:11:52 That would mean that the session will terminate ev
simonmorris 2012/02/25 00:25:21 OK - if it's clear that a session can be considere
490 // Host has disconnected without sending session-terminate message. 511 while (!pending_requests_.empty() && pending_requests_.front() != request) {
491 CloseInternal(OK); 512 delete pending_requests_.front();
492 } 513 pending_requests_.pop_front();
493 } 514 }
515
516 // Delete the |request| itself.
517 DCHECK_EQ(request, pending_requests_.front());
518 delete request;
519 if (!pending_requests_.empty())
520 pending_requests_.pop_front();
494 } 521 }
495 522
496 void JingleSession::SendTransportInfo() { 523 void JingleSession::SendTransportInfo() {
497 JingleMessage message(peer_jid_, JingleMessage::TRANSPORT_INFO, session_id_); 524 JingleMessage message(peer_jid_, JingleMessage::TRANSPORT_INFO, session_id_);
498 message.candidates.swap(pending_candidates_); 525 message.candidates.swap(pending_candidates_);
499 transport_info_request_ = session_manager_->iq_sender()->SendIq( 526 SendMessage(message);
500 message.ToXml(), base::Bind(
501 &JingleSession::OnTransportInfoResponse,
502 base::Unretained(this)));
503 } 527 }
504 528
505
506 void JingleSession::CloseInternal(Error error) { 529 void JingleSession::CloseInternal(Error error) {
507 DCHECK(CalledOnValidThread()); 530 DCHECK(CalledOnValidThread());
508 531
509 if (state_ == CONNECTING || state_ == CONNECTED || state_ == AUTHENTICATED) { 532 if (state_ == CONNECTING || state_ == CONNECTED || state_ == AUTHENTICATED) {
510 // Send session-terminate message with the appropriate error code. 533 // Send session-terminate message with the appropriate error code.
511 JingleMessage::Reason reason; 534 JingleMessage::Reason reason;
512 switch (error) { 535 switch (error) {
513 case OK: 536 case OK:
514 reason = JingleMessage::SUCCESS; 537 reason = JingleMessage::SUCCESS;
515 break; 538 break;
516 case SESSION_REJECTED: 539 case SESSION_REJECTED:
517 case AUTHENTICATION_FAILED: 540 case AUTHENTICATION_FAILED:
518 reason = JingleMessage::DECLINE; 541 reason = JingleMessage::DECLINE;
519 break; 542 break;
520 case INCOMPATIBLE_PROTOCOL: 543 case INCOMPATIBLE_PROTOCOL:
521 reason = JingleMessage::INCOMPATIBLE_PARAMETERS; 544 reason = JingleMessage::INCOMPATIBLE_PARAMETERS;
522 break; 545 break;
523 default: 546 default:
524 reason = JingleMessage::GENERAL_ERROR; 547 reason = JingleMessage::GENERAL_ERROR;
525 } 548 }
526 549
527 JingleMessage message(peer_jid_, JingleMessage::SESSION_TERMINATE, 550 JingleMessage message(peer_jid_, JingleMessage::SESSION_TERMINATE,
528 session_id_); 551 session_id_);
529 message.reason = reason; 552 message.reason = reason;
530 session_manager_->iq_sender()->SendIq( 553 SendMessage(message);
531 message.ToXml(), IqSender::ReplyCallback());
532 } 554 }
533 555
534 error_ = error; 556 error_ = error;
535 557
536 if (state_ != FAILED && state_ != CLOSED) { 558 if (state_ != FAILED && state_ != CLOSED) {
537 if (error != OK) { 559 if (error != OK) {
538 SetState(FAILED); 560 SetState(FAILED);
539 } else { 561 } else {
540 SetState(CLOSED); 562 SetState(CLOSED);
541 } 563 }
542 } 564 }
543 } 565 }
544 566
545 void JingleSession::SetState(State new_state) { 567 void JingleSession::SetState(State new_state) {
546 DCHECK(CalledOnValidThread()); 568 DCHECK(CalledOnValidThread());
547 569
548 if (new_state != state_) { 570 if (new_state != state_) {
549 DCHECK_NE(state_, CLOSED); 571 DCHECK_NE(state_, CLOSED);
550 DCHECK_NE(state_, FAILED); 572 DCHECK_NE(state_, FAILED);
551 573
552 state_ = new_state; 574 state_ = new_state;
553 if (!state_change_callback_.is_null()) 575 if (!state_change_callback_.is_null())
554 state_change_callback_.Run(new_state); 576 state_change_callback_.Run(new_state);
555 } 577 }
556 } 578 }
557 579
558 } // namespace protocol 580 } // namespace protocol
559 } // namespace remoting 581 } // namespace remoting
OLDNEW
« remoting/jingle_glue/iq_sender.cc ('K') | « remoting/protocol/jingle_session.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698