make CreateOffer/CreateAnswer use ice credentials of pooled sessions.
This patch make CreateOffer/CreateAnswer use the ice credentials
of pooled sessions (if any).
BUG=webrtc:9807
Change-Id: I51e0578f2ff0d4faa93d9666bd6b2c15461e8985
Reviewed-on: https://webrtc-review.googlesource.com/c/102923
Reviewed-by: Qingsi Wang <qingsi@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Jonas Oreland <jonaso@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#25132}
diff --git a/p2p/BUILD.gn b/p2p/BUILD.gn
index 5d4e706..f1466d7 100644
--- a/p2p/BUILD.gn
+++ b/p2p/BUILD.gn
@@ -29,6 +29,8 @@
"base/dtlstransport.h",
"base/dtlstransportinternal.cc",
"base/dtlstransportinternal.h",
+ "base/icecredentialsiterator.cc",
+ "base/icecredentialsiterator.h",
"base/icetransportinternal.cc",
"base/icetransportinternal.h",
"base/mdns_message.cc",
@@ -154,6 +156,7 @@
"base/asyncstuntcpsocket_unittest.cc",
"base/basicasyncresolverfactory_unittest.cc",
"base/dtlstransport_unittest.cc",
+ "base/icecredentialsiterator_unittest.cc",
"base/mdns_message_unittest.cc",
"base/p2ptransportchannel_unittest.cc",
"base/packetlossestimator_unittest.cc",
diff --git a/p2p/base/icecredentialsiterator.cc b/p2p/base/icecredentialsiterator.cc
new file mode 100644
index 0000000..7d29653
--- /dev/null
+++ b/p2p/base/icecredentialsiterator.cc
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2018 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "p2p/base/icecredentialsiterator.h"
+#include "rtc_base/helpers.h"
+
+namespace cricket {
+
+IceCredentialsIterator::IceCredentialsIterator(
+ const std::vector<IceParameters>& pooled_credentials)
+ : pooled_ice_credentials_(pooled_credentials) {}
+
+IceCredentialsIterator::~IceCredentialsIterator() = default;
+
+IceParameters IceCredentialsIterator::CreateRandomIceCredentials() {
+ return IceParameters(rtc::CreateRandomString(ICE_UFRAG_LENGTH),
+ rtc::CreateRandomString(ICE_PWD_LENGTH), false);
+}
+
+IceParameters IceCredentialsIterator::GetIceCredentials() {
+ if (pooled_ice_credentials_.empty()) {
+ return CreateRandomIceCredentials();
+ }
+ IceParameters credentials = pooled_ice_credentials_.back();
+ pooled_ice_credentials_.pop_back();
+ return credentials;
+}
+
+} // namespace cricket
diff --git a/p2p/base/icecredentialsiterator.h b/p2p/base/icecredentialsiterator.h
new file mode 100644
index 0000000..33e1d64
--- /dev/null
+++ b/p2p/base/icecredentialsiterator.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2018 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef P2P_BASE_ICECREDENTIALSITERATOR_H_
+#define P2P_BASE_ICECREDENTIALSITERATOR_H_
+
+#include <vector>
+
+#include "p2p/base/transportdescription.h"
+
+namespace cricket {
+
+class IceCredentialsIterator {
+ public:
+ explicit IceCredentialsIterator(const std::vector<IceParameters>&);
+ virtual ~IceCredentialsIterator();
+
+ // Get next pooled ice credentials.
+ // Returns a new random credential if the pool is empty.
+ IceParameters GetIceCredentials();
+
+ static IceParameters CreateRandomIceCredentials();
+
+ private:
+ std::vector<IceParameters> pooled_ice_credentials_;
+};
+
+} // namespace cricket
+
+#endif // P2P_BASE_ICECREDENTIALSITERATOR_H_
diff --git a/p2p/base/icecredentialsiterator_unittest.cc b/p2p/base/icecredentialsiterator_unittest.cc
new file mode 100644
index 0000000..00facfb
--- /dev/null
+++ b/p2p/base/icecredentialsiterator_unittest.cc
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2018 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "p2p/base/icecredentialsiterator.h"
+#include "rtc_base/gunit.h"
+
+using cricket::IceParameters;
+using cricket::IceCredentialsIterator;
+
+TEST(IceCredentialsIteratorTest, GetEmpty) {
+ std::vector<IceParameters> empty;
+ IceCredentialsIterator iterator(empty);
+ // Verify that we can get credentials even if input is empty.
+ IceParameters credentials1 = iterator.GetIceCredentials();
+}
+
+TEST(IceCredentialsIteratorTest, GetOne) {
+ std::vector<IceParameters> one = {
+ IceCredentialsIterator::CreateRandomIceCredentials()};
+ IceCredentialsIterator iterator(one);
+ EXPECT_EQ(iterator.GetIceCredentials(), one[0]);
+ auto random = iterator.GetIceCredentials();
+ EXPECT_NE(random, one[0]);
+ EXPECT_NE(random, iterator.GetIceCredentials());
+}
+
+TEST(IceCredentialsIteratorTest, GetTwo) {
+ std::vector<IceParameters> two = {
+ IceCredentialsIterator::CreateRandomIceCredentials(),
+ IceCredentialsIterator::CreateRandomIceCredentials()};
+ IceCredentialsIterator iterator(two);
+ EXPECT_EQ(iterator.GetIceCredentials(), two[1]);
+ EXPECT_EQ(iterator.GetIceCredentials(), two[0]);
+ auto random = iterator.GetIceCredentials();
+ EXPECT_NE(random, two[0]);
+ EXPECT_NE(random, two[1]);
+ EXPECT_NE(random, iterator.GetIceCredentials());
+}
diff --git a/p2p/base/portallocator.cc b/p2p/base/portallocator.cc
index 5470b5b..d3b3a56 100644
--- a/p2p/base/portallocator.cc
+++ b/p2p/base/portallocator.cc
@@ -10,8 +10,10 @@
#include "p2p/base/portallocator.h"
+#include <iterator>
#include <utility>
+#include "p2p/base/icecredentialsiterator.h"
#include "rtc_base/checks.h"
namespace cricket {
@@ -121,6 +123,10 @@
CheckRunOnValidThreadIfInitialized();
}
+void PortAllocator::set_restrict_ice_credentials_change(bool value) {
+ restrict_ice_credentials_change_ = value;
+}
+
bool PortAllocator::SetConfiguration(
const ServerAddresses& stun_servers,
const std::vector<RelayServerConfig>& turn_servers,
@@ -166,8 +172,8 @@
// If |candidate_pool_size_| is less than the number of pooled sessions, get
// rid of the extras.
while (candidate_pool_size_ < static_cast<int>(pooled_sessions_.size())) {
- pooled_sessions_.front().reset(nullptr);
- pooled_sessions_.pop_front();
+ pooled_sessions_.back().reset(nullptr);
+ pooled_sessions_.pop_back();
}
// |stun_candidate_keepalive_interval_| will be used in STUN port allocation
@@ -183,7 +189,11 @@
// If |candidate_pool_size_| is greater than the number of pooled sessions,
// create new sessions.
while (static_cast<int>(pooled_sessions_.size()) < candidate_pool_size_) {
- PortAllocatorSession* pooled_session = CreateSessionInternal("", 0, "", "");
+ IceParameters iceCredentials =
+ IceCredentialsIterator::CreateRandomIceCredentials();
+ PortAllocatorSession* pooled_session =
+ CreateSessionInternal("", 0, iceCredentials.ufrag, iceCredentials.pwd);
+ pooled_session->set_pooled(true);
pooled_session->StartGettingPorts();
pooled_sessions_.push_back(
std::unique_ptr<PortAllocatorSession>(pooled_session));
@@ -214,22 +224,50 @@
if (pooled_sessions_.empty()) {
return nullptr;
}
- std::unique_ptr<PortAllocatorSession> ret =
- std::move(pooled_sessions_.front());
+
+ IceParameters credentials(ice_ufrag, ice_pwd, false);
+ // If restrict_ice_credentials_change_ is TRUE, then call FindPooledSession
+ // with ice credentials. Otherwise call it with nullptr which means
+ // "find any" pooled session.
+ auto cit = FindPooledSession(restrict_ice_credentials_change_ ? &credentials
+ : nullptr);
+ if (cit == pooled_sessions_.end()) {
+ return nullptr;
+ }
+
+ auto it =
+ pooled_sessions_.begin() + std::distance(pooled_sessions_.cbegin(), cit);
+ std::unique_ptr<PortAllocatorSession> ret = std::move(*it);
ret->SetIceParameters(content_name, component, ice_ufrag, ice_pwd);
- // According to JSEP, a pooled session should filter candidates only after
- // it's taken out of the pool.
+ ret->set_pooled(false);
+ // According to JSEP, a pooled session should filter candidates only
+ // after it's taken out of the pool.
ret->SetCandidateFilter(candidate_filter());
- pooled_sessions_.pop_front();
+ pooled_sessions_.erase(it);
return ret;
}
-const PortAllocatorSession* PortAllocator::GetPooledSession() const {
+const PortAllocatorSession* PortAllocator::GetPooledSession(
+ const IceParameters* ice_credentials) const {
CheckRunOnValidThreadAndInitialized();
- if (pooled_sessions_.empty()) {
+ auto it = FindPooledSession(ice_credentials);
+ if (it == pooled_sessions_.end()) {
return nullptr;
+ } else {
+ return it->get();
}
- return pooled_sessions_.front().get();
+}
+
+std::vector<std::unique_ptr<PortAllocatorSession>>::const_iterator
+PortAllocator::FindPooledSession(const IceParameters* ice_credentials) const {
+ for (auto it = pooled_sessions_.begin(); it != pooled_sessions_.end(); ++it) {
+ if (ice_credentials == nullptr ||
+ ((*it)->ice_ufrag() == ice_credentials->ufrag &&
+ (*it)->ice_pwd() == ice_credentials->pwd)) {
+ return it;
+ }
+ }
+ return pooled_sessions_.end();
}
void PortAllocator::FreezeCandidatePool() {
@@ -250,4 +288,14 @@
}
}
+std::vector<IceParameters> PortAllocator::GetPooledIceCredentials() {
+ CheckRunOnValidThreadAndInitialized();
+ std::vector<IceParameters> list;
+ for (const auto& session : pooled_sessions_) {
+ list.push_back(
+ IceParameters(session->ice_ufrag(), session->ice_pwd(), false));
+ }
+ return list;
+}
+
} // namespace cricket
diff --git a/p2p/base/portallocator.h b/p2p/base/portallocator.h
index 8bd7096..988447c 100644
--- a/p2p/base/portallocator.h
+++ b/p2p/base/portallocator.h
@@ -201,7 +201,7 @@
int component() const { return component_; }
const std::string& ice_ufrag() const { return ice_ufrag_; }
const std::string& ice_pwd() const { return ice_pwd_; }
- bool pooled() const { return ice_ufrag_.empty(); }
+ bool pooled() const { return pooled_; }
// Setting this filter should affect not only candidates gathered in the
// future, but candidates already gathered and ports already "ready",
@@ -309,6 +309,8 @@
UpdateIceParametersInternal();
}
+ void set_pooled(bool value) { pooled_ = value; }
+
uint32_t flags_;
uint32_t generation_;
std::string content_name_;
@@ -316,6 +318,8 @@
std::string ice_ufrag_;
std::string ice_pwd_;
+ bool pooled_ = false;
+
// SetIceParameters is an implementation detail which only PortAllocator
// should be able to call.
friend class PortAllocator;
@@ -335,6 +339,11 @@
// constructing and configuring the PortAllocator subclasses.
virtual void Initialize();
+ // Set to true if some Ports need to know the ICE credentials when they are
+ // created. This will ensure that the PortAllocator will only match pooled
+ // allocator sessions to the ICE transport with the same credentials.
+ virtual void set_restrict_ice_credentials_change(bool value);
+
// Set STUN and TURN servers to be used in future sessions, and set
// candidate pool size, as described in JSEP.
//
@@ -392,6 +401,8 @@
//
// Caller takes ownership of the returned session.
//
+ // If restrict_ice_credentials_change is TRUE, then it will only
+ // return a pooled session with matching ice credentials.
// If no pooled sessions are available, returns null.
std::unique_ptr<PortAllocatorSession> TakePooledSession(
const std::string& content_name,
@@ -399,8 +410,10 @@
const std::string& ice_ufrag,
const std::string& ice_pwd);
- // Returns the next session that would be returned by TakePooledSession.
- const PortAllocatorSession* GetPooledSession() const;
+ // Returns the next session that would be returned by TakePooledSession
+ // optionally restricting it to sessions with specified ice credentials.
+ const PortAllocatorSession* GetPooledSession(
+ const IceParameters* ice_credentials = nullptr) const;
// After FreezeCandidatePool is called, changing the candidate pool size will
// no longer be allowed, and changing ICE servers will not cause pooled
@@ -548,6 +561,9 @@
virtual void GetCandidateStatsFromPooledSessions(
CandidateStatsList* candidate_stats_list);
+ // Return IceParameters of the pooled sessions.
+ std::vector<IceParameters> GetPooledIceCredentials();
+
protected:
virtual PortAllocatorSession* CreateSessionInternal(
const std::string& content_name,
@@ -555,7 +571,7 @@
const std::string& ice_ufrag,
const std::string& ice_pwd) = 0;
- const std::deque<std::unique_ptr<PortAllocatorSession>>& pooled_sessions() {
+ const std::vector<std::unique_ptr<PortAllocatorSession>>& pooled_sessions() {
return pooled_sessions_;
}
@@ -586,7 +602,7 @@
ServerAddresses stun_servers_;
std::vector<RelayServerConfig> turn_servers_;
int candidate_pool_size_ = 0; // Last value passed into SetConfiguration.
- std::deque<std::unique_ptr<PortAllocatorSession>> pooled_sessions_;
+ std::vector<std::unique_ptr<PortAllocatorSession>> pooled_sessions_;
bool candidate_pool_frozen_ = false;
bool prune_turn_ports_ = false;
@@ -596,6 +612,15 @@
webrtc::TurnCustomizer* turn_customizer_ = nullptr;
absl::optional<int> stun_candidate_keepalive_interval_;
+
+ // If true, TakePooledSession() will only return sessions that has same ice
+ // credentials as requested.
+ bool restrict_ice_credentials_change_ = false;
+
+ // Returns iterator to pooled session with specified ice_credentials or first
+ // if ice_credentials is nullptr.
+ std::vector<std::unique_ptr<PortAllocatorSession>>::const_iterator
+ FindPooledSession(const IceParameters* ice_credentials = nullptr) const;
};
} // namespace cricket
diff --git a/p2p/base/portallocator_unittest.cc b/p2p/base/portallocator_unittest.cc
index 3887a90d..8b317f4 100644
--- a/p2p/base/portallocator_unittest.cc
+++ b/p2p/base/portallocator_unittest.cc
@@ -71,8 +71,7 @@
int GetAllPooledSessionsReturnCount() {
int count = 0;
- while (GetPooledSession()) {
- TakePooledSession();
+ while (TakePooledSession() != nullptr) {
++count;
}
return count;
@@ -275,3 +274,29 @@
allocator_->DiscardCandidatePool();
EXPECT_EQ(0, GetAllPooledSessionsReturnCount());
}
+
+TEST_F(PortAllocatorTest, RestrictIceCredentialsChange) {
+ SetConfigurationWithPoolSize(1);
+ EXPECT_EQ(1, GetAllPooledSessionsReturnCount());
+ allocator_->DiscardCandidatePool();
+
+ // Only return pooled sessions with the ice credentials that
+ // match those requested in TakePooledSession().
+ allocator_->set_restrict_ice_credentials_change(true);
+ SetConfigurationWithPoolSize(1);
+ EXPECT_EQ(0, GetAllPooledSessionsReturnCount());
+ allocator_->DiscardCandidatePool();
+
+ SetConfigurationWithPoolSize(1);
+ auto credentials = allocator_->GetPooledIceCredentials();
+ ASSERT_EQ(1u, credentials.size());
+ EXPECT_EQ(nullptr,
+ allocator_->TakePooledSession(kContentName, 0, kIceUfrag, kIcePwd));
+ EXPECT_NE(nullptr,
+ allocator_->TakePooledSession(kContentName, 0, credentials[0].ufrag,
+ credentials[0].pwd));
+ EXPECT_EQ(nullptr,
+ allocator_->TakePooledSession(kContentName, 0, credentials[0].ufrag,
+ credentials[0].pwd));
+ allocator_->DiscardCandidatePool();
+}
diff --git a/p2p/base/transportdescription.h b/p2p/base/transportdescription.h
index 3bffdf9..2ab9732 100644
--- a/p2p/base/transportdescription.h
+++ b/p2p/base/transportdescription.h
@@ -67,11 +67,13 @@
bool ice_renomination)
: ufrag(ice_ufrag), pwd(ice_pwd), renomination(ice_renomination) {}
- bool operator==(const IceParameters& other) {
+ bool operator==(const IceParameters& other) const {
return ufrag == other.ufrag && pwd == other.pwd &&
renomination == other.renomination;
}
- bool operator!=(const IceParameters& other) { return !(*this == other); }
+ bool operator!=(const IceParameters& other) const {
+ return !(*this == other);
+ }
};
extern const char CONNECTIONROLE_ACTIVE_STR[];
diff --git a/p2p/base/transportdescriptionfactory.cc b/p2p/base/transportdescriptionfactory.cc
index 618726e..670950d 100644
--- a/p2p/base/transportdescriptionfactory.cc
+++ b/p2p/base/transportdescriptionfactory.cc
@@ -27,13 +27,15 @@
TransportDescription* TransportDescriptionFactory::CreateOffer(
const TransportOptions& options,
- const TransportDescription* current_description) const {
+ const TransportDescription* current_description,
+ IceCredentialsIterator* ice_credentials) const {
std::unique_ptr<TransportDescription> desc(new TransportDescription());
// Generate the ICE credentials if we don't already have them.
if (!current_description || options.ice_restart) {
- desc->ice_ufrag = rtc::CreateRandomString(ICE_UFRAG_LENGTH);
- desc->ice_pwd = rtc::CreateRandomString(ICE_PWD_LENGTH);
+ IceParameters credentials = ice_credentials->GetIceCredentials();
+ desc->ice_ufrag = credentials.ufrag;
+ desc->ice_pwd = credentials.pwd;
} else {
desc->ice_ufrag = current_description->ice_ufrag;
desc->ice_pwd = current_description->ice_pwd;
@@ -59,7 +61,8 @@
const TransportDescription* offer,
const TransportOptions& options,
bool require_transport_attributes,
- const TransportDescription* current_description) const {
+ const TransportDescription* current_description,
+ IceCredentialsIterator* ice_credentials) const {
// TODO(juberti): Figure out why we get NULL offers, and fix this upstream.
if (!offer) {
RTC_LOG(LS_WARNING) << "Failed to create TransportDescription answer "
@@ -71,8 +74,9 @@
// Generate the ICE credentials if we don't already have them or ice is
// being restarted.
if (!current_description || options.ice_restart) {
- desc->ice_ufrag = rtc::CreateRandomString(ICE_UFRAG_LENGTH);
- desc->ice_pwd = rtc::CreateRandomString(ICE_PWD_LENGTH);
+ IceParameters credentials = ice_credentials->GetIceCredentials();
+ desc->ice_ufrag = credentials.ufrag;
+ desc->ice_pwd = credentials.pwd;
} else {
desc->ice_ufrag = current_description->ice_ufrag;
desc->ice_pwd = current_description->ice_pwd;
diff --git a/p2p/base/transportdescriptionfactory.h b/p2p/base/transportdescriptionfactory.h
index 937c5fa..dc1476a 100644
--- a/p2p/base/transportdescriptionfactory.h
+++ b/p2p/base/transportdescriptionfactory.h
@@ -11,6 +11,7 @@
#ifndef P2P_BASE_TRANSPORTDESCRIPTIONFACTORY_H_
#define P2P_BASE_TRANSPORTDESCRIPTIONFACTORY_H_
+#include "p2p/base/icecredentialsiterator.h"
#include "p2p/base/transportdescription.h"
#include "rtc_base/rtccertificate.h"
@@ -54,7 +55,8 @@
// Creates a transport description suitable for use in an offer.
TransportDescription* CreateOffer(
const TransportOptions& options,
- const TransportDescription* current_description) const;
+ const TransportDescription* current_description,
+ IceCredentialsIterator* ice_credentials) const;
// Create a transport description that is a response to an offer.
//
// If |require_transport_attributes| is true, then TRANSPORT category
@@ -66,7 +68,8 @@
const TransportDescription* offer,
const TransportOptions& options,
bool require_transport_attributes,
- const TransportDescription* current_description) const;
+ const TransportDescription* current_description,
+ IceCredentialsIterator* ice_credentials) const;
private:
bool SetSecurityInfo(TransportDescription* description,
diff --git a/p2p/base/transportdescriptionfactory_unittest.cc b/p2p/base/transportdescriptionfactory_unittest.cc
index a7c34b5..a3cdb80 100644
--- a/p2p/base/transportdescriptionfactory_unittest.cc
+++ b/p2p/base/transportdescriptionfactory_unittest.cc
@@ -26,7 +26,8 @@
class TransportDescriptionFactoryTest : public testing::Test {
public:
TransportDescriptionFactoryTest()
- : cert1_(rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
+ : ice_credentials_({}),
+ cert1_(rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
new rtc::FakeSSLIdentity("User1")))),
cert2_(rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
new rtc::FakeSSLIdentity("User2")))) {}
@@ -64,21 +65,22 @@
SetDtls(dtls);
cricket::TransportOptions options;
// The initial offer / answer exchange.
- std::unique_ptr<TransportDescription> offer(f1_.CreateOffer(options, NULL));
+ std::unique_ptr<TransportDescription> offer(
+ f1_.CreateOffer(options, NULL, &ice_credentials_));
std::unique_ptr<TransportDescription> answer(
- f2_.CreateAnswer(offer.get(), options, true, NULL));
+ f2_.CreateAnswer(offer.get(), options, true, NULL, &ice_credentials_));
// Create an updated offer where we restart ice.
options.ice_restart = true;
std::unique_ptr<TransportDescription> restart_offer(
- f1_.CreateOffer(options, offer.get()));
+ f1_.CreateOffer(options, offer.get(), &ice_credentials_));
VerifyUfragAndPasswordChanged(dtls, offer.get(), restart_offer.get());
// Create a new answer. The transport ufrag and password is changed since
// |options.ice_restart == true|
- std::unique_ptr<TransportDescription> restart_answer(
- f2_.CreateAnswer(restart_offer.get(), options, true, answer.get()));
+ std::unique_ptr<TransportDescription> restart_answer(f2_.CreateAnswer(
+ restart_offer.get(), options, true, answer.get(), &ice_credentials_));
ASSERT_TRUE(restart_answer.get() != NULL);
VerifyUfragAndPasswordChanged(dtls, answer.get(), restart_answer.get());
@@ -108,19 +110,20 @@
cricket::TransportOptions options;
// The initial offer / answer exchange.
std::unique_ptr<TransportDescription> offer(
- f1_.CreateOffer(options, nullptr));
- std::unique_ptr<TransportDescription> answer(
- f2_.CreateAnswer(offer.get(), options, true, nullptr));
+ f1_.CreateOffer(options, nullptr, &ice_credentials_));
+ std::unique_ptr<TransportDescription> answer(f2_.CreateAnswer(
+ offer.get(), options, true, nullptr, &ice_credentials_));
VerifyRenomination(offer.get(), false);
VerifyRenomination(answer.get(), false);
options.enable_ice_renomination = true;
std::unique_ptr<TransportDescription> renomination_offer(
- f1_.CreateOffer(options, offer.get()));
+ f1_.CreateOffer(options, offer.get(), &ice_credentials_));
VerifyRenomination(renomination_offer.get(), true);
- std::unique_ptr<TransportDescription> renomination_answer(f2_.CreateAnswer(
- renomination_offer.get(), options, true, answer.get()));
+ std::unique_ptr<TransportDescription> renomination_answer(
+ f2_.CreateAnswer(renomination_offer.get(), options, true, answer.get(),
+ &ice_credentials_));
VerifyRenomination(renomination_answer.get(), true);
}
@@ -145,6 +148,7 @@
}
}
+ cricket::IceCredentialsIterator ice_credentials_;
TransportDescriptionFactory f1_;
TransportDescriptionFactory f2_;
@@ -154,7 +158,7 @@
TEST_F(TransportDescriptionFactoryTest, TestOfferDefault) {
std::unique_ptr<TransportDescription> desc(
- f1_.CreateOffer(TransportOptions(), NULL));
+ f1_.CreateOffer(TransportOptions(), NULL, &ice_credentials_));
CheckDesc(desc.get(), "", "", "", "");
}
@@ -165,11 +169,11 @@
ASSERT_TRUE(
cert1_->ssl_certificate().GetSignatureDigestAlgorithm(&digest_alg));
std::unique_ptr<TransportDescription> desc(
- f1_.CreateOffer(TransportOptions(), NULL));
+ f1_.CreateOffer(TransportOptions(), NULL, &ice_credentials_));
CheckDesc(desc.get(), "", "", "", digest_alg);
// Ensure it also works with SEC_REQUIRED.
f1_.set_secure(cricket::SEC_REQUIRED);
- desc.reset(f1_.CreateOffer(TransportOptions(), NULL));
+ desc.reset(f1_.CreateOffer(TransportOptions(), NULL, &ice_credentials_));
CheckDesc(desc.get(), "", "", "", digest_alg);
}
@@ -177,7 +181,7 @@
TEST_F(TransportDescriptionFactoryTest, TestOfferDtlsWithNoIdentity) {
f1_.set_secure(cricket::SEC_ENABLED);
std::unique_ptr<TransportDescription> desc(
- f1_.CreateOffer(TransportOptions(), NULL));
+ f1_.CreateOffer(TransportOptions(), NULL, &ice_credentials_));
ASSERT_TRUE(desc.get() == NULL);
}
@@ -190,34 +194,36 @@
ASSERT_TRUE(
cert1_->ssl_certificate().GetSignatureDigestAlgorithm(&digest_alg));
std::unique_ptr<TransportDescription> old_desc(
- f1_.CreateOffer(TransportOptions(), NULL));
+ f1_.CreateOffer(TransportOptions(), NULL, &ice_credentials_));
ASSERT_TRUE(old_desc.get() != NULL);
std::unique_ptr<TransportDescription> desc(
- f1_.CreateOffer(TransportOptions(), old_desc.get()));
+ f1_.CreateOffer(TransportOptions(), old_desc.get(), &ice_credentials_));
CheckDesc(desc.get(), "", old_desc->ice_ufrag, old_desc->ice_pwd, digest_alg);
}
TEST_F(TransportDescriptionFactoryTest, TestAnswerDefault) {
std::unique_ptr<TransportDescription> offer(
- f1_.CreateOffer(TransportOptions(), NULL));
+ f1_.CreateOffer(TransportOptions(), NULL, &ice_credentials_));
ASSERT_TRUE(offer.get() != NULL);
- std::unique_ptr<TransportDescription> desc(
- f2_.CreateAnswer(offer.get(), TransportOptions(), true, NULL));
+ std::unique_ptr<TransportDescription> desc(f2_.CreateAnswer(
+ offer.get(), TransportOptions(), true, NULL, &ice_credentials_));
CheckDesc(desc.get(), "", "", "", "");
- desc.reset(f2_.CreateAnswer(offer.get(), TransportOptions(), true, NULL));
+ desc.reset(f2_.CreateAnswer(offer.get(), TransportOptions(), true, NULL,
+ &ice_credentials_));
CheckDesc(desc.get(), "", "", "", "");
}
// Test that we can update an answer properly; ICE credentials shouldn't change.
TEST_F(TransportDescriptionFactoryTest, TestReanswer) {
std::unique_ptr<TransportDescription> offer(
- f1_.CreateOffer(TransportOptions(), NULL));
+ f1_.CreateOffer(TransportOptions(), NULL, &ice_credentials_));
ASSERT_TRUE(offer.get() != NULL);
- std::unique_ptr<TransportDescription> old_desc(
- f2_.CreateAnswer(offer.get(), TransportOptions(), true, NULL));
+ std::unique_ptr<TransportDescription> old_desc(f2_.CreateAnswer(
+ offer.get(), TransportOptions(), true, NULL, &ice_credentials_));
ASSERT_TRUE(old_desc.get() != NULL);
std::unique_ptr<TransportDescription> desc(
- f2_.CreateAnswer(offer.get(), TransportOptions(), true, old_desc.get()));
+ f2_.CreateAnswer(offer.get(), TransportOptions(), true, old_desc.get(),
+ &ice_credentials_));
ASSERT_TRUE(desc.get() != NULL);
CheckDesc(desc.get(), "", old_desc->ice_ufrag, old_desc->ice_pwd, "");
}
@@ -227,10 +233,10 @@
f1_.set_secure(cricket::SEC_ENABLED);
f1_.set_certificate(cert1_);
std::unique_ptr<TransportDescription> offer(
- f1_.CreateOffer(TransportOptions(), NULL));
+ f1_.CreateOffer(TransportOptions(), NULL, &ice_credentials_));
ASSERT_TRUE(offer.get() != NULL);
- std::unique_ptr<TransportDescription> desc(
- f2_.CreateAnswer(offer.get(), TransportOptions(), true, NULL));
+ std::unique_ptr<TransportDescription> desc(f2_.CreateAnswer(
+ offer.get(), TransportOptions(), true, NULL, &ice_credentials_));
CheckDesc(desc.get(), "", "", "", "");
}
@@ -240,13 +246,14 @@
f2_.set_secure(cricket::SEC_ENABLED);
f2_.set_certificate(cert2_);
std::unique_ptr<TransportDescription> offer(
- f1_.CreateOffer(TransportOptions(), NULL));
+ f1_.CreateOffer(TransportOptions(), NULL, &ice_credentials_));
ASSERT_TRUE(offer.get() != NULL);
- std::unique_ptr<TransportDescription> desc(
- f2_.CreateAnswer(offer.get(), TransportOptions(), true, NULL));
+ std::unique_ptr<TransportDescription> desc(f2_.CreateAnswer(
+ offer.get(), TransportOptions(), true, NULL, &ice_credentials_));
CheckDesc(desc.get(), "", "", "", "");
f2_.set_secure(cricket::SEC_REQUIRED);
- desc.reset(f2_.CreateAnswer(offer.get(), TransportOptions(), true, NULL));
+ desc.reset(f2_.CreateAnswer(offer.get(), TransportOptions(), true, NULL,
+ &ice_credentials_));
ASSERT_TRUE(desc.get() == NULL);
}
@@ -265,13 +272,14 @@
cert2_->ssl_certificate().GetSignatureDigestAlgorithm(&digest_alg2));
std::unique_ptr<TransportDescription> offer(
- f1_.CreateOffer(TransportOptions(), NULL));
+ f1_.CreateOffer(TransportOptions(), NULL, &ice_credentials_));
ASSERT_TRUE(offer.get() != NULL);
- std::unique_ptr<TransportDescription> desc(
- f2_.CreateAnswer(offer.get(), TransportOptions(), true, NULL));
+ std::unique_ptr<TransportDescription> desc(f2_.CreateAnswer(
+ offer.get(), TransportOptions(), true, NULL, &ice_credentials_));
CheckDesc(desc.get(), "", "", "", digest_alg2);
f2_.set_secure(cricket::SEC_REQUIRED);
- desc.reset(f2_.CreateAnswer(offer.get(), TransportOptions(), true, NULL));
+ desc.reset(f2_.CreateAnswer(offer.get(), TransportOptions(), true, NULL,
+ &ice_credentials_));
CheckDesc(desc.get(), "", "", "", digest_alg2);
}
@@ -304,9 +312,36 @@
TEST_F(TransportDescriptionFactoryTest, AddsTrickleIceOption) {
cricket::TransportOptions options;
std::unique_ptr<TransportDescription> offer(
- f1_.CreateOffer(options, nullptr));
+ f1_.CreateOffer(options, nullptr, &ice_credentials_));
EXPECT_TRUE(offer->HasOption("trickle"));
std::unique_ptr<TransportDescription> answer(
- f2_.CreateAnswer(offer.get(), options, true, nullptr));
+ f2_.CreateAnswer(offer.get(), options, true, nullptr, &ice_credentials_));
EXPECT_TRUE(answer->HasOption("trickle"));
}
+
+// Test CreateOffer with IceCredentialsIterator.
+TEST_F(TransportDescriptionFactoryTest, CreateOfferIceCredentialsIterator) {
+ std::vector<cricket::IceParameters> credentials = {
+ cricket::IceParameters("kalle", "anka", false)};
+ cricket::IceCredentialsIterator credentialsIterator(credentials);
+ cricket::TransportOptions options;
+ std::unique_ptr<TransportDescription> offer(
+ f1_.CreateOffer(options, nullptr, &credentialsIterator));
+ EXPECT_EQ(offer->GetIceParameters().ufrag, credentials[0].ufrag);
+ EXPECT_EQ(offer->GetIceParameters().pwd, credentials[0].pwd);
+}
+
+// Test CreateAnswer with IceCredentialsIterator.
+TEST_F(TransportDescriptionFactoryTest, CreateAnswerIceCredentialsIterator) {
+ cricket::TransportOptions options;
+ std::unique_ptr<TransportDescription> offer(
+ f1_.CreateOffer(options, nullptr, &ice_credentials_));
+
+ std::vector<cricket::IceParameters> credentials = {
+ cricket::IceParameters("kalle", "anka", false)};
+ cricket::IceCredentialsIterator credentialsIterator(credentials);
+ std::unique_ptr<TransportDescription> answer(f1_.CreateAnswer(
+ offer.get(), options, false, nullptr, &credentialsIterator));
+ EXPECT_EQ(answer->GetIceParameters().ufrag, credentials[0].ufrag);
+ EXPECT_EQ(answer->GetIceParameters().pwd, credentials[0].pwd);
+}
diff --git a/pc/mediasession.cc b/pc/mediasession.cc
index b75dfd6..889576c 100644
--- a/pc/mediasession.cc
+++ b/pc/mediasession.cc
@@ -1268,6 +1268,8 @@
const SessionDescription* current_description) const {
std::unique_ptr<SessionDescription> offer(new SessionDescription());
+ IceCredentialsIterator ice_credentials(
+ session_options.pooled_ice_credentials);
StreamParamsVec current_streams;
GetCurrentStreamParams(current_description, ¤t_streams);
@@ -1311,18 +1313,18 @@
}
switch (media_description_options.type) {
case MEDIA_TYPE_AUDIO:
- if (!AddAudioContentForOffer(media_description_options, session_options,
- current_content, current_description,
- audio_rtp_extensions, offer_audio_codecs,
- ¤t_streams, offer.get())) {
+ if (!AddAudioContentForOffer(
+ media_description_options, session_options, current_content,
+ current_description, audio_rtp_extensions, offer_audio_codecs,
+ ¤t_streams, offer.get(), &ice_credentials)) {
return nullptr;
}
break;
case MEDIA_TYPE_VIDEO:
- if (!AddVideoContentForOffer(media_description_options, session_options,
- current_content, current_description,
- video_rtp_extensions, offer_video_codecs,
- ¤t_streams, offer.get())) {
+ if (!AddVideoContentForOffer(
+ media_description_options, session_options, current_content,
+ current_description, video_rtp_extensions, offer_video_codecs,
+ ¤t_streams, offer.get(), &ice_credentials)) {
return nullptr;
}
break;
@@ -1330,7 +1332,7 @@
if (!AddDataContentForOffer(media_description_options, session_options,
current_content, current_description,
offer_data_codecs, ¤t_streams,
- offer.get())) {
+ offer.get(), &ice_credentials)) {
return nullptr;
}
break;
@@ -1387,6 +1389,10 @@
if (!offer) {
return nullptr;
}
+
+ IceCredentialsIterator ice_credentials(
+ session_options.pooled_ice_credentials);
+
// The answer contains the intersection of the codecs in the offer with the
// codecs we support. As indicated by XEP-0167, we retain the same payload ids
// from the offer in the answer.
@@ -1449,7 +1455,7 @@
media_description_options, session_options, offer_content,
offer, current_content, current_description,
bundle_transport.get(), answer_audio_codecs, ¤t_streams,
- answer.get())) {
+ answer.get(), &ice_credentials)) {
return nullptr;
}
break;
@@ -1458,16 +1464,16 @@
media_description_options, session_options, offer_content,
offer, current_content, current_description,
bundle_transport.get(), answer_video_codecs, ¤t_streams,
- answer.get())) {
+ answer.get(), &ice_credentials)) {
return nullptr;
}
break;
case MEDIA_TYPE_DATA:
- if (!AddDataContentForAnswer(media_description_options, session_options,
- offer_content, offer, current_content,
- current_description,
- bundle_transport.get(), answer_data_codecs,
- ¤t_streams, answer.get())) {
+ if (!AddDataContentForAnswer(
+ media_description_options, session_options, offer_content,
+ offer, current_content, current_description,
+ bundle_transport.get(), answer_data_codecs, ¤t_streams,
+ answer.get(), &ice_credentials)) {
return nullptr;
}
break;
@@ -1774,13 +1780,15 @@
const std::string& content_name,
const TransportOptions& transport_options,
const SessionDescription* current_desc,
- SessionDescription* offer_desc) const {
+ SessionDescription* offer_desc,
+ IceCredentialsIterator* ice_credentials) const {
if (!transport_desc_factory_)
return false;
const TransportDescription* current_tdesc =
GetTransportDescription(content_name, current_desc);
std::unique_ptr<TransportDescription> new_tdesc(
- transport_desc_factory_->CreateOffer(transport_options, current_tdesc));
+ transport_desc_factory_->CreateOffer(transport_options, current_tdesc,
+ ice_credentials));
bool ret =
(new_tdesc.get() != NULL &&
offer_desc->AddTransportInfo(TransportInfo(content_name, *new_tdesc)));
@@ -1796,7 +1804,8 @@
const SessionDescription* offer_desc,
const TransportOptions& transport_options,
const SessionDescription* current_desc,
- bool require_transport_attributes) const {
+ bool require_transport_attributes,
+ IceCredentialsIterator* ice_credentials) const {
if (!transport_desc_factory_)
return NULL;
const TransportDescription* offer_tdesc =
@@ -1805,7 +1814,7 @@
GetTransportDescription(content_name, current_desc);
return transport_desc_factory_->CreateAnswer(offer_tdesc, transport_options,
require_transport_attributes,
- current_tdesc);
+ current_tdesc, ice_credentials);
}
bool MediaSessionDescriptionFactory::AddTransportAnswer(
@@ -1841,7 +1850,8 @@
const RtpHeaderExtensions& audio_rtp_extensions,
const AudioCodecs& audio_codecs,
StreamParamsVec* current_streams,
- SessionDescription* desc) const {
+ SessionDescription* desc,
+ IceCredentialsIterator* ice_credentials) const {
// Filter audio_codecs (which includes all codecs, with correctly remapped
// payload types) based on transceiver direction.
const AudioCodecs& supported_audio_codecs =
@@ -1897,7 +1907,7 @@
media_description_options.stopped, audio.release());
if (!AddTransportOffer(media_description_options.mid,
media_description_options.transport_options,
- current_description, desc)) {
+ current_description, desc, ice_credentials)) {
return false;
}
@@ -1912,7 +1922,8 @@
const RtpHeaderExtensions& video_rtp_extensions,
const VideoCodecs& video_codecs,
StreamParamsVec* current_streams,
- SessionDescription* desc) const {
+ SessionDescription* desc,
+ IceCredentialsIterator* ice_credentials) const {
cricket::SecurePolicy sdes_policy =
IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
: secure();
@@ -1966,7 +1977,7 @@
media_description_options.stopped, video.release());
if (!AddTransportOffer(media_description_options.mid,
media_description_options.transport_options,
- current_description, desc)) {
+ current_description, desc, ice_credentials)) {
return false;
}
return true;
@@ -1979,7 +1990,8 @@
const SessionDescription* current_description,
const DataCodecs& data_codecs,
StreamParamsVec* current_streams,
- SessionDescription* desc) const {
+ SessionDescription* desc,
+ IceCredentialsIterator* ice_credentials) const {
bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
std::unique_ptr<DataContentDescription> data(new DataContentDescription());
@@ -2033,7 +2045,7 @@
}
if (!AddTransportOffer(media_description_options.mid,
media_description_options.transport_options,
- current_description, desc)) {
+ current_description, desc, ice_credentials)) {
return false;
}
return true;
@@ -2061,15 +2073,16 @@
const TransportInfo* bundle_transport,
const AudioCodecs& audio_codecs,
StreamParamsVec* current_streams,
- SessionDescription* answer) const {
+ SessionDescription* answer,
+ IceCredentialsIterator* ice_credentials) const {
RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_AUDIO));
const AudioContentDescription* offer_audio_description =
offer_content->media_description()->as_audio();
- std::unique_ptr<TransportDescription> audio_transport(
- CreateTransportAnswer(media_description_options.mid, offer_description,
- media_description_options.transport_options,
- current_description, bundle_transport != nullptr));
+ std::unique_ptr<TransportDescription> audio_transport(CreateTransportAnswer(
+ media_description_options.mid, offer_description,
+ media_description_options.transport_options, current_description,
+ bundle_transport != nullptr, ice_credentials));
if (!audio_transport) {
return false;
}
@@ -2155,15 +2168,16 @@
const TransportInfo* bundle_transport,
const VideoCodecs& video_codecs,
StreamParamsVec* current_streams,
- SessionDescription* answer) const {
+ SessionDescription* answer,
+ IceCredentialsIterator* ice_credentials) const {
RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_VIDEO));
const VideoContentDescription* offer_video_description =
offer_content->media_description()->as_video();
- std::unique_ptr<TransportDescription> video_transport(
- CreateTransportAnswer(media_description_options.mid, offer_description,
- media_description_options.transport_options,
- current_description, bundle_transport != nullptr));
+ std::unique_ptr<TransportDescription> video_transport(CreateTransportAnswer(
+ media_description_options.mid, offer_description,
+ media_description_options.transport_options, current_description,
+ bundle_transport != nullptr, ice_credentials));
if (!video_transport) {
return false;
}
@@ -2241,11 +2255,12 @@
const TransportInfo* bundle_transport,
const DataCodecs& data_codecs,
StreamParamsVec* current_streams,
- SessionDescription* answer) const {
- std::unique_ptr<TransportDescription> data_transport(
- CreateTransportAnswer(media_description_options.mid, offer_description,
- media_description_options.transport_options,
- current_description, bundle_transport != nullptr));
+ SessionDescription* answer,
+ IceCredentialsIterator* ice_credentials) const {
+ std::unique_ptr<TransportDescription> data_transport(CreateTransportAnswer(
+ media_description_options.mid, offer_description,
+ media_description_options.transport_options, current_description,
+ bundle_transport != nullptr, ice_credentials));
if (!data_transport) {
return false;
}
diff --git a/pc/mediasession.h b/pc/mediasession.h
index 54ca7c8..b1df1db 100644
--- a/pc/mediasession.h
+++ b/pc/mediasession.h
@@ -21,6 +21,7 @@
#include "api/mediatypes.h"
#include "media/base/mediaconstants.h"
#include "media/base/mediaengine.h" // For DataChannelType
+#include "p2p/base/icecredentialsiterator.h"
#include "p2p/base/transportdescriptionfactory.h"
#include "pc/jseptransport.h"
#include "pc/sessiondescription.h"
@@ -98,6 +99,7 @@
// List of media description options in the same order that the media
// descriptions will be generated.
std::vector<MediaDescriptionOptions> media_description_options;
+ std::vector<IceParameters> pooled_ice_credentials;
};
// Creates media session descriptions according to the supplied codecs and
@@ -186,14 +188,16 @@
bool AddTransportOffer(const std::string& content_name,
const TransportOptions& transport_options,
const SessionDescription* current_desc,
- SessionDescription* offer) const;
+ SessionDescription* offer,
+ IceCredentialsIterator* ice_credentials) const;
TransportDescription* CreateTransportAnswer(
const std::string& content_name,
const SessionDescription* offer_desc,
const TransportOptions& transport_options,
const SessionDescription* current_desc,
- bool require_transport_attributes) const;
+ bool require_transport_attributes,
+ IceCredentialsIterator* ice_credentials) const;
bool AddTransportAnswer(const std::string& content_name,
const TransportDescription& transport_desc,
@@ -211,7 +215,8 @@
const RtpHeaderExtensions& audio_rtp_extensions,
const AudioCodecs& audio_codecs,
StreamParamsVec* current_streams,
- SessionDescription* desc) const;
+ SessionDescription* desc,
+ IceCredentialsIterator* ice_credentials) const;
bool AddVideoContentForOffer(
const MediaDescriptionOptions& media_description_options,
@@ -221,7 +226,8 @@
const RtpHeaderExtensions& video_rtp_extensions,
const VideoCodecs& video_codecs,
StreamParamsVec* current_streams,
- SessionDescription* desc) const;
+ SessionDescription* desc,
+ IceCredentialsIterator* ice_credentials) const;
bool AddDataContentForOffer(
const MediaDescriptionOptions& media_description_options,
@@ -230,7 +236,8 @@
const SessionDescription* current_description,
const DataCodecs& data_codecs,
StreamParamsVec* current_streams,
- SessionDescription* desc) const;
+ SessionDescription* desc,
+ IceCredentialsIterator* ice_credentials) const;
bool AddAudioContentForAnswer(
const MediaDescriptionOptions& media_description_options,
@@ -242,7 +249,8 @@
const TransportInfo* bundle_transport,
const AudioCodecs& audio_codecs,
StreamParamsVec* current_streams,
- SessionDescription* answer) const;
+ SessionDescription* answer,
+ IceCredentialsIterator* ice_credentials) const;
bool AddVideoContentForAnswer(
const MediaDescriptionOptions& media_description_options,
@@ -254,7 +262,8 @@
const TransportInfo* bundle_transport,
const VideoCodecs& video_codecs,
StreamParamsVec* current_streams,
- SessionDescription* answer) const;
+ SessionDescription* answer,
+ IceCredentialsIterator* ice_credentials) const;
bool AddDataContentForAnswer(
const MediaDescriptionOptions& media_description_options,
@@ -266,7 +275,8 @@
const TransportInfo* bundle_transport,
const DataCodecs& data_codecs,
StreamParamsVec* current_streams,
- SessionDescription* answer) const;
+ SessionDescription* answer,
+ IceCredentialsIterator* ice_credentials) const;
void ComputeAudioCodecsIntersectionAndUnion();
diff --git a/pc/peerconnection.cc b/pc/peerconnection.cc
index 659d16b..0861246 100644
--- a/pc/peerconnection.cc
+++ b/pc/peerconnection.cc
@@ -3646,6 +3646,11 @@
session_options->rtcp_cname = rtcp_cname_;
session_options->crypto_options = factory_->options().crypto_options;
session_options->is_unified_plan = IsUnifiedPlan();
+ session_options->pooled_ice_credentials =
+ network_thread()->Invoke<std::vector<cricket::IceParameters>>(
+ RTC_FROM_HERE,
+ rtc::Bind(&cricket::PortAllocator::GetPooledIceCredentials,
+ port_allocator_.get()));
}
void PeerConnection::GetOptionsForPlanBOffer(
@@ -3906,6 +3911,11 @@
session_options->rtcp_cname = rtcp_cname_;
session_options->crypto_options = factory_->options().crypto_options;
session_options->is_unified_plan = IsUnifiedPlan();
+ session_options->pooled_ice_credentials =
+ network_thread()->Invoke<std::vector<cricket::IceParameters>>(
+ RTC_FROM_HERE,
+ rtc::Bind(&cricket::PortAllocator::GetPooledIceCredentials,
+ port_allocator_.get()));
}
void PeerConnection::GetOptionsForPlanBAnswer(
diff --git a/pc/peerconnection_ice_unittest.cc b/pc/peerconnection_ice_unittest.cc
index e6d6ac1..4e25614 100644
--- a/pc/peerconnection_ice_unittest.cc
+++ b/pc/peerconnection_ice_unittest.cc
@@ -78,6 +78,9 @@
void set_network(rtc::FakeNetworkManager* network) { network_ = network; }
+ // The port allocator used by this PC.
+ cricket::PortAllocator* port_allocator_;
+
private:
rtc::FakeNetworkManager* network_;
};
@@ -115,6 +118,7 @@
RTCConfiguration modified_config = config;
modified_config.sdp_semantics = sdp_semantics_;
auto observer = absl::make_unique<MockPeerConnectionObserver>();
+ auto port_allocator_copy = port_allocator.get();
auto pc = pc_factory_->CreatePeerConnection(
modified_config, std::move(port_allocator), nullptr, observer.get());
if (!pc) {
@@ -124,6 +128,7 @@
auto wrapper = absl::make_unique<PeerConnectionWrapperForIceTest>(
pc_factory_, pc, std::move(observer));
wrapper->set_network(fake_network);
+ wrapper->port_allocator_ = port_allocator_copy;
return wrapper;
}
@@ -1008,4 +1013,41 @@
EXPECT_EQ(actual_stun_keepalive_interval.value_or(-1), 321);
}
+TEST_P(PeerConnectionIceTest, IceCredentialsCreateOffer) {
+ RTCConfiguration config;
+ config.ice_candidate_pool_size = 1;
+ auto pc = CreatePeerConnectionWithAudioVideo(config);
+ ASSERT_NE(pc->port_allocator_, nullptr);
+ auto offer = pc->CreateOffer();
+ auto credentials = pc->port_allocator_->GetPooledIceCredentials();
+ ASSERT_EQ(1u, credentials.size());
+
+ auto* desc = offer->description();
+ for (const auto& content : desc->contents()) {
+ auto* transport_info = desc->GetTransportInfoByName(content.name);
+ EXPECT_EQ(transport_info->description.ice_ufrag, credentials[0].ufrag);
+ EXPECT_EQ(transport_info->description.ice_pwd, credentials[0].pwd);
+ }
+}
+
+TEST_P(PeerConnectionIceTest, IceCredentialsCreateAnswer) {
+ RTCConfiguration config;
+ config.ice_candidate_pool_size = 1;
+ auto pc = CreatePeerConnectionWithAudioVideo(config);
+ ASSERT_NE(pc->port_allocator_, nullptr);
+ auto offer = pc->CreateOffer();
+ ASSERT_TRUE(pc->SetRemoteDescription(std::move(offer)));
+ auto answer = pc->CreateAnswer();
+
+ auto credentials = pc->port_allocator_->GetPooledIceCredentials();
+ ASSERT_EQ(1u, credentials.size());
+
+ auto* desc = answer->description();
+ for (const auto& content : desc->contents()) {
+ auto* transport_info = desc->GetTransportInfoByName(content.name);
+ EXPECT_EQ(transport_info->description.ice_ufrag, credentials[0].ufrag);
+ EXPECT_EQ(transport_info->description.ice_pwd, credentials[0].pwd);
+ }
+}
+
} // namespace webrtc