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

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

Issue 2453933008: Bugfixes in JingleSession (Closed)
Patch Set: Created 4 years, 1 month 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
« no previous file with comments | « remoting/protocol/jingle_session.h ('k') | remoting/protocol/jingle_session_unittest.cc » ('j') | 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 <stdint.h> 7 #include <stdint.h>
8 8
9 #include <limits> 9 #include <limits>
10 #include <utility> 10 #include <utility>
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
99 // This behavior leads to transient session setup failures. For instance, 99 // This behavior leads to transient session setup failures. For instance,
100 // a <transport-info> that is sent after a <session-info> message is sometimes 100 // a <transport-info> that is sent after a <session-info> message is sometimes
101 // delivered to the client out of order, causing the client to close the 101 // delivered to the client out of order, causing the client to close the
102 // session due to an unexpected request. 102 // session due to an unexpected request.
103 class JingleSession::OrderedMessageQueue { 103 class JingleSession::OrderedMessageQueue {
104 public: 104 public:
105 OrderedMessageQueue() {} 105 OrderedMessageQueue() {}
106 ~OrderedMessageQueue() {} 106 ~OrderedMessageQueue() {}
107 107
108 // Returns the list of messages ordered by their sequential IDs. 108 // Returns the list of messages ordered by their sequential IDs.
109 std::vector<std::unique_ptr<PendingMessage>> OnIncomingMessage( 109 std::vector<PendingMessage> OnIncomingMessage(
110 const std::string& id, 110 const std::string& id,
111 std::unique_ptr<PendingMessage>); 111 PendingMessage&& pending_message);
112 112
113 private: 113 private:
114 // Implements an ordered list by using map with the |sequence_id| as the key, 114 // Implements an ordered list by using map with the |sequence_id| as the key,
115 // so that |queue_| is always sorted by |sequence_id|. 115 // so that |queue_| is always sorted by |sequence_id|.
116 std::map<int, std::unique_ptr<PendingMessage>> queue_; 116 std::map<int, PendingMessage> queue_;
117 117
118 int next_incoming_ = kAny; 118 int next_incoming_ = kAny;
119 119
120 DISALLOW_COPY_AND_ASSIGN(OrderedMessageQueue); 120 DISALLOW_COPY_AND_ASSIGN(OrderedMessageQueue);
121 }; 121 };
122 122
123 std::vector<std::unique_ptr<JingleSession::PendingMessage>> 123 std::vector<JingleSession::PendingMessage>
124 JingleSession::OrderedMessageQueue::OnIncomingMessage( 124 JingleSession::OrderedMessageQueue::OnIncomingMessage(
125 const std::string& id, 125 const std::string& id,
126 std::unique_ptr<JingleSession::PendingMessage> message) { 126 JingleSession::PendingMessage&& message) {
127 std::vector<std::unique_ptr<JingleSession::PendingMessage>> result; 127 std::vector<JingleSession::PendingMessage> result;
128 int current = GetSequentialId(id); 128 int current = GetSequentialId(id);
129 // If there is no sequencing order encoded in the id, just return the 129 // If there is no sequencing order encoded in the id, just return the
130 // message. 130 // message.
131 if (current == kInvalid) { 131 if (current == kInvalid) {
132 result.push_back(std::move(message)); 132 result.push_back(std::move(message));
133 return result; 133 return result;
134 } 134 }
135 135
136 if (next_incoming_ == kAny) { 136 if (next_incoming_ == kAny) {
137 next_incoming_ = current; 137 next_incoming_ = current;
(...skipping 12 matching lines...) Expand all
150 next_incoming_++; 150 next_incoming_++;
151 } 151 }
152 152
153 if (current - next_incoming_ >= 3) { 153 if (current - next_incoming_ >= 3) {
154 LOG(WARNING) << "Multiple messages are missing: expected= " 154 LOG(WARNING) << "Multiple messages are missing: expected= "
155 << next_incoming_ << " current= " << current; 155 << next_incoming_ << " current= " << current;
156 } 156 }
157 return result; 157 return result;
158 }; 158 };
159 159
160 JingleSession::PendingMessage::PendingMessage() = default;
kelvinp 2016/10/31 18:23:14 Out of curiosity, why is a default empty construct
Sergey Ulanov 2016/10/31 18:25:02 std::vector<> needs it.
161 JingleSession::PendingMessage::PendingMessage(PendingMessage&& moved) = default;
160 JingleSession::PendingMessage::PendingMessage( 162 JingleSession::PendingMessage::PendingMessage(
161 std::unique_ptr<JingleMessage> message, 163 std::unique_ptr<JingleMessage> message,
162 const ReplyCallback& reply_callback) 164 const ReplyCallback& reply_callback)
163 : message(std::move(message)), reply_callback(reply_callback) {} 165 : message(std::move(message)), reply_callback(reply_callback) {}
166 JingleSession::PendingMessage::~PendingMessage() = default;
164 167
165 JingleSession::PendingMessage::~PendingMessage() {} 168 JingleSession::PendingMessage& JingleSession::PendingMessage::operator=(
169 PendingMessage&& moved) = default;
166 170
167 JingleSession::JingleSession(JingleSessionManager* session_manager) 171 JingleSession::JingleSession(JingleSessionManager* session_manager)
168 : session_manager_(session_manager), 172 : session_manager_(session_manager),
169 event_handler_(nullptr), 173 event_handler_(nullptr),
170 state_(INITIALIZING), 174 state_(INITIALIZING),
171 error_(OK), 175 error_(OK),
172 message_queue_(new OrderedMessageQueue), 176 message_queue_(new OrderedMessageQueue),
173 weak_factory_(this) {} 177 weak_factory_(this) {}
174 178
175 JingleSession::~JingleSession() { 179 JingleSession::~JingleSession() {
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after
392 std::move(stanza), base::Bind(&JingleSession::OnMessageResponse, 396 std::move(stanza), base::Bind(&JingleSession::OnMessageResponse,
393 base::Unretained(this), message->action)); 397 base::Unretained(this), message->action));
394 398
395 int timeout = kDefaultMessageTimeout; 399 int timeout = kDefaultMessageTimeout;
396 if (message->action == JingleMessage::SESSION_INITIATE || 400 if (message->action == JingleMessage::SESSION_INITIATE ||
397 message->action == JingleMessage::SESSION_ACCEPT) { 401 message->action == JingleMessage::SESSION_ACCEPT) {
398 timeout = kSessionInitiateAndAcceptTimeout; 402 timeout = kSessionInitiateAndAcceptTimeout;
399 } 403 }
400 if (request) { 404 if (request) {
401 request->SetTimeout(base::TimeDelta::FromSeconds(timeout)); 405 request->SetTimeout(base::TimeDelta::FromSeconds(timeout));
402 pending_requests_.insert(std::move(request)); 406 pending_requests_.push_back(std::move(request));
403 } else { 407 } else {
404 LOG(ERROR) << "Failed to send a " 408 LOG(ERROR) << "Failed to send a "
405 << JingleMessage::GetActionName(message->action) << " message"; 409 << JingleMessage::GetActionName(message->action) << " message";
406 } 410 }
407 } 411 }
408 412
409 void JingleSession::OnMessageResponse( 413 void JingleSession::OnMessageResponse(
410 JingleMessage::ActionType request_type, 414 JingleMessage::ActionType request_type,
411 IqRequest* request, 415 IqRequest* request,
412 const buzz::XmlElement* response) { 416 const buzz::XmlElement* response) {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
444 } 448 }
445 } 449 }
446 } 450 }
447 451
448 void JingleSession::OnTransportInfoResponse(IqRequest* request, 452 void JingleSession::OnTransportInfoResponse(IqRequest* request,
449 const buzz::XmlElement* response) { 453 const buzz::XmlElement* response) {
450 DCHECK(thread_checker_.CalledOnValidThread()); 454 DCHECK(thread_checker_.CalledOnValidThread());
451 DCHECK(!transport_info_requests_.empty()); 455 DCHECK(!transport_info_requests_.empty());
452 456
453 // Consider transport-info requests sent before this one lost and delete 457 // Consider transport-info requests sent before this one lost and delete
454 // corresponding IqRequest objects. 458 // all IqRequest objects in front of |request|.
455 while (transport_info_requests_.front().get() != request) { 459 auto request_it = std::find_if(
456 transport_info_requests_.pop_front(); 460 transport_info_requests_.begin(), transport_info_requests_.end(),
457 } 461 [request](const std::unique_ptr<IqRequest>& ptr) {
458 462 return ptr.get() == request;
459 // Delete the |request| itself. 463 });
460 DCHECK_EQ(request, transport_info_requests_.front().get()); 464 DCHECK(request_it != transport_info_requests_.end());
461 transport_info_requests_.pop_front(); 465 transport_info_requests_.erase(transport_info_requests_.begin(),
466 request_it + 1);
462 467
463 // Ignore transport-info timeouts. 468 // Ignore transport-info timeouts.
464 if (!response) { 469 if (!response) {
465 LOG(ERROR) << "transport-info request has timed out."; 470 LOG(ERROR) << "transport-info request has timed out.";
466 return; 471 return;
467 } 472 }
468 473
469 const std::string& type = response->Attr(buzz::QName(std::string(), "type")); 474 const std::string& type = response->Attr(buzz::QName(std::string(), "type"));
470 if (type != "result") { 475 if (type != "result") {
471 LOG(ERROR) << "Received error in response to transport-info message: \"" 476 LOG(ERROR) << "Received error in response to transport-info message: \""
472 << response->Str() << "\". Terminating the session."; 477 << response->Str() << "\". Terminating the session.";
473 Close(PEER_IS_OFFLINE); 478 Close(PEER_IS_OFFLINE);
474 } 479 }
475 } 480 }
476 481
477 void JingleSession::OnIncomingMessage(const std::string& id, 482 void JingleSession::OnIncomingMessage(const std::string& id,
478 std::unique_ptr<JingleMessage> message, 483 std::unique_ptr<JingleMessage> message,
479 const ReplyCallback& reply_callback) { 484 const ReplyCallback& reply_callback) {
480 std::unique_ptr<PendingMessage> item( 485 std::vector<PendingMessage> ordered = message_queue_->OnIncomingMessage(
481 new PendingMessage(std::move(message), reply_callback)); 486 id, PendingMessage{std::move(message), reply_callback});
482 std::vector<std::unique_ptr<PendingMessage>> ordered = 487 base::WeakPtr<JingleSession> self = weak_factory_.GetWeakPtr();
483 message_queue_->OnIncomingMessage(id, std::move(item));
484 for (auto& message : ordered) { 488 for (auto& message : ordered) {
485 ProcessIncomingMessage(std::move(message->message), 489 ProcessIncomingMessage(std::move(message.message), message.reply_callback);
486 message->reply_callback); 490 if (!self)
491 return;
487 } 492 }
488 } 493 }
489 494
490 void JingleSession::ProcessIncomingMessage( 495 void JingleSession::ProcessIncomingMessage(
491 std::unique_ptr<JingleMessage> message, 496 std::unique_ptr<JingleMessage> message,
492 const ReplyCallback& reply_callback) { 497 const ReplyCallback& reply_callback) {
493 DCHECK(thread_checker_.CalledOnValidThread()); 498 DCHECK(thread_checker_.CalledOnValidThread());
494 499
495 if (peer_address_ != message->from) { 500 if (peer_address_ != message->from) {
496 // Ignore messages received from a different Jid. 501 // Ignore messages received from a different Jid.
497 reply_callback.Run(JingleMessageReply::INVALID_SID); 502 reply_callback.Run(JingleMessageReply::INVALID_SID);
498 return; 503 return;
499 } 504 }
500 505
501 switch (message->action) { 506 switch (message->action) {
502 case JingleMessage::SESSION_ACCEPT: 507 case JingleMessage::SESSION_ACCEPT:
503 OnAccept(std::move(message), reply_callback); 508 OnAccept(std::move(message), reply_callback);
504 break; 509 break;
505 510
506 case JingleMessage::SESSION_INFO: 511 case JingleMessage::SESSION_INFO:
507 OnSessionInfo(std::move(message), reply_callback); 512 OnSessionInfo(std::move(message), reply_callback);
508 break; 513 break;
509 514
510 case JingleMessage::TRANSPORT_INFO: 515 case JingleMessage::TRANSPORT_INFO:
511 if (!transport_) { 516 OnTransportInfo(std::move(message), reply_callback);
512 LOG(ERROR) << "Received unexpected transport-info message->";
513 reply_callback.Run(JingleMessageReply::NONE);
514 return;
515 }
516
517 if (!message->transport_info ||
518 !transport_->ProcessTransportInfo(message->transport_info.get())) {
519 reply_callback.Run(JingleMessageReply::BAD_REQUEST);
520 return;
521 }
522
523 reply_callback.Run(JingleMessageReply::NONE);
524 break; 517 break;
525 518
526 case JingleMessage::SESSION_TERMINATE: 519 case JingleMessage::SESSION_TERMINATE:
527 OnTerminate(std::move(message), reply_callback); 520 OnTerminate(std::move(message), reply_callback);
528 break; 521 break;
529 522
530 default: 523 default:
531 reply_callback.Run(JingleMessageReply::UNEXPECTED_REQUEST); 524 reply_callback.Run(JingleMessageReply::UNEXPECTED_REQUEST);
532 } 525 }
533 } 526 }
(...skipping 16 matching lines...) Expand all
550 } 543 }
551 544
552 if (!InitializeConfigFromDescription(message->description.get())) { 545 if (!InitializeConfigFromDescription(message->description.get())) {
553 Close(INCOMPATIBLE_PROTOCOL); 546 Close(INCOMPATIBLE_PROTOCOL);
554 return; 547 return;
555 } 548 }
556 549
557 SetState(ACCEPTED); 550 SetState(ACCEPTED);
558 551
559 DCHECK(authenticator_->state() == Authenticator::WAITING_MESSAGE); 552 DCHECK(authenticator_->state() == Authenticator::WAITING_MESSAGE);
560 authenticator_->ProcessMessage(auth_message, base::Bind( 553 authenticator_->ProcessMessage(
561 &JingleSession::ProcessAuthenticationStep,base::Unretained(this))); 554 auth_message, base::Bind(&JingleSession::ProcessAuthenticationStep,
555 base::Unretained(this)));
562 } 556 }
563 557
564 void JingleSession::OnSessionInfo(std::unique_ptr<JingleMessage> message, 558 void JingleSession::OnSessionInfo(std::unique_ptr<JingleMessage> message,
565 const ReplyCallback& reply_callback) { 559 const ReplyCallback& reply_callback) {
566 if (!message->info.get() || 560 if (!message->info.get() ||
567 !Authenticator::IsAuthenticatorMessage(message->info.get())) { 561 !Authenticator::IsAuthenticatorMessage(message->info.get())) {
568 reply_callback.Run(JingleMessageReply::UNSUPPORTED_INFO); 562 reply_callback.Run(JingleMessageReply::UNSUPPORTED_INFO);
569 return; 563 return;
570 } 564 }
571 565
572 if ((state_ != ACCEPTED && state_ != AUTHENTICATING) || 566 if ((state_ != ACCEPTED && state_ != AUTHENTICATING) ||
573 authenticator_->state() != Authenticator::WAITING_MESSAGE) { 567 authenticator_->state() != Authenticator::WAITING_MESSAGE) {
574 LOG(WARNING) << "Received unexpected authenticator message " 568 LOG(WARNING) << "Received unexpected authenticator message "
575 << message->info->Str(); 569 << message->info->Str();
576 reply_callback.Run(JingleMessageReply::UNEXPECTED_REQUEST); 570 reply_callback.Run(JingleMessageReply::UNEXPECTED_REQUEST);
577 Close(INCOMPATIBLE_PROTOCOL); 571 Close(INCOMPATIBLE_PROTOCOL);
578 return; 572 return;
579 } 573 }
580 574
581 reply_callback.Run(JingleMessageReply::NONE); 575 reply_callback.Run(JingleMessageReply::NONE);
582 576
583 authenticator_->ProcessMessage(message->info.get(), base::Bind( 577 authenticator_->ProcessMessage(
584 &JingleSession::ProcessAuthenticationStep, base::Unretained(this))); 578 message->info.get(), base::Bind(&JingleSession::ProcessAuthenticationStep,
579 base::Unretained(this)));
580 }
581
582 void JingleSession::OnTransportInfo(std::unique_ptr<JingleMessage> message,
583 const ReplyCallback& reply_callback) {
584 if (!message->transport_info) {
585 reply_callback.Run(JingleMessageReply::BAD_REQUEST);
586 return;
587 }
588
589 if (state_ == AUTHENTICATING) {
590 pending_transport_info_.push_back(
591 PendingMessage{std::move(message), reply_callback});
592 } else if (state_ == AUTHENTICATED) {
593 reply_callback.Run(
594 transport_->ProcessTransportInfo(message->transport_info.get())
595 ? JingleMessageReply::NONE
596 : JingleMessageReply::BAD_REQUEST);
597 } else {
598 LOG(ERROR) << "Received unexpected transport-info message.";
599 reply_callback.Run(JingleMessageReply::UNEXPECTED_REQUEST);
600 }
585 } 601 }
586 602
587 void JingleSession::OnTerminate(std::unique_ptr<JingleMessage> message, 603 void JingleSession::OnTerminate(std::unique_ptr<JingleMessage> message,
588 const ReplyCallback& reply_callback) { 604 const ReplyCallback& reply_callback) {
589 if (!is_session_active()) { 605 if (!is_session_active()) {
590 LOG(WARNING) << "Received unexpected session-terminate message."; 606 LOG(WARNING) << "Received unexpected session-terminate message.";
591 reply_callback.Run(JingleMessageReply::UNEXPECTED_REQUEST); 607 reply_callback.Run(JingleMessageReply::UNEXPECTED_REQUEST);
592 return; 608 return;
593 } 609 }
594 610
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
671 687
672 if (authenticator_->state() == Authenticator::MESSAGE_READY) { 688 if (authenticator_->state() == Authenticator::MESSAGE_READY) {
673 std::unique_ptr<JingleMessage> message(new JingleMessage( 689 std::unique_ptr<JingleMessage> message(new JingleMessage(
674 peer_address_, JingleMessage::SESSION_INFO, session_id_)); 690 peer_address_, JingleMessage::SESSION_INFO, session_id_));
675 message->info = authenticator_->GetNextMessage(); 691 message->info = authenticator_->GetNextMessage();
676 DCHECK(message->info.get()); 692 DCHECK(message->info.get());
677 SendMessage(std::move(message)); 693 SendMessage(std::move(message));
678 } 694 }
679 DCHECK_NE(authenticator_->state(), Authenticator::MESSAGE_READY); 695 DCHECK_NE(authenticator_->state(), Authenticator::MESSAGE_READY);
680 696
681 // The current JingleSession object can be destroyed by event_handler of 697 if (authenticator_->started()) {
682 // SetState(AUTHENTICATING) and cause subsequent dereferencing of the this 698 base::WeakPtr<JingleSession> self = weak_factory_.GetWeakPtr();
683 // pointer to crash. To protect against it, we run ContinueAuthenticationStep 699 SetState(AUTHENTICATING);
684 // asychronously using a weak pointer. 700 if (!self)
685 base::ThreadTaskRunnerHandle::Get()->PostTask( 701 return;
686 FROM_HERE, 702 }
687 base::Bind(&JingleSession::ContinueAuthenticationStep,
688 weak_factory_.GetWeakPtr()));
689 703
690 if (authenticator_->started()) {
691 SetState(AUTHENTICATING);
692 }
693 }
694
695 void JingleSession::ContinueAuthenticationStep() {
696 if (authenticator_->state() == Authenticator::ACCEPTED) { 704 if (authenticator_->state() == Authenticator::ACCEPTED) {
697 OnAuthenticated(); 705 OnAuthenticated();
698 } else if (authenticator_->state() == Authenticator::REJECTED) { 706 } else if (authenticator_->state() == Authenticator::REJECTED) {
699 Close(AuthRejectionReasonToErrorCode( 707 Close(AuthRejectionReasonToErrorCode(
700 authenticator_->rejection_reason())); 708 authenticator_->rejection_reason()));
701 } 709 }
702 } 710 }
703 711
704 void JingleSession::OnAuthenticated() { 712 void JingleSession::OnAuthenticated() {
705 transport_->Start(authenticator_.get(), 713 transport_->Start(authenticator_.get(),
706 base::Bind(&JingleSession::SendTransportInfo, 714 base::Bind(&JingleSession::SendTransportInfo,
707 weak_factory_.GetWeakPtr())); 715 weak_factory_.GetWeakPtr()));
708 716
717 base::WeakPtr<JingleSession> self = weak_factory_.GetWeakPtr();
718 std::vector<PendingMessage> messages_to_process;
719 std::swap(messages_to_process, pending_transport_info_);
720 for (auto& message : messages_to_process) {
721 message.reply_callback.Run(
722 transport_->ProcessTransportInfo(message.message->transport_info.get())
723 ? JingleMessageReply::NONE
724 : JingleMessageReply::BAD_REQUEST);
725 if (!self)
726 return;
727 }
728
709 SetState(AUTHENTICATED); 729 SetState(AUTHENTICATED);
710 } 730 }
711 731
712 void JingleSession::SetState(State new_state) { 732 void JingleSession::SetState(State new_state) {
713 DCHECK(thread_checker_.CalledOnValidThread()); 733 DCHECK(thread_checker_.CalledOnValidThread());
714 734
715 if (new_state != state_) { 735 if (new_state != state_) {
716 DCHECK_NE(state_, CLOSED); 736 DCHECK_NE(state_, CLOSED);
717 DCHECK_NE(state_, FAILED); 737 DCHECK_NE(state_, FAILED);
718 738
719 state_ = new_state; 739 state_ = new_state;
720 if (event_handler_) 740 if (event_handler_)
721 event_handler_->OnSessionStateChange(new_state); 741 event_handler_->OnSessionStateChange(new_state);
722 } 742 }
723 } 743 }
724 744
725 bool JingleSession::is_session_active() { 745 bool JingleSession::is_session_active() {
726 return state_ == CONNECTING || state_ == ACCEPTING || state_ == ACCEPTED || 746 return state_ == CONNECTING || state_ == ACCEPTING || state_ == ACCEPTED ||
727 state_ == AUTHENTICATING || state_ == AUTHENTICATED; 747 state_ == AUTHENTICATING || state_ == AUTHENTICATED;
728 } 748 }
729 749
730 std::string JingleSession::GetNextOutgoingId() { 750 std::string JingleSession::GetNextOutgoingId() {
731 return outgoing_id_prefix_ + "_" + base::IntToString(++next_outgoing_id_); 751 return outgoing_id_prefix_ + "_" + base::IntToString(++next_outgoing_id_);
732 } 752 }
733 753
734 } // namespace protocol 754 } // namespace protocol
735 } // namespace remoting 755 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/protocol/jingle_session.h ('k') | remoting/protocol/jingle_session_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698