diff options
author | sergeyu <sergeyu@chromium.org> | 2015-04-23 10:20:49 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-04-23 17:21:38 +0000 |
commit | 5a5854ee3e1c5760b422f26d31909bfb5dca631f (patch) | |
tree | a8a29175db6839ce5fe3326cb85931e857c78915 | |
parent | 8431e8f39edd5d7bff793f446035207fee6dacd1 (diff) | |
download | chromium_src-5a5854ee3e1c5760b422f26d31909bfb5dca631f.zip chromium_src-5a5854ee3e1c5760b422f26d31909bfb5dca631f.tar.gz chromium_src-5a5854ee3e1c5760b422f26d31909bfb5dca631f.tar.bz2 |
Use standard ICE in Chromoting.
Previously we were using legacy, non-standard version of ICE. This
change adds ICE version negotiation and enabled standard ICE by default,
when both peers support it.
BUG=473758
Review URL: https://codereview.chromium.org/1085703003
Cr-Commit-Position: refs/heads/master@{#326560}
27 files changed, 743 insertions, 327 deletions
diff --git a/remoting/client/jni/chromoting_jni_instance.cc b/remoting/client/jni/chromoting_jni_instance.cc index 33bd246..fd19dea 100644 --- a/remoting/client/jni/chromoting_jni_instance.cc +++ b/remoting/client/jni/chromoting_jni_instance.cc @@ -434,7 +434,8 @@ void ChromotingJniInstance::ConnectToHostOnNetworkThread() { scoped_ptr<protocol::TransportFactory> transport_factory( new protocol::LibjingleTransportFactory( - signaling_.get(), port_allocator.Pass(), network_settings)); + signaling_.get(), port_allocator.Pass(), network_settings, + protocol::TransportRole::CLIENT)); client_->Start(signaling_.get(), authenticator_.Pass(), transport_factory.Pass(), host_jid_, capabilities_); diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc index 262bbbd..9572bc4 100644 --- a/remoting/client/plugin/chromoting_instance.cc +++ b/remoting/client/plugin/chromoting_instance.cc @@ -712,10 +712,10 @@ void ChromotingInstance::HandleConnect(const base::DictionaryValue& data) { // Create TransportFactory. scoped_ptr<protocol::TransportFactory> transport_factory( new protocol::LibjingleTransportFactory( - signal_strategy_.get(), - PepperPortAllocator::Create(this).Pass(), + signal_strategy_.get(), PepperPortAllocator::Create(this).Pass(), protocol::NetworkSettings( - protocol::NetworkSettings::NAT_TRAVERSAL_FULL))); + protocol::NetworkSettings::NAT_TRAVERSAL_FULL), + protocol::TransportRole::CLIENT)); // Create Authenticator. scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher> diff --git a/remoting/host/chromoting_host.cc b/remoting/host/chromoting_host.cc index 346e887..57f0f9b 100644 --- a/remoting/host/chromoting_host.cc +++ b/remoting/host/chromoting_host.cc @@ -285,15 +285,17 @@ void ChromotingHost::OnIncomingSession( return; } - protocol::SessionConfig config; - if (!protocol_config_->Select(session->candidate_config(), &config)) { + scoped_ptr<protocol::SessionConfig> config = + protocol::SessionConfig::SelectCommon(session->candidate_config(), + protocol_config_.get()); + if (!config) { LOG(WARNING) << "Rejecting connection from " << session->jid() << " because no compatible configuration has been found."; *response = protocol::SessionManager::INCOMPATIBLE; return; } - session->set_config(config); + session->set_config(config.Pass()); *response = protocol::SessionManager::ACCEPT; diff --git a/remoting/host/chromoting_host_unittest.cc b/remoting/host/chromoting_host_unittest.cc index 19efc25..b7d6d65 100644 --- a/remoting/host/chromoting_host_unittest.cc +++ b/remoting/host/chromoting_host_unittest.cc @@ -108,9 +108,7 @@ class ChromotingHostTest : public testing::Test { session_jid1_ = "user@domain/rest-of-jid"; session_config2_ = SessionConfig::ForTest(); session_jid2_ = "user2@domain/rest-of-jid"; - session_unowned_config1_ = SessionConfig::ForTest(); session_unowned_jid1_ = "user3@doman/rest-of-jid"; - session_unowned_config2_ = SessionConfig::ForTest(); session_unowned_jid2_ = "user4@doman/rest-of-jid"; EXPECT_CALL(*session1_, jid()) @@ -132,9 +130,9 @@ class ChromotingHostTest : public testing::Test { .Times(AnyNumber()) .WillRepeatedly(SaveArg<0>(&session_unowned2_event_handler_)); EXPECT_CALL(*session1_, config()) - .WillRepeatedly(ReturnRef(session_config1_)); + .WillRepeatedly(ReturnRef(*session_config1_)); EXPECT_CALL(*session2_, config()) - .WillRepeatedly(ReturnRef(session_config2_)); + .WillRepeatedly(ReturnRef(*session_config2_)); owned_connection1_.reset(new MockConnectionToClient(session1_, &host_stub1_)); @@ -421,7 +419,7 @@ class ChromotingHostTest : public testing::Test { ClientSession* client1_; std::string session_jid1_; MockSession* session1_; // Owned by |connection_|. - SessionConfig session_config1_; + scoped_ptr<SessionConfig> session_config1_; MockVideoStub video_stub1_; MockClientStub client_stub1_; MockHostStub host_stub1_; @@ -430,15 +428,13 @@ class ChromotingHostTest : public testing::Test { ClientSession* client2_; std::string session_jid2_; MockSession* session2_; // Owned by |connection2_|. - SessionConfig session_config2_; + scoped_ptr<SessionConfig> session_config2_; MockVideoStub video_stub2_; MockClientStub client_stub2_; MockHostStub host_stub2_; scoped_ptr<MockSession> session_unowned1_; // Not owned by a connection. - SessionConfig session_unowned_config1_; std::string session_unowned_jid1_; scoped_ptr<MockSession> session_unowned2_; // Not owned by a connection. - SessionConfig session_unowned_config2_; std::string session_unowned_jid2_; protocol::Session::EventHandler* session_unowned1_event_handler_; protocol::Session::EventHandler* session_unowned2_event_handler_; @@ -599,7 +595,7 @@ TEST_F(ChromotingHostTest, IncomingSessionAccepted) { ExpectHostAndSessionManagerStart(); EXPECT_CALL(*session_unowned1_, candidate_config()).WillOnce(Return( default_candidate_config_.get())); - EXPECT_CALL(*session_unowned1_, set_config(_)); + EXPECT_CALL(*session_unowned1_, set_config_ptr(_)); EXPECT_CALL(*session_unowned1_, Close()).WillOnce(InvokeWithoutArgs( this, &ChromotingHostTest::NotifyConnectionClosed1)); EXPECT_CALL(host_status_observer_, OnAccessDenied(_)); @@ -620,7 +616,7 @@ TEST_F(ChromotingHostTest, LoginBackOffUponConnection) { ExpectHostAndSessionManagerStart(); EXPECT_CALL(*session_unowned1_, candidate_config()).WillOnce( Return(default_candidate_config_.get())); - EXPECT_CALL(*session_unowned1_, set_config(_)); + EXPECT_CALL(*session_unowned1_, set_config_ptr(_)); EXPECT_CALL(*session_unowned1_, Close()).WillOnce( InvokeWithoutArgs(this, &ChromotingHostTest::NotifyConnectionClosed1)); EXPECT_CALL(host_status_observer_, OnAccessDenied(_)); @@ -646,13 +642,13 @@ TEST_F(ChromotingHostTest, LoginBackOffUponAuthenticating) { Expectation start = ExpectHostAndSessionManagerStart(); EXPECT_CALL(*session_unowned1_, candidate_config()).WillOnce( Return(default_candidate_config_.get())); - EXPECT_CALL(*session_unowned1_, set_config(_)); + EXPECT_CALL(*session_unowned1_, set_config_ptr(_)); EXPECT_CALL(*session_unowned1_, Close()).WillOnce( InvokeWithoutArgs(this, &ChromotingHostTest::NotifyConnectionClosed1)); EXPECT_CALL(*session_unowned2_, candidate_config()).WillOnce( Return(default_candidate_config_.get())); - EXPECT_CALL(*session_unowned2_, set_config(_)); + EXPECT_CALL(*session_unowned2_, set_config_ptr(_)); EXPECT_CALL(*session_unowned2_, Close()).WillOnce( InvokeWithoutArgs(this, &ChromotingHostTest::NotifyConnectionClosed2)); diff --git a/remoting/host/client_session_unittest.cc b/remoting/host/client_session_unittest.cc index 5d94591..8af1e6c 100644 --- a/remoting/host/client_session_unittest.cc +++ b/remoting/host/client_session_unittest.cc @@ -178,7 +178,7 @@ class ClientSessionTest : public testing::Test { MockClientSessionEventHandler session_event_handler_; // Storage for values to be returned by the protocol::Session mock. - SessionConfig session_config_; + scoped_ptr<SessionConfig> session_config_; const std::string client_jid_; // Stubs returned to |client_session_| components by |connection_|. @@ -224,7 +224,7 @@ void ClientSessionTest::TearDown() { void ClientSessionTest::CreateClientSession() { // Mock protocol::Session APIs called directly by ClientSession. protocol::MockSession* session = new MockSession(); - EXPECT_CALL(*session, config()).WillRepeatedly(ReturnRef(session_config_)); + EXPECT_CALL(*session, config()).WillRepeatedly(ReturnRef(*session_config_)); EXPECT_CALL(*session, jid()).WillRepeatedly(ReturnRef(client_jid_)); EXPECT_CALL(*session, SetEventHandler(_)); diff --git a/remoting/host/session_manager_factory.cc b/remoting/host/session_manager_factory.cc index ad6ac6bb..996bbce 100644 --- a/remoting/host/session_manager_factory.cc +++ b/remoting/host/session_manager_factory.cc @@ -25,7 +25,8 @@ scoped_ptr<protocol::SessionManager> CreateHostSessionManager( scoped_ptr<protocol::TransportFactory> transport_factory( new protocol::LibjingleTransportFactory( - signal_strategy, port_allocator.Pass(), network_settings)); + signal_strategy, port_allocator.Pass(), network_settings, + protocol::TransportRole::SERVER)); scoped_ptr<protocol::JingleSessionManager> session_manager( new protocol::JingleSessionManager(transport_factory.Pass())); diff --git a/remoting/protocol/content_description.cc b/remoting/protocol/content_description.cc index 5d8aaac..a48c57b 100644 --- a/remoting/protocol/content_description.cc +++ b/remoting/protocol/content_description.cc @@ -25,6 +25,7 @@ const char kDefaultNs[] = ""; // Following constants are used to format session description in XML. const char kDescriptionTag[] = "description"; +const char kStandardIceTag[] = "standard-ice"; const char kControlTag[] = "control"; const char kEventTag[] = "event"; const char kVideoTag[] = "video"; @@ -121,17 +122,10 @@ ContentDescription::ContentDescription( ContentDescription::~ContentDescription() { } -ContentDescription* ContentDescription::Copy() const { - if (!candidate_config_.get() || !authenticator_message_.get()) { - return nullptr; - } - scoped_ptr<XmlElement> message(new XmlElement(*authenticator_message_)); - return new ContentDescription(candidate_config_->Clone(), message.Pass()); -} - // ToXml() creates content description for chromoting session. The // description looks as follows: // <description xmlns="google:remoting"> +// <standard-ice/> // <control transport="stream" version="1" /> // <event transport="datagram" version="1" /> // <video transport="stream" codec="vp8" version="1" /> @@ -145,27 +139,25 @@ XmlElement* ContentDescription::ToXml() const { XmlElement* root = new XmlElement( QName(kChromotingXmlNamespace, kDescriptionTag), true); - std::list<ChannelConfig>::const_iterator it; + if (config()->standard_ice()) { + root->AddElement( + new buzz::XmlElement(QName(kChromotingXmlNamespace, kStandardIceTag))); + } - for (it = config()->control_configs().begin(); - it != config()->control_configs().end(); ++it) { - root->AddElement(FormatChannelConfig(*it, kControlTag)); + for (const ChannelConfig& channel_config : config()->control_configs()) { + root->AddElement(FormatChannelConfig(channel_config, kControlTag)); } - for (it = config()->event_configs().begin(); - it != config()->event_configs().end(); ++it) { - root->AddElement(FormatChannelConfig(*it, kEventTag)); + for (const ChannelConfig& channel_config : config()->event_configs()) { + root->AddElement(FormatChannelConfig(channel_config, kEventTag)); } - for (it = config()->video_configs().begin(); - it != config()->video_configs().end(); ++it) { - root->AddElement(FormatChannelConfig(*it, kVideoTag)); + for (const ChannelConfig& channel_config : config()->video_configs()) { + root->AddElement(FormatChannelConfig(channel_config, kVideoTag)); } - for (it = config()->audio_configs().begin(); - it != config()->audio_configs().end(); ++it) { - ChannelConfig config = *it; - root->AddElement(FormatChannelConfig(config, kAudioTag)); + for (const ChannelConfig& channel_config : config()->audio_configs()) { + root->AddElement(FormatChannelConfig(channel_config, kAudioTag)); } // Older endpoints require an initial-resolution tag, but otherwise ignore it. @@ -192,7 +184,6 @@ bool ContentDescription::ParseChannelConfigs( bool codec_required, bool optional, std::list<ChannelConfig>* const configs) { - QName tag(kChromotingXmlNamespace, tag_name); const XmlElement* child = element->FirstNamed(tag); while (child) { @@ -218,6 +209,11 @@ scoped_ptr<ContentDescription> ContentDescription::ParseXml( } scoped_ptr<CandidateSessionConfig> config( CandidateSessionConfig::CreateEmpty()); + + config->set_standard_ice( + element->FirstNamed(QName(kChromotingXmlNamespace, kStandardIceTag)) != + nullptr); + if (!ParseChannelConfigs(element, kControlTag, false, false, config->mutable_control_configs()) || !ParseChannelConfigs(element, kEventTag, false, false, diff --git a/remoting/protocol/content_description.h b/remoting/protocol/content_description.h index 748b0f9..f12582f 100644 --- a/remoting/protocol/content_description.h +++ b/remoting/protocol/content_description.h @@ -10,7 +10,6 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "remoting/protocol/session_config.h" -#include "third_party/webrtc/p2p/base/sessiondescription.h" namespace buzz { class XmlElement; @@ -24,15 +23,13 @@ namespace protocol { // // This class also provides a type abstraction so that the Chromotocol Session // interface does not need to depend on libjingle. -class ContentDescription : public cricket::ContentDescription { +class ContentDescription { public: static const char kChromotingContentName[]; ContentDescription(scoped_ptr<CandidateSessionConfig> config, scoped_ptr<buzz::XmlElement> authenticator_message); - ~ContentDescription() override; - - ContentDescription* Copy() const override; + ~ContentDescription(); const CandidateSessionConfig* config() const { return candidate_config_.get(); diff --git a/remoting/protocol/fake_connection_to_host.cc b/remoting/protocol/fake_connection_to_host.cc index 025f720..6567d92 100644 --- a/remoting/protocol/fake_connection_to_host.cc +++ b/remoting/protocol/fake_connection_to_host.cc @@ -85,7 +85,7 @@ void FakeConnectionToHost::SignalConnectionReady(bool ready) { } const protocol::SessionConfig& FakeConnectionToHost::config() { - return session_config_; + return *session_config_; } protocol::ClipboardStub* FakeConnectionToHost::clipboard_forwarder() { diff --git a/remoting/protocol/fake_connection_to_host.h b/remoting/protocol/fake_connection_to_host.h index 8220a96..1c3fe40 100644 --- a/remoting/protocol/fake_connection_to_host.h +++ b/remoting/protocol/fake_connection_to_host.h @@ -54,7 +54,7 @@ class FakeConnectionToHost : public protocol::ConnectionToHost { testing::NiceMock<protocol::MockClipboardStub> mock_clipboard_stub_; testing::NiceMock<protocol::MockHostStub> mock_host_stub_; testing::NiceMock<protocol::MockInputStub> mock_input_stub_; - protocol::SessionConfig session_config_; + scoped_ptr<protocol::SessionConfig> session_config_; DISALLOW_COPY_AND_ASSIGN(FakeConnectionToHost); }; diff --git a/remoting/protocol/fake_session.cc b/remoting/protocol/fake_session.cc index ba6a5a9..68a78ca 100644 --- a/remoting/protocol/fake_session.cc +++ b/remoting/protocol/fake_session.cc @@ -36,11 +36,11 @@ const CandidateSessionConfig* FakeSession::candidate_config() { } const SessionConfig& FakeSession::config() { - return config_; + return *config_; } -void FakeSession::set_config(const SessionConfig& config) { - config_ = config; +void FakeSession::set_config(scoped_ptr<SessionConfig> config) { + config_ = config.Pass(); } StreamChannelFactory* FakeSession::GetTransportChannelFactory() { diff --git a/remoting/protocol/fake_session.h b/remoting/protocol/fake_session.h index 2e5d5ce..e8ea472 100644 --- a/remoting/protocol/fake_session.h +++ b/remoting/protocol/fake_session.h @@ -39,7 +39,7 @@ class FakeSession : public Session { const std::string& jid() override; const CandidateSessionConfig* candidate_config() override; const SessionConfig& config() override; - void set_config(const SessionConfig& config) override; + void set_config(scoped_ptr<SessionConfig> config) override; StreamChannelFactory* GetTransportChannelFactory() override; StreamChannelFactory* GetMultiplexedChannelFactory() override; void Close() override; @@ -47,7 +47,7 @@ class FakeSession : public Session { public: EventHandler* event_handler_; scoped_ptr<const CandidateSessionConfig> candidate_config_; - SessionConfig config_; + scoped_ptr<SessionConfig> config_; FakeStreamChannelFactory channel_factory_; diff --git a/remoting/protocol/jingle_messages.cc b/remoting/protocol/jingle_messages.cc index c2c9b80..7e4c21e 100644 --- a/remoting/protocol/jingle_messages.cc +++ b/remoting/protocol/jingle_messages.cc @@ -17,11 +17,16 @@ using buzz::XmlElement; namespace remoting { namespace protocol { +namespace { + const char kJabberNamespace[] = "jabber:client"; const char kJingleNamespace[] = "urn:xmpp:jingle:1"; -const char kP2PTransportNamespace[] = "http://www.google.com/transport/p2p"; -namespace { +// Namespace for transport messages for legacy GICE. +const char kGiceTransportNamespace[] = "http://www.google.com/transport/p2p"; + +// Namespace for transport messages when using standard ICE. +const char kIceTransportNamespace[] = "google:remoting:ice"; const char kEmptyNamespace[] = ""; const char kXmlNamespace[] = "http://www.w3.org/XML/1998/namespace"; @@ -45,9 +50,101 @@ const NameMapElement<JingleMessage::Reason> kReasons[] = { { JingleMessage::INCOMPATIBLE_PARAMETERS, "incompatible-parameters" }, }; -bool ParseCandidate(const buzz::XmlElement* element, - JingleMessage::NamedCandidate* candidate) { - DCHECK(element->Name() == QName(kP2PTransportNamespace, "candidate")); +bool ParseIceCredentials(const buzz::XmlElement* element, + JingleMessage::IceCredentials* credentials) { + DCHECK(element->Name() == QName(kIceTransportNamespace, "credentials")); + + const std::string& channel = element->Attr(QName(kEmptyNamespace, "channel")); + const std::string& ufrag = + element->Attr(QName(kEmptyNamespace, "ufrag")); + const std::string& password = + element->Attr(QName(kEmptyNamespace, "password")); + + if (channel.empty() || ufrag.empty() || password.empty()) { + return false; + } + + credentials->channel = channel; + credentials->ufrag = ufrag; + credentials->password = password; + + return true; +} + +bool ParseIceCandidate(const buzz::XmlElement* element, + JingleMessage::NamedCandidate* candidate) { + DCHECK(element->Name() == QName(kIceTransportNamespace, "candidate")); + + const std::string& name = element->Attr(QName(kEmptyNamespace, "name")); + const std::string& foundation = + element->Attr(QName(kEmptyNamespace, "foundation")); + const std::string& address = element->Attr(QName(kEmptyNamespace, "address")); + const std::string& port_str = element->Attr(QName(kEmptyNamespace, "port")); + const std::string& type = element->Attr(QName(kEmptyNamespace, "type")); + const std::string& protocol = + element->Attr(QName(kEmptyNamespace, "protocol")); + const std::string& priority_str = + element->Attr(QName(kEmptyNamespace, "priority")); + const std::string& generation_str = + element->Attr(QName(kEmptyNamespace, "generation")); + + int port; + unsigned priority; + int generation; + if (name.empty() || foundation.empty() || address.empty() || + !base::StringToInt(port_str, &port) || port < kPortMin || + port > kPortMax || type.empty() || protocol.empty() || + !base::StringToUint(priority_str, &priority) || + !base::StringToInt(generation_str, &generation)) { + return false; + } + + candidate->name = name; + + candidate->candidate.set_foundation(foundation); + candidate->candidate.set_address(rtc::SocketAddress(address, port)); + candidate->candidate.set_type(type); + candidate->candidate.set_protocol(protocol); + candidate->candidate.set_priority(priority); + candidate->candidate.set_generation(generation); + + return true; +} + +bool ParseIceTransportInfo( + const buzz::XmlElement* element, + std::list<JingleMessage::IceCredentials>* ice_credentials, + std::list<JingleMessage::NamedCandidate>* candidates) { + DCHECK(element->Name() == QName(kIceTransportNamespace, "transport")); + + ice_credentials->clear(); + candidates->clear(); + + QName qn_credentials(kIceTransportNamespace, "credentials"); + for (const XmlElement* credentials_tag = element->FirstNamed(qn_credentials); + credentials_tag; + credentials_tag = credentials_tag->NextNamed(qn_credentials)) { + JingleMessage::IceCredentials credentials; + if (!ParseIceCredentials(credentials_tag, &credentials)) + return false; + ice_credentials->push_back(credentials); + } + + QName qn_candidate(kIceTransportNamespace, "candidate"); + for (const XmlElement* candidate_tag = element->FirstNamed(qn_candidate); + candidate_tag; candidate_tag = candidate_tag->NextNamed(qn_candidate)) { + JingleMessage::NamedCandidate candidate; + if (!ParseIceCandidate(candidate_tag, &candidate)) + return false; + candidates->push_back(candidate); + } + + return true; +} + +bool ParseGiceCandidate(const buzz::XmlElement* element, + JingleMessage::NamedCandidate* candidate) { + DCHECK(element->Name() == QName(kGiceTransportNamespace, "candidate")); const std::string& name = element->Attr(QName(kEmptyNamespace, "name")); const std::string& address = element->Attr(QName(kEmptyNamespace, "address")); @@ -88,9 +185,59 @@ bool ParseCandidate(const buzz::XmlElement* element, return true; } -XmlElement* FormatCandidate(const JingleMessage::NamedCandidate& candidate) { +bool ParseGiceTransportInfo( + const buzz::XmlElement* element, + std::list<JingleMessage::NamedCandidate>* candidates) { + DCHECK(element->Name() == QName(kGiceTransportNamespace, "transport")); + + candidates->clear(); + + QName qn_candidate(kGiceTransportNamespace, "candidate"); + for (const XmlElement* candidate_tag = element->FirstNamed(qn_candidate); + candidate_tag; candidate_tag = candidate_tag->NextNamed(qn_candidate)) { + JingleMessage::NamedCandidate candidate; + if (!ParseGiceCandidate(candidate_tag, &candidate)) + return false; + candidates->push_back(candidate); + } + + return true; +} + +XmlElement* FormatIceCredentials( + const JingleMessage::IceCredentials& credentials) { + XmlElement* result = + new XmlElement(QName(kIceTransportNamespace, "credentials")); + result->SetAttr(QName(kEmptyNamespace, "channel"), credentials.channel); + result->SetAttr(QName(kEmptyNamespace, "ufrag"), credentials.ufrag); + result->SetAttr(QName(kEmptyNamespace, "password"), credentials.password); + return result; +} + +XmlElement* FormatIceCandidate(const JingleMessage::NamedCandidate& candidate) { + XmlElement* result = + new XmlElement(QName(kIceTransportNamespace, "candidate")); + result->SetAttr(QName(kEmptyNamespace, "name"), candidate.name); + result->SetAttr(QName(kEmptyNamespace, "foundation"), + candidate.candidate.foundation()); + result->SetAttr(QName(kEmptyNamespace, "address"), + candidate.candidate.address().ipaddr().ToString()); + result->SetAttr(QName(kEmptyNamespace, "port"), + base::IntToString(candidate.candidate.address().port())); + result->SetAttr(QName(kEmptyNamespace, "type"), candidate.candidate.type()); + result->SetAttr(QName(kEmptyNamespace, "protocol"), + candidate.candidate.protocol()); + result->SetAttr(QName(kEmptyNamespace, "priority"), + base::DoubleToString(candidate.candidate.priority())); + result->SetAttr(QName(kEmptyNamespace, "generation"), + base::IntToString(candidate.candidate.generation())); + return result; +} + +XmlElement* FormatGiceCandidate( + const JingleMessage::NamedCandidate& candidate) { XmlElement* result = - new XmlElement(QName(kP2PTransportNamespace, "candidate")); + new XmlElement(QName(kGiceTransportNamespace, "candidate")); result->SetAttr(QName(kEmptyNamespace, "name"), candidate.name); result->SetAttr(QName(kEmptyNamespace, "address"), candidate.candidate.address().ipaddr().ToString()); @@ -112,9 +259,6 @@ XmlElement* FormatCandidate(const JingleMessage::NamedCandidate& candidate) { } // namespace -JingleMessage::NamedCandidate::NamedCandidate() { -} - JingleMessage::NamedCandidate::NamedCandidate( const std::string& name, const cricket::Candidate& candidate) @@ -122,6 +266,12 @@ JingleMessage::NamedCandidate::NamedCandidate( candidate(candidate) { } +JingleMessage::IceCredentials::IceCredentials(std::string channel, + std::string ufrag, + std::string password) + : channel(channel), ufrag(ufrag), password(password) { +} + // static bool JingleMessage::IsJingleMessage(const buzz::XmlElement* stanza) { return stanza->Name() == QName(kJabberNamespace, "iq") && @@ -134,19 +284,13 @@ std::string JingleMessage::GetActionName(ActionType action) { return ValueToName(kActionTypes, action); } -JingleMessage::JingleMessage() - : action(UNKNOWN_ACTION), - reason(UNKNOWN_REASON) { +JingleMessage::JingleMessage() { } -JingleMessage::JingleMessage( - const std::string& to_value, - ActionType action_value, - const std::string& sid_value) - : to(to_value), - action(action_value), - sid(sid_value), - reason(UNKNOWN_REASON) { +JingleMessage::JingleMessage(const std::string& to, + ActionType action, + const std::string& sid) + : to(to), action(action), sid(sid) { } JingleMessage::~JingleMessage() { @@ -240,21 +384,26 @@ bool JingleMessage::ParseXml(const buzz::XmlElement* stanza, } } - candidates.clear(); - const XmlElement* transport_tag = content_tag->FirstNamed( - QName(kP2PTransportNamespace, "transport")); - if (transport_tag) { - QName qn_candidate(kP2PTransportNamespace, "candidate"); - for (const XmlElement* candidate_tag = - transport_tag->FirstNamed(qn_candidate); - candidate_tag != nullptr; - candidate_tag = candidate_tag->NextNamed(qn_candidate)) { - NamedCandidate candidate; - if (!ParseCandidate(candidate_tag, &candidate)) { - *error = "Failed to parse candidates"; - return false; - } - candidates.push_back(candidate); + const XmlElement* ice_transport_tag = content_tag->FirstNamed( + QName(kIceTransportNamespace, "transport")); + const XmlElement* gice_transport_tag = content_tag->FirstNamed( + QName(kGiceTransportNamespace, "transport")); + if (ice_transport_tag && gice_transport_tag) { + *error = "ICE and GICE transport information is found in the same message"; + return false; + } else if (ice_transport_tag) { + standard_ice = true; + if (!ParseIceTransportInfo(ice_transport_tag, &ice_credentials, + &candidates)) { + *error = "Failed to parse transport info"; + return false; + } + } else if (gice_transport_tag) { + standard_ice = false; + ice_credentials.clear(); + if (!ParseGiceTransportInfo(gice_transport_tag, &candidates)) { + *error = "Failed to parse transport info"; + return false; } } @@ -313,12 +462,27 @@ scoped_ptr<buzz::XmlElement> JingleMessage::ToXml() const { if (description.get()) content_tag->AddElement(description->ToXml()); - XmlElement* transport_tag = - new XmlElement(QName(kP2PTransportNamespace, "transport"), true); - content_tag->AddElement(transport_tag); - for (std::list<NamedCandidate>::const_iterator it = candidates.begin(); - it != candidates.end(); ++it) { - transport_tag->AddElement(FormatCandidate(*it)); + if (standard_ice) { + XmlElement* transport_tag = + new XmlElement(QName(kIceTransportNamespace, "transport"), true); + content_tag->AddElement(transport_tag); + for (std::list<IceCredentials>::const_iterator it = + ice_credentials.begin(); + it != ice_credentials.end(); ++it) { + transport_tag->AddElement(FormatIceCredentials(*it)); + } + for (std::list<NamedCandidate>::const_iterator it = candidates.begin(); + it != candidates.end(); ++it) { + transport_tag->AddElement(FormatIceCandidate(*it)); + } + } else { + XmlElement* transport_tag = + new XmlElement(QName(kGiceTransportNamespace, "transport"), true); + content_tag->AddElement(transport_tag); + for (std::list<NamedCandidate>::const_iterator it = candidates.begin(); + it != candidates.end(); ++it) { + transport_tag->AddElement(FormatGiceCandidate(*it)); + } } } diff --git a/remoting/protocol/jingle_messages.h b/remoting/protocol/jingle_messages.h index e12c854..c83776a 100644 --- a/remoting/protocol/jingle_messages.h +++ b/remoting/protocol/jingle_messages.h @@ -12,16 +12,11 @@ #include "third_party/webrtc/libjingle/xmllite/xmlelement.h" #include "third_party/webrtc/p2p/base/candidate.h" - namespace remoting { namespace protocol { class ContentDescription; -extern const char kJabberNamespace[]; -extern const char kJingleNamespace[]; -extern const char kP2PTransportNamespace[]; - struct JingleMessage { enum ActionType { UNKNOWN_ACTION, @@ -42,7 +37,7 @@ struct JingleMessage { }; struct NamedCandidate { - NamedCandidate(); + NamedCandidate() = default; NamedCandidate(const std::string& name, const cricket::Candidate& candidate); @@ -50,6 +45,17 @@ struct JingleMessage { cricket::Candidate candidate; }; + struct IceCredentials { + IceCredentials() = default; + IceCredentials(std::string channel, + std::string ufrag, + std::string password); + + std::string channel; + std::string ufrag; + std::string password; + }; + JingleMessage(); JingleMessage(const std::string& to_value, ActionType action_value, @@ -68,12 +74,15 @@ struct JingleMessage { std::string from; std::string to; - ActionType action; + ActionType action = UNKNOWN_ACTION; std::string sid; std::string initiator; scoped_ptr<ContentDescription> description; + + bool standard_ice = true; + std::list<IceCredentials> ice_credentials; std::list<NamedCandidate> candidates; // Content of session-info messages. @@ -82,7 +91,7 @@ struct JingleMessage { // Value from the <reason> tag if it is present in the // message. Useful mainly for session-terminate messages, but Jingle // spec allows it in any message. - Reason reason; + Reason reason = UNKNOWN_REASON; }; struct JingleMessageReply { diff --git a/remoting/protocol/jingle_messages_unittest.cc b/remoting/protocol/jingle_messages_unittest.cc index de58443..aa95d07 100644 --- a/remoting/protocol/jingle_messages_unittest.cc +++ b/remoting/protocol/jingle_messages_unittest.cc @@ -105,6 +105,7 @@ TEST(JingleMessageTest, SessionInitiate) { "initiator='user@gmail.com/chromiumsy5C6A652D'>" "<content name='chromoting' creator='initiator'>" "<description xmlns='google:remoting'>" + "<standard-ice/>" "<control transport='stream' version='2'/>" "<event transport='stream' version='2'/>" "<video transport='stream' version='2' codec='vp8'/>" @@ -145,6 +146,7 @@ TEST(JingleMessageTest, SessionAccept) { "xmlns='urn:xmpp:jingle:1'>i" "<content creator='initiator' name='chromoting'>" "<description xmlns='google:remoting'>" + "<standard-ice/>" "<control transport='stream' version='2'/>" "<event transport='stream' version='2'/>" "<video codec='vp8' transport='stream' version='2'/>" @@ -177,23 +179,112 @@ TEST(JingleMessageTest, SessionAccept) { << error; } -TEST(JingleMessageTest, TransportInfo) { - const char* kTestTransportInfoMessage = +TEST(JingleMessageTest, SessionAcceptNoIce) { + const char* kTestSessionAcceptMessage = + "<cli:iq from='user@gmail.com/chromoting016DBB07' " + "to='user@gmail.com/chromiumsy5C6A652D' type='set' " + "xmlns:cli='jabber:client'>" + "<jingle action='session-accept' sid='2227053353' " + "xmlns='urn:xmpp:jingle:1'>i" + "<content creator='initiator' name='chromoting'>" + "<description xmlns='google:remoting'>" + "<control transport='stream' version='2'/>" + "<event transport='stream' version='2'/>" + "<video codec='vp8' transport='stream' version='2'/>" + "<audio transport='stream' version='2' codec='verbatim'/>" + "<initial-resolution height='480' width='640'/>" + "<authentication><certificate>" + "MIICpjCCAY6gW0Cert0TANBgkqhkiG9w0BAQUFA=" + "</certificate></authentication>" + "</description>" + "<transport xmlns='http://www.google.com/transport/p2p'/>" + "</content>" + "</jingle>" + "</cli:iq>"; + + scoped_ptr<XmlElement> source_message( + XmlElement::ForStr(kTestSessionAcceptMessage)); + ASSERT_TRUE(source_message.get()); + + EXPECT_TRUE(JingleMessage::IsJingleMessage(source_message.get())); + + JingleMessage message; + std::string error; + EXPECT_TRUE(message.ParseXml(source_message.get(), &error)) << error; + + EXPECT_EQ(message.action, JingleMessage::SESSION_ACCEPT); + + scoped_ptr<XmlElement> formatted_message(message.ToXml()); + ASSERT_TRUE(formatted_message.get()); + EXPECT_TRUE(VerifyXml(source_message.get(), formatted_message.get(), &error)) + << error; +} + +TEST(JingleMessageTest, IceTransportInfo) { + const char* kTestIceTransportInfoMessage = + "<cli:iq to='user@gmail.com/chromoting016DBB07' type='set' " + "xmlns:cli='jabber:client'>" + "<jingle xmlns='urn:xmpp:jingle:1' action='transport-info' " + "sid='2227053353'>" + "<content name='chromoting' creator='initiator'>" + "<transport xmlns='google:remoting:ice'>" + "<credentials channel='event' ufrag='tPUyEAmQrEw3y7hi' " + "password='2iRdhLfawKZC5ydJ'/>" + "<credentials channel='video' ufrag='EPK3CXo5sTLJSez0' " + "password='eM0VUfUkZ+1Pyi0M'/>" + "<candidate name='event' foundation='725747215' " + "address='172.23.164.186' port='59089' type='local' " + "protocol='udp' priority='2122194688' generation='0'/>" + "<candidate name='video' foundation='3623806809' " + "address='172.23.164.186' port='57040' type='local' " + "protocol='udp' priority='2122194688' generation='0'/>" + "</transport>" + "</content>" + "</jingle>" + "</cli:iq>"; + + scoped_ptr<XmlElement> source_message( + XmlElement::ForStr(kTestIceTransportInfoMessage)); + ASSERT_TRUE(source_message.get()); + + EXPECT_TRUE(JingleMessage::IsJingleMessage(source_message.get())); + + JingleMessage message; + std::string error; + EXPECT_TRUE(message.ParseXml(source_message.get(), &error)) << error; + + EXPECT_EQ(message.action, JingleMessage::TRANSPORT_INFO); + EXPECT_EQ(message.candidates.size(), 2U); + + scoped_ptr<XmlElement> formatted_message(message.ToXml()); + ASSERT_TRUE(formatted_message.get()); + EXPECT_TRUE(VerifyXml(source_message.get(), formatted_message.get(), &error)) + << error; +} + +TEST(JingleMessageTest, GiceTransportInfo) { + const char* kTestGiceTransportInfoMessage = "<cli:iq to='user@gmail.com/chromoting016DBB07' type='set' " - "xmlns:cli='jabber:client'><jingle xmlns='urn:xmpp:jingle:1' " - "action='transport-info' sid='2227053353'><content name='chromoting' " - "creator='initiator'><transport " - "xmlns='http://www.google.com/transport/p2p'><candidate name='event' " - "address='172.23.164.186' port='57040' preference='1' " - "username='tPUyEAmQrEw3y7hi' protocol='udp' generation='0' " - "password='2iRdhLfawKZC5ydJ' type='local'/><candidate name='video' " - "address='172.23.164.186' port='42171' preference='1' " - "username='EPK3CXo5sTLJSez0' protocol='udp' generation='0' " - "password='eM0VUfUkZ+1Pyi0M' type='local'/></transport></content>" - "</jingle></cli:iq>"; + "xmlns:cli='jabber:client'>" + "<jingle xmlns='urn:xmpp:jingle:1' action='transport-info' " + "sid='2227053353'>" + "<content name='chromoting' creator='initiator'>" + "<transport xmlns='http://www.google.com/transport/p2p'>" + "<candidate name='event' address='172.23.164.186' port='57040' " + "preference='1' username='tPUyEAmQrEw3y7hi' " + "protocol='udp' generation='0' " + "password='2iRdhLfawKZC5ydJ' type='local'/>" + "<candidate name='video' address='172.23.164.186' port='42171' " + "preference='1' username='EPK3CXo5sTLJSez0' " + "protocol='udp' generation='0' " + "password='eM0VUfUkZ+1Pyi0M' type='local'/>" + "</transport>" + "</content>" + "</jingle>" + "</cli:iq>"; scoped_ptr<XmlElement> source_message( - XmlElement::ForStr(kTestTransportInfoMessage)); + XmlElement::ForStr(kTestGiceTransportInfoMessage)); ASSERT_TRUE(source_message.get()); EXPECT_TRUE(JingleMessage::IsJingleMessage(source_message.get())); diff --git a/remoting/protocol/jingle_session.cc b/remoting/protocol/jingle_session.cc index edc48ee..0f4f0a2 100644 --- a/remoting/protocol/jingle_session.cc +++ b/remoting/protocol/jingle_session.cc @@ -32,12 +32,11 @@ namespace remoting { namespace protocol { namespace { -// Delay after candidate creation before sending transport-info -// message. This is neccessary to be able to pack multiple candidates -// into one transport-info messages. The value needs to be greater -// than zero because ports are opened asynchronously in the browser -// process. -const int kTransportInfoSendDelayMs = 2; + +// Delay after candidate creation before sending transport-info message to +// accumulate multiple candidates. This is an optimization to reduce number of +// transport-info messages. +const int kTransportInfoSendDelayMs = 20; // How long we should wait for a response from the other end. This value is used // for all requests except |transport-info|. @@ -74,7 +73,6 @@ JingleSession::JingleSession(JingleSessionManager* session_manager) event_handler_(nullptr), state_(INITIALIZING), error_(OK), - config_is_set_(false), weak_factory_(this) { } @@ -149,7 +147,7 @@ void JingleSession::InitializeIncomingConnection( void JingleSession::AcceptIncomingConnection( const JingleMessage& initiate_message) { - DCHECK(config_is_set_); + DCHECK(config_); // Process the first authentication message. const buzz::XmlElement* first_auth_message = @@ -184,7 +182,7 @@ void JingleSession::ContinueAcceptIncomingConnection() { auth_message = authenticator_->GetNextMessage(); message.description.reset( - new ContentDescription(CandidateSessionConfig::CreateFrom(config_), + new ContentDescription(CandidateSessionConfig::CreateFrom(*config_), auth_message.Pass())); SendMessage(message); @@ -213,14 +211,13 @@ const CandidateSessionConfig* JingleSession::candidate_config() { const SessionConfig& JingleSession::config() { DCHECK(CalledOnValidThread()); - return config_; + return *config_; } -void JingleSession::set_config(const SessionConfig& config) { +void JingleSession::set_config(scoped_ptr<SessionConfig> config) { DCHECK(CalledOnValidThread()); - DCHECK(!config_is_set_); - config_ = config; - config_is_set_ = true; + DCHECK(!config_); + config_ = config.Pass(); } StreamChannelFactory* JingleSession::GetTransportChannelFactory() { @@ -243,16 +240,26 @@ void JingleSession::Close() { CloseInternal(OK); } -void JingleSession::AddPendingRemoteCandidates(Transport* channel, - const std::string& name) { - std::list<JingleMessage::NamedCandidate>::iterator it = +void JingleSession::AddPendingRemoteTransportInfo(Transport* channel) { + std::list<JingleMessage::IceCredentials>::iterator credentials = + pending_remote_ice_credentials_.begin(); + while (credentials != pending_remote_ice_credentials_.end()) { + if (credentials->channel == channel->name()) { + channel->SetRemoteCredentials(credentials->ufrag, credentials->password); + credentials = pending_remote_ice_credentials_.erase(credentials); + } else { + ++credentials; + } + } + + std::list<JingleMessage::NamedCandidate>::iterator candidate = pending_remote_candidates_.begin(); - while(it != pending_remote_candidates_.end()) { - if (it->name == name) { - channel->AddRemoteCandidate(it->candidate); - it = pending_remote_candidates_.erase(it); + while (candidate != pending_remote_candidates_.end()) { + if (candidate->name == channel->name()) { + channel->AddRemoteCandidate(candidate->candidate); + candidate = pending_remote_candidates_.erase(candidate); } else { - ++it; + ++candidate; } } } @@ -263,8 +270,9 @@ void JingleSession::CreateChannel(const std::string& name, scoped_ptr<Transport> channel = session_manager_->transport_factory_->CreateTransport(); + channel->SetUseStandardIce(config_->standard_ice()); channel->Connect(name, this, callback); - AddPendingRemoteCandidates(channel.get(), name); + AddPendingRemoteTransportInfo(channel.get()); channels_[name] = channel.release(); } @@ -277,18 +285,19 @@ void JingleSession::CancelChannelCreation(const std::string& name) { } } +void JingleSession::OnTransportIceCredentials(Transport* transport, + const std::string& ufrag, + const std::string& password) { + EnsurePendingTransportInfoMessage(); + pending_transport_info_message_->ice_credentials.push_back( + JingleMessage::IceCredentials(transport->name(), ufrag, password)); +} + void JingleSession::OnTransportCandidate(Transport* transport, const cricket::Candidate& candidate) { - pending_candidates_.push_back(JingleMessage::NamedCandidate( - transport->name(), candidate)); - - if (!transport_infos_timer_.IsRunning()) { - // Delay sending the new candidates in case we get more candidates - // that we can send in one message. - transport_infos_timer_.Start( - FROM_HERE, base::TimeDelta::FromMilliseconds(kTransportInfoSendDelayMs), - this, &JingleSession::SendTransportInfo); - } + EnsurePendingTransportInfoMessage(); + pending_transport_info_message_->candidates.push_back( + JingleMessage::NamedCandidate(transport->name(), candidate)); } void JingleSession::OnTransportRouteChange(Transport* transport, @@ -362,14 +371,33 @@ void JingleSession::OnMessageResponse( } } +void JingleSession::EnsurePendingTransportInfoMessage() { + // |transport_info_timer_| must be running iff + // |pending_transport_info_message_| exists. + DCHECK_EQ(pending_transport_info_message_ != nullptr, + transport_info_timer_.IsRunning()); + + if (!pending_transport_info_message_) { + pending_transport_info_message_.reset(new JingleMessage( + peer_jid_, JingleMessage::TRANSPORT_INFO, session_id_)); + pending_transport_info_message_->standard_ice = config_->standard_ice(); + + // Delay sending the new candidates in case we get more candidates + // that we can send in one message. + transport_info_timer_.Start( + FROM_HERE, base::TimeDelta::FromMilliseconds(kTransportInfoSendDelayMs), + this, &JingleSession::SendTransportInfo); + } +} + void JingleSession::SendTransportInfo() { - JingleMessage message(peer_jid_, JingleMessage::TRANSPORT_INFO, session_id_); - message.candidates.swap(pending_candidates_); + DCHECK(pending_transport_info_message_); scoped_ptr<IqRequest> request = session_manager_->iq_sender()->SendIq( - message.ToXml(), + pending_transport_info_message_->ToXml(), base::Bind(&JingleSession::OnTransportInfoResponse, base::Unretained(this))); + pending_transport_info_message_.reset(); if (request) { request->SetTimeout(base::TimeDelta::FromSeconds(kTransportInfoTimeout)); transport_info_requests_.push_back(request.release()); @@ -463,9 +491,6 @@ void JingleSession::OnAccept(const JingleMessage& message, return; } - // In case there is transport information in the accept message. - ProcessTransportInfo(message); - SetState(CONNECTED); DCHECK(authenticator_->state() == Authenticator::WAITING_MESSAGE); @@ -497,6 +522,27 @@ void JingleSession::OnSessionInfo(const JingleMessage& message, } void JingleSession::ProcessTransportInfo(const JingleMessage& message) { + // Check if the transport information version matches what was negotiated. + if (message.standard_ice != config_->standard_ice()) { + LOG(ERROR) << "Received transport-info message in format different from " + "negotiated."; + CloseInternal(INCOMPATIBLE_PROTOCOL); + return; + } + + for (std::list<JingleMessage::IceCredentials>::const_iterator it = + message.ice_credentials.begin(); + it != message.ice_credentials.end(); ++it) { + ChannelsMap::iterator channel = channels_.find(it->channel); + if (channel != channels_.end()) { + channel->second->SetRemoteCredentials(it->ufrag, it->password); + } else { + // Transport info was received before the channel was created. + // This could happen due to messages being reordered on the wire. + pending_remote_ice_credentials_.push_back(*it); + } + } + for (std::list<JingleMessage::NamedCandidate>::const_iterator it = message.candidates.begin(); it != message.candidates.end(); ++it) { @@ -555,12 +601,12 @@ void JingleSession::OnTerminate(const JingleMessage& message, bool JingleSession::InitializeConfigFromDescription( const ContentDescription* description) { DCHECK(description); - - if (!description->config()->GetFinalConfig(&config_)) { + config_ = SessionConfig::GetFinalConfig(description->config()); + if (!config_) { LOG(ERROR) << "session-accept does not specify configuration"; return false; } - if (!candidate_config()->IsSupported(config_)) { + if (!candidate_config()->IsSupported(*config_)) { LOG(ERROR) << "session-accept specifies an invalid configuration"; return false; } diff --git a/remoting/protocol/jingle_session.h b/remoting/protocol/jingle_session.h index eb30e50..584aeae 100644 --- a/remoting/protocol/jingle_session.h +++ b/remoting/protocol/jingle_session.h @@ -51,7 +51,7 @@ class JingleSession : public base::NonThreadSafe, const std::string& jid() override; const CandidateSessionConfig* candidate_config() override; const SessionConfig& config() override; - void set_config(const SessionConfig& config) override; + void set_config(scoped_ptr<SessionConfig> config) override; StreamChannelFactory* GetTransportChannelFactory() override; StreamChannelFactory* GetMultiplexedChannelFactory() override; void Close() override; @@ -62,6 +62,9 @@ class JingleSession : public base::NonThreadSafe, void CancelChannelCreation(const std::string& name) override; // Transport::EventHandler interface. + void OnTransportIceCredentials(Transport* transport, + const std::string& ufrag, + const std::string& password) override; void OnTransportCandidate(Transport* transport, const cricket::Candidate& candidate) override; void OnTransportRouteChange(Transport* transport, @@ -82,8 +85,9 @@ class JingleSession : public base::NonThreadSafe, scoped_ptr<Authenticator> authenticator, scoped_ptr<CandidateSessionConfig> config); - // Adds to a new channel the remote candidates received before it was created. - void AddPendingRemoteCandidates(Transport* channel, const std::string& name); + // Passes transport info to a new |channel| in case it was received before the + // channel was created. + void AddPendingRemoteTransportInfo(Transport* channel); // Called by JingleSessionManager for incoming connections. void InitializeIncomingConnection(const JingleMessage& initiate_message, @@ -100,6 +104,10 @@ class JingleSession : public base::NonThreadSafe, IqRequest* request, const buzz::XmlElement* response); + // Creates empty |pending_transport_info_message_| and schedules timer for + // SentTransportInfo() to sent the message later. + void EnsurePendingTransportInfoMessage(); + // Sends transport-info message with candidates from |pending_candidates_|. void SendTransportInfo(); @@ -158,8 +166,7 @@ class JingleSession : public base::NonThreadSafe, State state_; ErrorCode error_; - SessionConfig config_; - bool config_is_set_; + scoped_ptr<SessionConfig> config_; scoped_ptr<Authenticator> authenticator_; @@ -174,10 +181,12 @@ class JingleSession : public base::NonThreadSafe, scoped_ptr<SecureChannelFactory> secure_channel_factory_; scoped_ptr<ChannelMultiplexer> channel_multiplexer_; - base::OneShotTimer<JingleSession> transport_infos_timer_; - std::list<JingleMessage::NamedCandidate> pending_candidates_; + scoped_ptr<JingleMessage> pending_transport_info_message_; + base::OneShotTimer<JingleSession> transport_info_timer_; - // Pending remote candidates, received before the local channels were created. + // Pending remote transport info received before the local channels were + // created. + std::list<JingleMessage::IceCredentials> pending_remote_ice_credentials_; std::list<JingleMessage::NamedCandidate> pending_remote_candidates_; base::WeakPtrFactory<JingleSession> weak_factory_; diff --git a/remoting/protocol/jingle_session_unittest.cc b/remoting/protocol/jingle_session_unittest.cc index 9ec24b9..9eb829d 100644 --- a/remoting/protocol/jingle_session_unittest.cc +++ b/remoting/protocol/jingle_session_unittest.cc @@ -105,7 +105,8 @@ class JingleSessionTest : public testing::Test { host_session_.reset(session); host_session_->SetEventHandler(&host_session_event_handler_); - session->set_config(SessionConfig::ForTest()); + session->set_config(standard_ice_ ? SessionConfig::ForTest() + : SessionConfig::WithLegacyIceForTest()); } void DeleteSession() { @@ -153,7 +154,7 @@ class JingleSessionTest : public testing::Test { scoped_ptr<TransportFactory> host_transport(new LibjingleTransportFactory( nullptr, ChromiumPortAllocator::Create(nullptr, network_settings).Pass(), - network_settings)); + network_settings, TransportRole::SERVER)); host_server_.reset(new JingleSessionManager(host_transport.Pass())); host_server_->Init(host_signal_strategy_.get(), &host_server_listener_); @@ -167,7 +168,7 @@ class JingleSessionTest : public testing::Test { scoped_ptr<TransportFactory> client_transport(new LibjingleTransportFactory( nullptr, ChromiumPortAllocator::Create(nullptr, network_settings).Pass(), - network_settings)); + network_settings, TransportRole::CLIENT)); client_server_.reset( new JingleSessionManager(client_transport.Pass())); client_server_->Init(client_signal_strategy_.get(), @@ -290,6 +291,8 @@ class JingleSessionTest : public testing::Test { scoped_ptr<base::MessageLoopForIO> message_loop_; + bool standard_ice_ = true; + scoped_ptr<FakeSignalStrategy> host_signal_strategy_; scoped_ptr<FakeSignalStrategy> client_signal_strategy_; @@ -352,7 +355,7 @@ TEST_F(JingleSessionTest, Connect) { const buzz::XmlElement* initiate_xml = host_signal_strategy_->received_messages().front(); const buzz::XmlElement* jingle_element = - initiate_xml->FirstNamed(buzz::QName(kJingleNamespace, "jingle")); + initiate_xml->FirstNamed(buzz::QName("urn:xmpp:jingle:1", "jingle")); ASSERT_TRUE(jingle_element); ASSERT_EQ(kClientJid, jingle_element->Attr(buzz::QName(std::string(), "initiator"))); @@ -391,6 +394,23 @@ TEST_F(JingleSessionTest, TestStreamChannel) { tester.CheckResults(); } +// Verify that we can still connect using legacy GICE transport. +TEST_F(JingleSessionTest, TestLegacyIceConnection) { + standard_ice_ = false; + + CreateSessionManagers(1, FakeAuthenticator::ACCEPT); + ASSERT_NO_FATAL_FAILURE( + InitiateConnection(1, FakeAuthenticator::ACCEPT, false)); + + ASSERT_NO_FATAL_FAILURE(CreateChannel()); + + StreamConnectionTester tester(host_socket_.get(), client_socket_.get(), + kMessageSize, kMessages); + tester.Start(); + message_loop_->Run(); + tester.CheckResults(); +} + TEST_F(JingleSessionTest, DeleteSessionOnIncomingConnection) { CreateSessionManagers(3, FakeAuthenticator::ACCEPT); diff --git a/remoting/protocol/libjingle_transport_factory.cc b/remoting/protocol/libjingle_transport_factory.cc index 151d329..b442a02 100644 --- a/remoting/protocol/libjingle_transport_factory.cc +++ b/remoting/protocol/libjingle_transport_factory.cc @@ -57,7 +57,8 @@ class LibjingleTransport public sigslot::has_slots<> { public: LibjingleTransport(cricket::PortAllocator* port_allocator, - const NetworkSettings& network_settings); + const NetworkSettings& network_settings, + TransportRole role); ~LibjingleTransport() override; // Called by JingleTransportFactory when it has fresh Jingle info. @@ -67,9 +68,12 @@ class LibjingleTransport void Connect(const std::string& name, Transport::EventHandler* event_handler, const Transport::ConnectedCallback& callback) override; + void SetRemoteCredentials(const std::string& ufrag, + const std::string& password) override; void AddRemoteCandidate(const cricket::Candidate& candidate) override; const std::string& name() const override; bool is_connected() const override; + void SetUseStandardIce(bool use_standard_ice) override; private: void DoStart(); @@ -94,15 +98,19 @@ class LibjingleTransport cricket::PortAllocator* port_allocator_; NetworkSettings network_settings_; + TransportRole role_; + + bool use_standard_ice_ = true; std::string name_; EventHandler* event_handler_; Transport::ConnectedCallback callback_; std::string ice_username_fragment_; - std::string ice_password_; bool can_start_; + std::string remote_ice_username_fragment_; + std::string remote_ice_password_; std::list<cricket::Candidate> pending_candidates_; scoped_ptr<cricket::P2PTransportChannel> channel_; int connect_attempts_left_; @@ -114,18 +122,18 @@ class LibjingleTransport }; LibjingleTransport::LibjingleTransport(cricket::PortAllocator* port_allocator, - const NetworkSettings& network_settings) + const NetworkSettings& network_settings, + TransportRole role) : port_allocator_(port_allocator), network_settings_(network_settings), + role_(role), event_handler_(nullptr), ice_username_fragment_( rtc::CreateRandomString(cricket::ICE_UFRAG_LENGTH)), - ice_password_(rtc::CreateRandomString(cricket::ICE_PWD_LENGTH)), can_start_(false), connect_attempts_left_(kMaxReconnectAttempts), weak_factory_(this) { DCHECK(!ice_username_fragment_.empty()); - DCHECK(!ice_password_.empty()); } LibjingleTransport::~LibjingleTransport() { @@ -149,9 +157,17 @@ void LibjingleTransport::OnCanStart() { if (!callback_.is_null()) DoStart(); + // Pass pending ICE credentials and candidates to the channel. + if (!remote_ice_username_fragment_.empty()) { + channel_->SetRemoteIceCredentials(remote_ice_username_fragment_, + remote_ice_password_); + } + while (!pending_candidates_.empty()) { - channel_->SetRemoteIceCredentials(pending_candidates_.front().username(), - pending_candidates_.front().password()); + if (!use_standard_ice_) { + channel_->SetRemoteIceCredentials(pending_candidates_.front().username(), + pending_candidates_.front().password()); + } channel_->OnCandidate(pending_candidates_.front()); pending_candidates_.pop_front(); } @@ -182,8 +198,18 @@ void LibjingleTransport::DoStart() { // TODO(sergeyu): Specify correct component ID for the channel. channel_.reset(new cricket::P2PTransportChannel( std::string(), 0, nullptr, port_allocator_)); - channel_->SetIceProtocolType(cricket::ICEPROTO_GOOGLE); - channel_->SetIceCredentials(ice_username_fragment_, ice_password_); + std::string ice_password = rtc::CreateRandomString(cricket::ICE_PWD_LENGTH); + if (use_standard_ice_) { + channel_->SetIceProtocolType(cricket::ICEPROTO_RFC5245); + channel_->SetIceRole((role_ == TransportRole::CLIENT) + ? cricket::ICEROLE_CONTROLLING + : cricket::ICEROLE_CONTROLLED); + event_handler_->OnTransportIceCredentials(this, ice_username_fragment_, + ice_password); + } else { + channel_->SetIceProtocolType(cricket::ICEPROTO_GOOGLE); + } + channel_->SetIceCredentials(ice_username_fragment_, ice_password); channel_->SignalRequestSignaling.connect( this, &LibjingleTransport::OnRequestSignaling); channel_->SignalCandidateReady.connect( @@ -218,6 +244,17 @@ void LibjingleTransport::NotifyConnected() { base::ResetAndReturn(&callback_).Run(socket.Pass()); } +void LibjingleTransport::SetRemoteCredentials(const std::string& ufrag, + const std::string& password) { + DCHECK(CalledOnValidThread()); + + remote_ice_username_fragment_ = ufrag; + remote_ice_password_ = password; + + if (channel_) + channel_->SetRemoteIceCredentials(ufrag, password); +} + void LibjingleTransport::AddRemoteCandidate( const cricket::Candidate& candidate) { DCHECK(CalledOnValidThread()); @@ -230,8 +267,10 @@ void LibjingleTransport::AddRemoteCandidate( return; if (channel_) { - channel_->SetRemoteIceCredentials(candidate.username(), - candidate.password()); + if (!use_standard_ice_) { + channel_->SetRemoteIceCredentials(candidate.username(), + candidate.password()); + } channel_->OnCandidate(candidate); } else { pending_candidates_.push_back(candidate); @@ -248,6 +287,12 @@ bool LibjingleTransport::is_connected() const { return callback_.is_null(); } +void LibjingleTransport::SetUseStandardIce(bool use_standard_ice) { + DCHECK(CalledOnValidThread()); + DCHECK(!channel_); + use_standard_ice_ = use_standard_ice; +} + void LibjingleTransport::OnRequestSignaling( cricket::TransportChannelImpl* channel) { DCHECK(CalledOnValidThread()); @@ -339,8 +384,10 @@ void LibjingleTransport::TryReconnect() { --connect_attempts_left_; // Restart ICE by resetting ICE password. - ice_password_ = rtc::CreateRandomString(cricket::ICE_PWD_LENGTH); - channel_->SetIceCredentials(ice_username_fragment_, ice_password_); + std::string ice_password = rtc::CreateRandomString(cricket::ICE_PWD_LENGTH); + event_handler_->OnTransportIceCredentials(this, ice_username_fragment_, + ice_password); + channel_->SetIceCredentials(ice_username_fragment_, ice_password); } } // namespace @@ -348,10 +395,12 @@ void LibjingleTransport::TryReconnect() { LibjingleTransportFactory::LibjingleTransportFactory( SignalStrategy* signal_strategy, scoped_ptr<cricket::HttpPortAllocatorBase> port_allocator, - const NetworkSettings& network_settings) + const NetworkSettings& network_settings, + TransportRole role) : signal_strategy_(signal_strategy), port_allocator_(port_allocator.Pass()), - network_settings_(network_settings) { + network_settings_(network_settings), + role_(role) { } LibjingleTransportFactory::~LibjingleTransportFactory() { @@ -368,7 +417,7 @@ void LibjingleTransportFactory::PrepareTokens() { scoped_ptr<Transport> LibjingleTransportFactory::CreateTransport() { scoped_ptr<LibjingleTransport> result( - new LibjingleTransport(port_allocator_.get(), network_settings_)); + new LibjingleTransport(port_allocator_.get(), network_settings_, role_)); EnsureFreshJingleInfo(); diff --git a/remoting/protocol/libjingle_transport_factory.h b/remoting/protocol/libjingle_transport_factory.h index f6af301..1fd8855 100644 --- a/remoting/protocol/libjingle_transport_factory.h +++ b/remoting/protocol/libjingle_transport_factory.h @@ -41,7 +41,8 @@ class LibjingleTransportFactory : public TransportFactory { LibjingleTransportFactory( SignalStrategy* signal_strategy, scoped_ptr<cricket::HttpPortAllocatorBase> port_allocator, - const NetworkSettings& network_settings); + const NetworkSettings& network_settings, + TransportRole role); ~LibjingleTransportFactory() override; @@ -58,6 +59,7 @@ class LibjingleTransportFactory : public TransportFactory { SignalStrategy* signal_strategy_; scoped_ptr<cricket::HttpPortAllocatorBase> port_allocator_; NetworkSettings network_settings_; + TransportRole role_; base::TimeTicks last_jingle_info_update_time_; scoped_ptr<JingleInfoRequest> jingle_info_request_; diff --git a/remoting/protocol/protocol_mock_objects.h b/remoting/protocol/protocol_mock_objects.h index 2484e9a..b3fca8e 100644 --- a/remoting/protocol/protocol_mock_objects.h +++ b/remoting/protocol/protocol_mock_objects.h @@ -207,7 +207,10 @@ class MockSession : public Session { MOCK_METHOD0(jid, const std::string&()); MOCK_METHOD0(candidate_config, const CandidateSessionConfig*()); MOCK_METHOD0(config, const SessionConfig&()); - MOCK_METHOD1(set_config, void(const SessionConfig& config)); + MOCK_METHOD1(set_config_ptr, void(const SessionConfig* config)); + void set_config(scoped_ptr<SessionConfig> config) override { + set_config_ptr(config.get()); + } MOCK_METHOD0(initiator_token, const std::string&()); MOCK_METHOD1(set_initiator_token, void(const std::string& initiator_token)); MOCK_METHOD0(receiver_token, const std::string&()); diff --git a/remoting/protocol/session.h b/remoting/protocol/session.h index f806e21..b4a0d03 100644 --- a/remoting/protocol/session.h +++ b/remoting/protocol/session.h @@ -94,7 +94,7 @@ class Session { // Set protocol configuration for an incoming session. Must be // called on the host before the connection is accepted, from // ChromotocolServer::IncomingConnectionCallback. - virtual void set_config(const SessionConfig& config) = 0; + virtual void set_config(scoped_ptr<SessionConfig> config) = 0; // GetTransportChannelFactory() returns a factory that creates a new transport // channel for each logical channel. GetMultiplexedChannelFactory() channels diff --git a/remoting/protocol/session_config.cc b/remoting/protocol/session_config.cc index 460da28..f6163f4 100644 --- a/remoting/protocol/session_config.cc +++ b/remoting/protocol/session_config.cc @@ -9,6 +9,30 @@ namespace remoting { namespace protocol { +namespace { + +bool IsChannelConfigSupported(const std::list<ChannelConfig>& list, + const ChannelConfig& value) { + return std::find(list.begin(), list.end(), value) != list.end(); +} + +bool SelectCommonChannelConfig(const std::list<ChannelConfig>& host_configs, + const std::list<ChannelConfig>& client_configs, + ChannelConfig* config) { + // Usually each of these lists will contain just a few elements, so iterating + // over all of them is not a problem. + std::list<ChannelConfig>::const_iterator it; + for (it = client_configs.begin(); it != client_configs.end(); ++it) { + if (IsChannelConfigSupported(host_configs, *it)) { + *config = *it; + return true; + } + } + return false; +} + +} // namespace + const int kDefaultStreamVersion = 2; const int kControlStreamVersion = 3; @@ -16,12 +40,6 @@ ChannelConfig ChannelConfig::None() { return ChannelConfig(); } -ChannelConfig::ChannelConfig() - : transport(TRANSPORT_NONE), - version(0), - codec(CODEC_UNDEFINED) { -} - ChannelConfig::ChannelConfig(TransportType transport, int version, Codec codec) : transport(transport), version(version), @@ -35,32 +53,93 @@ bool ChannelConfig::operator==(const ChannelConfig& b) const { return transport == b.transport && version == b.version && codec == b.codec; } -SessionConfig::SessionConfig() { +// static +scoped_ptr<SessionConfig> SessionConfig::SelectCommon( + const CandidateSessionConfig* client_config, + const CandidateSessionConfig* host_config) { + scoped_ptr<SessionConfig> result(new SessionConfig()); + ChannelConfig control_config; + ChannelConfig event_config; + ChannelConfig video_config; + ChannelConfig audio_config; + + result->standard_ice_ = + host_config->standard_ice() && client_config->standard_ice(); + + if (!SelectCommonChannelConfig(host_config->control_configs(), + client_config->control_configs(), + &result->control_config_) || + !SelectCommonChannelConfig(host_config->event_configs(), + client_config->event_configs(), + &result->event_config_) || + !SelectCommonChannelConfig(host_config->video_configs(), + client_config->video_configs(), + &result->video_config_) || + !SelectCommonChannelConfig(host_config->audio_configs(), + client_config->audio_configs(), + &result->audio_config_)) { + return nullptr; + } + + return result; } // static -SessionConfig SessionConfig::ForTest() { - SessionConfig result; - result.set_control_config(ChannelConfig(ChannelConfig::TRANSPORT_MUX_STREAM, +scoped_ptr<SessionConfig> SessionConfig::GetFinalConfig( + const CandidateSessionConfig* candidate_config) { + if (candidate_config->control_configs().size() != 1 || + candidate_config->event_configs().size() != 1 || + candidate_config->video_configs().size() != 1 || + candidate_config->audio_configs().size() != 1) { + return nullptr; + } + + scoped_ptr<SessionConfig> result(new SessionConfig()); + result->standard_ice_ = candidate_config->standard_ice(); + result->control_config_ = candidate_config->control_configs().front(); + result->event_config_ = candidate_config->event_configs().front(); + result->video_config_ = candidate_config->video_configs().front(); + result->audio_config_ = candidate_config->audio_configs().front(); + + return result.Pass(); +} + +// static +scoped_ptr<SessionConfig> SessionConfig::ForTest() { + scoped_ptr<SessionConfig> result(new SessionConfig()); + result->standard_ice_ = true; + result->control_config_ = ChannelConfig(ChannelConfig::TRANSPORT_MUX_STREAM, kControlStreamVersion, - ChannelConfig::CODEC_UNDEFINED)); - result.set_event_config(ChannelConfig(ChannelConfig::TRANSPORT_MUX_STREAM, + ChannelConfig::CODEC_UNDEFINED); + result->event_config_ = ChannelConfig(ChannelConfig::TRANSPORT_MUX_STREAM, kDefaultStreamVersion, - ChannelConfig::CODEC_UNDEFINED)); - result.set_video_config(ChannelConfig(ChannelConfig::TRANSPORT_STREAM, + ChannelConfig::CODEC_UNDEFINED); + result->video_config_ = ChannelConfig(ChannelConfig::TRANSPORT_STREAM, kDefaultStreamVersion, - ChannelConfig::CODEC_VP8)); - result.set_audio_config(ChannelConfig(ChannelConfig::TRANSPORT_NONE, + ChannelConfig::CODEC_VP8); + result->audio_config_ = ChannelConfig(ChannelConfig::TRANSPORT_NONE, kDefaultStreamVersion, - ChannelConfig::CODEC_UNDEFINED)); - return result; + ChannelConfig::CODEC_UNDEFINED); + return result.Pass(); } +// static +scoped_ptr<SessionConfig> SessionConfig::WithLegacyIceForTest() { + scoped_ptr<SessionConfig> result = ForTest(); + result->standard_ice_ = false; + return result.Pass(); +} + +SessionConfig::SessionConfig() { +} + + CandidateSessionConfig::CandidateSessionConfig() { } CandidateSessionConfig::CandidateSessionConfig( const CandidateSessionConfig& config) - : control_configs_(config.control_configs_), + : standard_ice_(true), + control_configs_(config.control_configs_), event_configs_(config.event_configs_), video_configs_(config.video_configs_), audio_configs_(config.audio_configs_) { @@ -68,33 +147,6 @@ CandidateSessionConfig::CandidateSessionConfig( CandidateSessionConfig::~CandidateSessionConfig() { } -bool CandidateSessionConfig::Select( - const CandidateSessionConfig* client_config, - SessionConfig* result) { - ChannelConfig control_config; - ChannelConfig event_config; - ChannelConfig video_config; - ChannelConfig audio_config; - - if (!SelectCommonChannelConfig( - control_configs_, client_config->control_configs_, &control_config) || - !SelectCommonChannelConfig( - event_configs_, client_config->event_configs_, &event_config) || - !SelectCommonChannelConfig( - video_configs_, client_config->video_configs_, &video_config) || - !SelectCommonChannelConfig( - audio_configs_, client_config->audio_configs_, &audio_config)) { - return false; - } - - result->set_control_config(control_config); - result->set_event_config(event_config); - result->set_video_config(video_config); - result->set_audio_config(audio_config); - - return true; -} - bool CandidateSessionConfig::IsSupported( const SessionConfig& config) const { return @@ -104,46 +156,6 @@ bool CandidateSessionConfig::IsSupported( IsChannelConfigSupported(audio_configs_, config.audio_config()); } -bool CandidateSessionConfig::GetFinalConfig(SessionConfig* result) const { - if (control_configs_.size() != 1 || - event_configs_.size() != 1 || - video_configs_.size() != 1 || - audio_configs_.size() != 1) { - return false; - } - - result->set_control_config(control_configs_.front()); - result->set_event_config(event_configs_.front()); - result->set_video_config(video_configs_.front()); - result->set_audio_config(audio_configs_.front()); - - return true; -} - -// static -bool CandidateSessionConfig::SelectCommonChannelConfig( - const std::list<ChannelConfig>& host_configs, - const std::list<ChannelConfig>& client_configs, - ChannelConfig* config) { - // Usually each of these vectors will contain just several elements, - // so iterating over all of them is not a problem. - std::list<ChannelConfig>::const_iterator it; - for (it = client_configs.begin(); it != client_configs.end(); ++it) { - if (IsChannelConfigSupported(host_configs, *it)) { - *config = *it; - return true; - } - } - return false; -} - -// static -bool CandidateSessionConfig::IsChannelConfigSupported( - const std::list<ChannelConfig>& vector, - const ChannelConfig& value) { - return std::find(vector.begin(), vector.end(), value) != vector.end(); -} - scoped_ptr<CandidateSessionConfig> CandidateSessionConfig::Clone() const { return make_scoped_ptr(new CandidateSessionConfig(*this)); } @@ -157,6 +169,7 @@ scoped_ptr<CandidateSessionConfig> CandidateSessionConfig::CreateEmpty() { scoped_ptr<CandidateSessionConfig> CandidateSessionConfig::CreateFrom( const SessionConfig& config) { scoped_ptr<CandidateSessionConfig> result = CreateEmpty(); + result->set_standard_ice(config.standard_ice()); result->mutable_control_configs()->push_back(config.control_config()); result->mutable_event_configs()->push_back(config.event_config()); result->mutable_video_configs()->push_back(config.video_config()); @@ -168,6 +181,8 @@ scoped_ptr<CandidateSessionConfig> CandidateSessionConfig::CreateFrom( scoped_ptr<CandidateSessionConfig> CandidateSessionConfig::CreateDefault() { scoped_ptr<CandidateSessionConfig> result = CreateEmpty(); + result->set_standard_ice(true); + // Control channel. result->mutable_control_configs()->push_back( ChannelConfig(ChannelConfig::TRANSPORT_MUX_STREAM, diff --git a/remoting/protocol/session_config.h b/remoting/protocol/session_config.h index c0313a0..acd3dba 100644 --- a/remoting/protocol/session_config.h +++ b/remoting/protocol/session_config.h @@ -42,7 +42,7 @@ struct ChannelConfig { static ChannelConfig None(); // Default constructor. Equivalent to None(). - ChannelConfig(); + ChannelConfig() = default; // Creates a channel config with the specified parameters. ChannelConfig(TransportType transport, int version, Codec codec); @@ -51,42 +51,53 @@ struct ChannelConfig { // std::list<ChannelConfig>. bool operator==(const ChannelConfig& b) const; - TransportType transport; - int version; - Codec codec; + TransportType transport = TRANSPORT_NONE; + int version = 0; + Codec codec = CODEC_UNDEFINED; }; +class CandidateSessionConfig; + // SessionConfig is used by the chromoting Session to store negotiated // chromotocol configuration. class SessionConfig { public: - SessionConfig(); + // Selects session configuration that is supported by both participants. + // nullptr is returned if such configuration doesn't exist. When selecting + // channel configuration priority is given to the configs listed first + // in |client_config|. + static scoped_ptr<SessionConfig> SelectCommon( + const CandidateSessionConfig* client_config, + const CandidateSessionConfig* host_config); + + // Extracts final protocol configuration. Must be used for the description + // received in the session-accept stanza. If the selection is ambiguous + // (e.g. there is more than one configuration for one of the channel) + // or undefined (e.g. no configurations for a channel) then nullptr is + // returned. + static scoped_ptr<SessionConfig> GetFinalConfig( + const CandidateSessionConfig* candidate_config); + + // Returns a suitable session configuration for use in tests. + static scoped_ptr<SessionConfig> ForTest(); + static scoped_ptr<SessionConfig> WithLegacyIceForTest(); + + bool standard_ice() const { return standard_ice_; } - void set_control_config(const ChannelConfig& control_config) { - control_config_ = control_config; - } const ChannelConfig& control_config() const { return control_config_; } - void set_event_config(const ChannelConfig& event_config) { - event_config_ = event_config; - } const ChannelConfig& event_config() const { return event_config_; } - void set_video_config(const ChannelConfig& video_config) { - video_config_ = video_config; - } const ChannelConfig& video_config() const { return video_config_; } - void set_audio_config(const ChannelConfig& audio_config) { - audio_config_ = audio_config; - } const ChannelConfig& audio_config() const { return audio_config_; } bool is_audio_enabled() const { return audio_config_.transport != ChannelConfig::TRANSPORT_NONE; } - // Returns a suitable session configuration for use in tests. - static SessionConfig ForTest(); - private: + SessionConfig(); + + bool standard_ice_ = true; + ChannelConfig control_config_; ChannelConfig event_config_; ChannelConfig video_config_; @@ -105,6 +116,9 @@ class CandidateSessionConfig { ~CandidateSessionConfig(); + bool standard_ice() const { return standard_ice_; } + void set_standard_ice(bool standard_ice) { standard_ice_ = standard_ice; } + const std::list<ChannelConfig>& control_configs() const { return control_configs_; } @@ -137,23 +151,9 @@ class CandidateSessionConfig { return &audio_configs_; } - // Selects session configuration that is supported by both participants. - // nullptr is returned if such configuration doesn't exist. When selecting - // channel configuration priority is given to the configs listed first - // in |client_config|. - bool Select(const CandidateSessionConfig* client_config, - SessionConfig* result); - // Returns true if |config| is supported. bool IsSupported(const SessionConfig& config) const; - // Extracts final protocol configuration. Must be used for the description - // received in the session-accept stanza. If the selection is ambiguous - // (e.g. there is more than one configuration for one of the channel) - // or undefined (e.g. no configurations for a channel) then nullptr is - // returned. - bool GetFinalConfig(SessionConfig* result) const; - scoped_ptr<CandidateSessionConfig> Clone() const; // Helpers for enabling/disabling specific features. @@ -165,12 +165,7 @@ class CandidateSessionConfig { explicit CandidateSessionConfig(const CandidateSessionConfig& config); CandidateSessionConfig& operator=(const CandidateSessionConfig& b); - static bool SelectCommonChannelConfig( - const std::list<ChannelConfig>& host_configs_, - const std::list<ChannelConfig>& client_configs_, - ChannelConfig* config); - static bool IsChannelConfigSupported(const std::list<ChannelConfig>& list, - const ChannelConfig& value); + bool standard_ice_ = true; std::list<ChannelConfig> control_configs_; std::list<ChannelConfig> event_configs_; diff --git a/remoting/protocol/transport.h b/remoting/protocol/transport.h index d4c4b3f..4223796 100644 --- a/remoting/protocol/transport.h +++ b/remoting/protocol/transport.h @@ -44,6 +44,11 @@ namespace protocol { class ChannelAuthenticator; +enum class TransportRole { + SERVER, + CLIENT, +}; + struct TransportRoute { enum RouteType { DIRECT, @@ -69,6 +74,12 @@ class Transport : public base::NonThreadSafe { EventHandler() {}; virtual ~EventHandler() {}; + // Called to pass ICE credentials to the session. Used only for STANDARD + // version of ICE, see SetIceVersion(). + virtual void OnTransportIceCredentials(Transport* transport, + const std::string& ufrag, + const std::string& password) = 0; + // Called when the transport generates a new candidate that needs // to be passed to the AddRemoteCandidate() method on the remote // end of the connection. @@ -97,6 +108,10 @@ class Transport : public base::NonThreadSafe { Transport::EventHandler* event_handler, const ConnectedCallback& callback) = 0; + // Sets remote ICE credentials. + virtual void SetRemoteCredentials(const std::string& ufrag, + const std::string& password) = 0; + // Adds |candidate| received from the peer. virtual void AddRemoteCandidate(const cricket::Candidate& candidate) = 0; @@ -108,6 +123,12 @@ class Transport : public base::NonThreadSafe { // Returns true if the channel is already connected. virtual bool is_connected() const = 0; + // Sets ICE version for the transport. + // + // TODO(sergeyu): Remove this when support for legacy ICE is removed. + // crbug.com/473758 + virtual void SetUseStandardIce(bool use_standard_ice) {} + private: DISALLOW_COPY_AND_ASSIGN(Transport); }; diff --git a/remoting/test/protocol_perftest.cc b/remoting/test/protocol_perftest.cc index 6401c46..6959edb 100644 --- a/remoting/test/protocol_perftest.cc +++ b/remoting/test/protocol_perftest.cc @@ -235,9 +235,8 @@ class ProtocolPerfTest GetParam().out_of_order_rate); scoped_ptr<protocol::TransportFactory> host_transport_factory( new protocol::LibjingleTransportFactory( - host_signaling_.get(), - port_allocator.Pass(), - network_settings)); + host_signaling_.get(), port_allocator.Pass(), network_settings, + protocol::TransportRole::SERVER)); scoped_ptr<protocol::SessionManager> session_manager( new protocol::JingleSessionManager(host_transport_factory.Pass())); @@ -306,9 +305,8 @@ class ProtocolPerfTest GetParam().out_of_order_rate); scoped_ptr<protocol::TransportFactory> client_transport_factory( new protocol::LibjingleTransportFactory( - client_signaling_.get(), - port_allocator.Pass(), - network_settings)); + client_signaling_.get(), port_allocator.Pass(), network_settings, + protocol::TransportRole::CLIENT)); std::vector<protocol::AuthenticationMethod> auth_methods; auth_methods.push_back(protocol::AuthenticationMethod::Spake2( diff --git a/remoting/test/test_chromoting_client.cc b/remoting/test/test_chromoting_client.cc index adf1093..5f2e537 100644 --- a/remoting/test/test_chromoting_client.cc +++ b/remoting/test/test_chromoting_client.cc @@ -191,7 +191,8 @@ void TestChromotingClient::StartConnection( scoped_ptr<protocol::TransportFactory> transport_factory( new protocol::LibjingleTransportFactory( - signal_strategy_.get(), port_allocator.Pass(), network_settings)); + signal_strategy_.get(), port_allocator.Pass(), network_settings, + protocol::TransportRole::CLIENT)); scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher> token_fetcher(new TokenFetcherProxy( |