OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |