Improve IPv6 selection logic when gathering candidates.

- If there are more than 5 IPv6 networks, then diversify IPv6 interface types selection.
- Passing field_trial from peer_connection_factory.cc when creating BasicPortAllocator object.

Bug: webrtc:14334
Change-Id: I7d100d944f4e60414e3421f422997bc3f168cc24
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/271581
Reviewed-by: Per Kjellander <perkj@webrtc.org>
Reviewed-by: Jonas Oreland <jonaso@webrtc.org>
Commit-Queue: Diep Bui <diepbp@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#37924}
This commit is contained in:
Diep Bui 2022-08-26 15:43:44 +00:00 committed by WebRTC LUCI CQ
parent 4b6819434d
commit 9068f456a3
4 changed files with 430 additions and 47 deletions

View File

@ -31,8 +31,10 @@
#include "p2p/base/turn_port.h"
#include "p2p/base/udp_port.h"
#include "rtc_base/checks.h"
#include "rtc_base/experiments/field_trial_parser.h"
#include "rtc_base/helpers.h"
#include "rtc_base/logging.h"
#include "rtc_base/network_constants.h"
#include "rtc_base/strings/string_builder.h"
#include "rtc_base/trace_event.h"
#include "system_wrappers/include/metrics.h"
@ -152,6 +154,21 @@ std::string NetworksToString(const std::vector<const rtc::Network*>& networks) {
return ost.Release();
}
bool IsDiversifyIpv6InterfacesEnabled(
const webrtc::FieldTrialsView* field_trials) {
// webrtc:14334: Improve IPv6 network resolution and candidate creation
if (field_trials &&
field_trials->IsEnabled("WebRTC-IPv6NetworkResolutionFixes")) {
webrtc::FieldTrialParameter<bool> diversify_ipv6_interfaces(
"DiversifyIpv6Interfaces", false);
webrtc::ParseFieldTrial(
{&diversify_ipv6_interfaces},
field_trials->Lookup("WebRTC-IPv6NetworkResolutionFixes"));
return diversify_ipv6_interfaces;
}
return false;
}
} // namespace
const uint32_t DISABLE_ALL_PHASES =
@ -163,9 +180,12 @@ BasicPortAllocator::BasicPortAllocator(
rtc::NetworkManager* network_manager,
rtc::PacketSocketFactory* socket_factory,
webrtc::TurnCustomizer* customizer,
RelayPortFactoryInterface* relay_port_factory)
: network_manager_(network_manager), socket_factory_(socket_factory) {
Init(relay_port_factory, nullptr);
RelayPortFactoryInterface* relay_port_factory,
const webrtc::FieldTrialsView* field_trials)
: field_trials_(field_trials),
network_manager_(network_manager),
socket_factory_(socket_factory) {
Init(relay_port_factory);
RTC_DCHECK(relay_port_factory_ != nullptr);
RTC_DCHECK(network_manager_ != nullptr);
RTC_CHECK(socket_factory_ != nullptr);
@ -175,10 +195,12 @@ BasicPortAllocator::BasicPortAllocator(
BasicPortAllocator::BasicPortAllocator(
rtc::NetworkManager* network_manager,
std::unique_ptr<rtc::PacketSocketFactory> owned_socket_factory)
: network_manager_(network_manager),
std::unique_ptr<rtc::PacketSocketFactory> owned_socket_factory,
const webrtc::FieldTrialsView* field_trials)
: field_trials_(field_trials),
network_manager_(network_manager),
socket_factory_(std::move(owned_socket_factory)) {
Init(nullptr, nullptr);
Init(nullptr);
RTC_DCHECK(relay_port_factory_ != nullptr);
RTC_DCHECK(network_manager_ != nullptr);
RTC_CHECK(socket_factory_ != nullptr);
@ -187,10 +209,12 @@ BasicPortAllocator::BasicPortAllocator(
BasicPortAllocator::BasicPortAllocator(
rtc::NetworkManager* network_manager,
std::unique_ptr<rtc::PacketSocketFactory> owned_socket_factory,
const ServerAddresses& stun_servers)
: network_manager_(network_manager),
const ServerAddresses& stun_servers,
const webrtc::FieldTrialsView* field_trials)
: field_trials_(field_trials),
network_manager_(network_manager),
socket_factory_(std::move(owned_socket_factory)) {
Init(nullptr, nullptr);
Init(nullptr);
RTC_DCHECK(relay_port_factory_ != nullptr);
RTC_DCHECK(network_manager_ != nullptr);
RTC_CHECK(socket_factory_ != nullptr);
@ -198,11 +222,15 @@ BasicPortAllocator::BasicPortAllocator(
webrtc::NO_PRUNE, nullptr);
}
BasicPortAllocator::BasicPortAllocator(rtc::NetworkManager* network_manager,
rtc::PacketSocketFactory* socket_factory,
const ServerAddresses& stun_servers)
: network_manager_(network_manager), socket_factory_(socket_factory) {
Init(nullptr, nullptr);
BasicPortAllocator::BasicPortAllocator(
rtc::NetworkManager* network_manager,
rtc::PacketSocketFactory* socket_factory,
const ServerAddresses& stun_servers,
const webrtc::FieldTrialsView* field_trials)
: field_trials_(field_trials),
network_manager_(network_manager),
socket_factory_(socket_factory) {
Init(nullptr);
RTC_DCHECK(relay_port_factory_ != nullptr);
RTC_DCHECK(network_manager_ != nullptr);
RTC_CHECK(socket_factory_ != nullptr);
@ -278,21 +306,13 @@ void BasicPortAllocator::AddTurnServer(const RelayServerConfig& turn_server) {
turn_port_prune_policy(), turn_customizer());
}
void BasicPortAllocator::Init(RelayPortFactoryInterface* relay_port_factory,
const webrtc::FieldTrialsView* field_trials) {
void BasicPortAllocator::Init(RelayPortFactoryInterface* relay_port_factory) {
if (relay_port_factory != nullptr) {
relay_port_factory_ = relay_port_factory;
} else {
default_relay_port_factory_.reset(new TurnPortFactory());
relay_port_factory_ = default_relay_port_factory_.get();
}
if (field_trials != nullptr) {
field_trials_ = field_trials;
} else {
owned_field_trials_ = std::make_unique<webrtc::FieldTrialBasedConfig>();
field_trials_ = owned_field_trials_.get();
}
}
// BasicPortAllocatorSession
@ -795,21 +815,75 @@ std::vector<const rtc::Network*> BasicPortAllocatorSession::GetNetworks() {
// hard to define what that means though; it's not just "lowest cost".
// Alternatively, we could just focus on making our ICE pinging logic smarter
// such that this filtering isn't necessary in the first place.
int ipv6_networks = 0;
for (auto it = networks.begin(); it != networks.end();) {
if ((*it)->prefix().family() == AF_INET6) {
if (ipv6_networks >= allocator_->max_ipv6_networks()) {
const webrtc::FieldTrialsView* field_trials = allocator_->field_trials();
if (IsDiversifyIpv6InterfacesEnabled(field_trials)) {
std::vector<const rtc::Network*> ipv6_networks;
for (auto it = networks.begin(); it != networks.end();) {
if ((*it)->prefix().family() == AF_INET6) {
ipv6_networks.push_back(*it);
it = networks.erase(it);
continue;
} else {
++ipv6_networks;
}
++it;
}
ipv6_networks =
SelectIPv6Networks(ipv6_networks, allocator_->max_ipv6_networks());
networks.insert(networks.end(), ipv6_networks.begin(), ipv6_networks.end());
} else {
int ipv6_networks = 0;
for (auto it = networks.begin(); it != networks.end();) {
if ((*it)->prefix().family() == AF_INET6) {
if (ipv6_networks >= allocator_->max_ipv6_networks()) {
it = networks.erase(it);
continue;
} else {
++ipv6_networks;
}
}
++it;
}
++it;
}
return networks;
}
std::vector<const rtc::Network*> BasicPortAllocatorSession::SelectIPv6Networks(
std::vector<const rtc::Network*>& all_ipv6_networks,
int max_ipv6_networks) {
if (static_cast<int>(all_ipv6_networks.size()) <= max_ipv6_networks) {
return all_ipv6_networks;
}
// Adapter types are placed in priority order. Cellular type is an alias of
// cellular, 2G..5G types.
std::vector<rtc::AdapterType> adapter_types = {
rtc::ADAPTER_TYPE_ETHERNET, rtc::ADAPTER_TYPE_LOOPBACK,
rtc::ADAPTER_TYPE_WIFI, rtc::ADAPTER_TYPE_CELLULAR,
rtc::ADAPTER_TYPE_VPN, rtc::ADAPTER_TYPE_UNKNOWN,
rtc::ADAPTER_TYPE_ANY};
int adapter_types_cnt = adapter_types.size();
std::vector<const rtc::Network*> selected_networks;
int adapter_types_pos = 0;
while (static_cast<int>(selected_networks.size()) < max_ipv6_networks &&
adapter_types_pos < adapter_types_cnt * max_ipv6_networks) {
int network_pos = 0;
while (network_pos < static_cast<int>(all_ipv6_networks.size())) {
if (adapter_types[adapter_types_pos % adapter_types_cnt] ==
all_ipv6_networks[network_pos]->type() ||
(adapter_types[adapter_types_pos % adapter_types_cnt] ==
rtc::ADAPTER_TYPE_CELLULAR &&
all_ipv6_networks[network_pos]->IsCellular())) {
selected_networks.push_back(all_ipv6_networks[network_pos]);
all_ipv6_networks.erase(all_ipv6_networks.begin() + network_pos);
break;
}
network_pos++;
}
adapter_types_pos++;
}
return selected_networks;
}
// For each network, see if we have a sequence that covers it already. If not,
// create a new sequence to create the appropriate ports.
void BasicPortAllocatorSession::DoAllocate(bool disable_equivalent) {

View File

@ -39,17 +39,21 @@ class RTC_EXPORT BasicPortAllocator : public PortAllocator {
BasicPortAllocator(rtc::NetworkManager* network_manager,
rtc::PacketSocketFactory* socket_factory,
webrtc::TurnCustomizer* customizer = nullptr,
RelayPortFactoryInterface* relay_port_factory = nullptr);
BasicPortAllocator(
rtc::NetworkManager* network_manager,
std::unique_ptr<rtc::PacketSocketFactory> owned_socket_factory);
RelayPortFactoryInterface* relay_port_factory = nullptr,
const webrtc::FieldTrialsView* field_trials = nullptr);
BasicPortAllocator(
rtc::NetworkManager* network_manager,
std::unique_ptr<rtc::PacketSocketFactory> owned_socket_factory,
const ServerAddresses& stun_servers);
const webrtc::FieldTrialsView* field_trials = nullptr);
BasicPortAllocator(
rtc::NetworkManager* network_manager,
std::unique_ptr<rtc::PacketSocketFactory> owned_socket_factory,
const ServerAddresses& stun_servers,
const webrtc::FieldTrialsView* field_trials = nullptr);
BasicPortAllocator(rtc::NetworkManager* network_manager,
rtc::PacketSocketFactory* socket_factory,
const ServerAddresses& stun_servers);
const ServerAddresses& stun_servers,
const webrtc::FieldTrialsView* field_trials = nullptr);
~BasicPortAllocator() override;
// Set to kDefaultNetworkIgnoreMask by default.
@ -84,21 +88,22 @@ class RTC_EXPORT BasicPortAllocator : public PortAllocator {
void SetVpnList(const std::vector<rtc::NetworkMask>& vpn_list) override;
const webrtc::FieldTrialsView* field_trials() const { return field_trials_; }
const webrtc::FieldTrialsView* field_trials() const {
return field_trials_.get();
}
private:
void OnIceRegathering(PortAllocatorSession* session,
IceRegatheringReason reason);
// This function makes sure that relay_port_factory_ and field_trials_ is set
// properly.
void Init(RelayPortFactoryInterface* relay_port_factory,
const webrtc::FieldTrialsView* field_trials);
// This function makes sure that relay_port_factory_ is set properly.
void Init(RelayPortFactoryInterface* relay_port_factory);
bool MdnsObfuscationEnabled() const override;
const webrtc::FieldTrialsView* field_trials_;
std::unique_ptr<webrtc::FieldTrialsView> owned_field_trials_;
webrtc::AlwaysValidPointer<const webrtc::FieldTrialsView,
webrtc::FieldTrialBasedConfig>
field_trials_;
rtc::NetworkManager* network_manager_;
const webrtc::AlwaysValidPointerNoDefault<rtc::PacketSocketFactory>
socket_factory_;
@ -163,6 +168,9 @@ class RTC_EXPORT BasicPortAllocatorSession : public PortAllocatorSession {
void SetStunKeepaliveIntervalForReadyPorts(
const absl::optional<int>& stun_keepalive_interval) override;
void PruneAllPorts() override;
static std::vector<const rtc::Network*> SelectIPv6Networks(
std::vector<const rtc::Network*>& all_ipv6_networks,
int max_ipv6_networks);
protected:
void UpdateIceParametersInternal() override;

View File

@ -72,6 +72,12 @@ static const SocketAddress kClientIPv6Addr2(
static const SocketAddress kClientIPv6Addr3(
"2401:fa00:4:3000:be30:5bff:fee5:c3",
0);
static const SocketAddress kClientIPv6Addr4(
"2401:fa00:4:4000:be30:5bff:fee5:c3",
0);
static const SocketAddress kClientIPv6Addr5(
"2401:fa00:4:5000:be30:5bff:fee5:c3",
0);
static const SocketAddress kNatUdpAddr("77.77.77.77", rtc::NAT_SERVER_UDP_PORT);
static const SocketAddress kNatTcpAddr("77.77.77.77", rtc::NAT_SERVER_TCP_PORT);
static const SocketAddress kRemoteClientAddr("22.22.22.22", 0);
@ -165,7 +171,7 @@ class BasicPortAllocatorTestBase : public ::testing::Test,
allocator_ = std::make_unique<BasicPortAllocator>(
&network_manager_,
std::make_unique<rtc::BasicPacketSocketFactory>(fss_.get()),
stun_servers);
stun_servers, &field_trials_);
allocator_->Initialize();
allocator_->set_step_delay(kMinimumStepDelay);
webrtc::metrics::Reset();
@ -375,6 +381,17 @@ class BasicPortAllocatorTestBase : public ::testing::Test,
return (addr.port() >= min_port && addr.port() <= max_port);
}
static bool HasNetwork(const std::vector<const rtc::Network*>& networks,
const rtc::Network& to_be_found) {
auto it =
absl::c_find_if(networks, [to_be_found](const rtc::Network* network) {
return network->description() == to_be_found.description() &&
network->name() == to_be_found.name() &&
network->prefix() == to_be_found.prefix();
});
return it != networks.end();
}
void OnCandidatesAllocationDone(PortAllocatorSession* session) {
// We should only get this callback once, except in the mux test where
// we have multiple port allocation sessions.
@ -486,8 +503,9 @@ class BasicPortAllocatorTestBase : public ::testing::Test,
if (!stun_server.IsNil()) {
stun_servers.insert(stun_server);
}
allocator_.reset(new BasicPortAllocator(
&network_manager_, nat_socket_factory_.get(), stun_servers));
allocator_.reset(new BasicPortAllocator(&network_manager_,
nat_socket_factory_.get(),
stun_servers, &field_trials_));
allocator_->Initialize();
allocator_->set_step_delay(kMinimumStepDelay);
}
@ -506,6 +524,7 @@ class BasicPortAllocatorTestBase : public ::testing::Test,
std::vector<PortInterface*> ports_;
std::vector<Candidate> candidates_;
bool candidate_allocation_done_;
webrtc::test::ScopedKeyValueConfig field_trials_;
};
class BasicPortAllocatorTestWithRealClock : public BasicPortAllocatorTestBase {
@ -2472,4 +2491,284 @@ TEST_F(BasicPortAllocatorTest, TestDoNotUseTurnServerAsStunSever) {
EXPECT_EQ(1U, port_config.StunServers().size());
}
// Test that no more than allocator.max_ipv6_networks() IPv6 networks are used
// to gather candidates.
TEST_F(BasicPortAllocatorTest, TwoIPv6AreSelectedBecauseOfMaxIpv6Limit) {
rtc::Network wifi1("wifi1", "Test NetworkAdapter 1", kClientIPv6Addr.ipaddr(),
64, rtc::ADAPTER_TYPE_WIFI);
rtc::Network ethe1("ethe1", "Test NetworkAdapter 2",
kClientIPv6Addr2.ipaddr(), 64, rtc::ADAPTER_TYPE_ETHERNET);
rtc::Network wifi2("wifi2", "Test NetworkAdapter 3",
kClientIPv6Addr3.ipaddr(), 64, rtc::ADAPTER_TYPE_WIFI);
std::vector<const rtc::Network*> networks = {&wifi1, &ethe1, &wifi2};
// Ensure that only 2 interfaces were selected.
EXPECT_EQ(2U, BasicPortAllocatorSession::SelectIPv6Networks(
networks, /*max_ipv6_networks=*/2)
.size());
}
// Test that if the number of available IPv6 networks is less than
// allocator.max_ipv6_networks(), all IPv6 networks will be selected.
TEST_F(BasicPortAllocatorTest, AllIPv6AreSelected) {
rtc::Network wifi1("wifi1", "Test NetworkAdapter 1", kClientIPv6Addr.ipaddr(),
64, rtc::ADAPTER_TYPE_WIFI);
rtc::Network ethe1("ethe1", "Test NetworkAdapter 2",
kClientIPv6Addr2.ipaddr(), 64, rtc::ADAPTER_TYPE_ETHERNET);
std::vector<const rtc::Network*> networks = {&wifi1, &ethe1};
// Ensure that all 2 interfaces were selected.
EXPECT_EQ(2U, BasicPortAllocatorSession::SelectIPv6Networks(
networks, /*max_ipv6_networks=*/3)
.size());
}
// If there are some IPv6 networks with different types, diversify IPv6
// networks.
TEST_F(BasicPortAllocatorTest, TwoIPv6WifiAreSelectedIfThereAreTwo) {
rtc::Network wifi1("wifi1", "Test NetworkAdapter 1", kClientIPv6Addr.ipaddr(),
64, rtc::ADAPTER_TYPE_WIFI);
rtc::Network ethe1("ethe1", "Test NetworkAdapter 2",
kClientIPv6Addr2.ipaddr(), 64, rtc::ADAPTER_TYPE_ETHERNET);
rtc::Network ethe2("ethe2", "Test NetworkAdapter 3",
kClientIPv6Addr3.ipaddr(), 64, rtc::ADAPTER_TYPE_ETHERNET);
rtc::Network unknown1("unknown1", "Test NetworkAdapter 4",
kClientIPv6Addr2.ipaddr(), 64,
rtc::ADAPTER_TYPE_UNKNOWN);
rtc::Network cell1("cell1", "Test NetworkAdapter 5",
kClientIPv6Addr3.ipaddr(), 64,
rtc::ADAPTER_TYPE_CELLULAR_4G);
std::vector<const rtc::Network*> networks = {&wifi1, &ethe1, &ethe2,
&unknown1, &cell1};
networks = BasicPortAllocatorSession::SelectIPv6Networks(
networks, /*max_ipv6_networks=*/4);
EXPECT_EQ(4U, networks.size());
// Ensure the expected 4 interfaces (wifi1, ethe1, cell1, unknown1) were
// selected.
EXPECT_TRUE(HasNetwork(networks, wifi1));
EXPECT_TRUE(HasNetwork(networks, ethe1));
EXPECT_TRUE(HasNetwork(networks, cell1));
EXPECT_TRUE(HasNetwork(networks, unknown1));
}
// If there are some IPv6 networks with the same type, select them because there
// is no other option.
TEST_F(BasicPortAllocatorTest, IPv6WithSameTypeAreSelectedIfNoOtherOption) {
// Add 5 cellular interfaces
rtc::Network cell1("cell1", "Test NetworkAdapter 1", kClientIPv6Addr.ipaddr(),
64, rtc::ADAPTER_TYPE_CELLULAR_2G);
rtc::Network cell2("cell2", "Test NetworkAdapter 2",
kClientIPv6Addr2.ipaddr(), 64,
rtc::ADAPTER_TYPE_CELLULAR_3G);
rtc::Network cell3("cell3", "Test NetworkAdapter 3",
kClientIPv6Addr3.ipaddr(), 64,
rtc::ADAPTER_TYPE_CELLULAR_4G);
rtc::Network cell4("cell4", "Test NetworkAdapter 4",
kClientIPv6Addr2.ipaddr(), 64,
rtc::ADAPTER_TYPE_CELLULAR_5G);
rtc::Network cell5("cell5", "Test NetworkAdapter 5",
kClientIPv6Addr3.ipaddr(), 64,
rtc::ADAPTER_TYPE_CELLULAR_3G);
std::vector<const rtc::Network*> networks = {&cell1, &cell2, &cell3, &cell4,
&cell5};
// Ensure that 4 interfaces were selected.
EXPECT_EQ(4U, BasicPortAllocatorSession::SelectIPv6Networks(
networks, /*max_ipv6_networks=*/4)
.size());
}
TEST_F(BasicPortAllocatorTest, IPv6EthernetHasHigherPriorityThanWifi) {
rtc::Network wifi1("wifi1", "Test NetworkAdapter 1", kClientIPv6Addr.ipaddr(),
64, rtc::ADAPTER_TYPE_WIFI);
rtc::Network ethe1("ethe1", "Test NetworkAdapter 2",
kClientIPv6Addr2.ipaddr(), 64, rtc::ADAPTER_TYPE_ETHERNET);
rtc::Network wifi2("wifi2", "Test NetworkAdapter 3",
kClientIPv6Addr3.ipaddr(), 64, rtc::ADAPTER_TYPE_WIFI);
std::vector<const rtc::Network*> networks = {&wifi1, &ethe1, &wifi2};
networks = BasicPortAllocatorSession::SelectIPv6Networks(
networks, /*max_ipv6_networks=*/1);
EXPECT_EQ(1U, networks.size());
// Ensure ethe1 was selected.
EXPECT_TRUE(HasNetwork(networks, ethe1));
}
TEST_F(BasicPortAllocatorTest, IPv6EtherAndWifiHaveHigherPriorityThanOthers) {
rtc::Network cell1("cell1", "Test NetworkAdapter 1", kClientIPv6Addr.ipaddr(),
64, rtc::ADAPTER_TYPE_CELLULAR_3G);
rtc::Network ethe1("ethe1", "Test NetworkAdapter 2",
kClientIPv6Addr2.ipaddr(), 64, rtc::ADAPTER_TYPE_ETHERNET);
rtc::Network wifi1("wifi1", "Test NetworkAdapter 3",
kClientIPv6Addr3.ipaddr(), 64, rtc::ADAPTER_TYPE_WIFI);
rtc::Network unknown("unknown", "Test NetworkAdapter 4",
kClientIPv6Addr2.ipaddr(), 64,
rtc::ADAPTER_TYPE_UNKNOWN);
rtc::Network vpn1("vpn1", "Test NetworkAdapter 5", kClientIPv6Addr3.ipaddr(),
64, rtc::ADAPTER_TYPE_VPN);
std::vector<const rtc::Network*> networks = {&cell1, &ethe1, &wifi1, &unknown,
&vpn1};
networks = BasicPortAllocatorSession::SelectIPv6Networks(
networks, /*max_ipv6_networks=*/2);
EXPECT_EQ(2U, networks.size());
// Ensure ethe1 and wifi1 were selected.
EXPECT_TRUE(HasNetwork(networks, wifi1));
EXPECT_TRUE(HasNetwork(networks, ethe1));
}
// Do not change the default IPv6 selection behavior if
// IPv6NetworkResolutionFixes is disabled.
TEST_F(BasicPortAllocatorTest,
NotDiversifyIPv6NetworkTypesIfIPv6NetworkResolutionFixesDisabled) {
webrtc::test::ScopedKeyValueConfig field_trials(
field_trials_, "WebRTC-IPv6NetworkResolutionFixes/Disabled/");
// Add three IPv6 network interfaces, but tell the allocator to only use two.
allocator().set_max_ipv6_networks(2);
AddInterface(kClientIPv6Addr, "ethe1", rtc::ADAPTER_TYPE_ETHERNET);
AddInterface(kClientIPv6Addr2, "ethe2", rtc::ADAPTER_TYPE_ETHERNET);
AddInterface(kClientIPv6Addr3, "wifi1", rtc::ADAPTER_TYPE_WIFI);
// To simplify the test, only gather UDP host candidates.
allocator().set_flags(PORTALLOCATOR_ENABLE_IPV6 | PORTALLOCATOR_DISABLE_TCP |
PORTALLOCATOR_DISABLE_STUN |
PORTALLOCATOR_DISABLE_RELAY |
PORTALLOCATOR_ENABLE_IPV6_ON_WIFI);
ASSERT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
session_->StartGettingPorts();
EXPECT_TRUE_SIMULATED_WAIT(candidate_allocation_done_,
kDefaultAllocationTimeout, fake_clock);
EXPECT_EQ(2U, candidates_.size());
// Wifi1 was not selected because it comes after ethe1 and ethe2.
EXPECT_FALSE(HasCandidate(candidates_, "local", "udp", kClientIPv6Addr3));
}
// Do not change the default IPv6 selection behavior if
// IPv6NetworkResolutionFixes is enabled but DiversifyIpv6Interfaces is not
// enabled.
TEST_F(BasicPortAllocatorTest,
NotDiversifyIPv6NetworkTypesIfDiversifyIpv6InterfacesDisabled) {
webrtc::test::ScopedKeyValueConfig field_trials(
field_trials_,
"WebRTC-IPv6NetworkResolutionFixes/"
"Enabled,DiversifyIpv6Interfaces:false/");
// Add three IPv6 network interfaces, but tell the allocator to only use two.
allocator().set_max_ipv6_networks(2);
AddInterface(kClientIPv6Addr, "ethe1", rtc::ADAPTER_TYPE_ETHERNET);
AddInterface(kClientIPv6Addr2, "ethe2", rtc::ADAPTER_TYPE_ETHERNET);
AddInterface(kClientIPv6Addr3, "wifi1", rtc::ADAPTER_TYPE_WIFI);
// To simplify the test, only gather UDP host candidates.
allocator().set_flags(PORTALLOCATOR_ENABLE_IPV6 | PORTALLOCATOR_DISABLE_TCP |
PORTALLOCATOR_DISABLE_STUN |
PORTALLOCATOR_DISABLE_RELAY |
PORTALLOCATOR_ENABLE_IPV6_ON_WIFI);
ASSERT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
session_->StartGettingPorts();
EXPECT_TRUE_SIMULATED_WAIT(candidate_allocation_done_,
kDefaultAllocationTimeout, fake_clock);
EXPECT_EQ(2U, candidates_.size());
// Wifi1 was not selected because it comes after ethe1 and ethe2.
EXPECT_FALSE(HasCandidate(candidates_, "local", "udp", kClientIPv6Addr3));
}
TEST_F(BasicPortAllocatorTest,
Select2DifferentIntefacesIfDiversifyIpv6InterfacesEnabled) {
webrtc::test::ScopedKeyValueConfig field_trials(
field_trials_,
"WebRTC-IPv6NetworkResolutionFixes/"
"Enabled,DiversifyIpv6Interfaces:true/");
allocator().set_max_ipv6_networks(2);
AddInterface(kClientIPv6Addr, "ethe1", rtc::ADAPTER_TYPE_ETHERNET);
AddInterface(kClientIPv6Addr2, "ethe2", rtc::ADAPTER_TYPE_ETHERNET);
AddInterface(kClientIPv6Addr3, "wifi1", rtc::ADAPTER_TYPE_WIFI);
AddInterface(kClientIPv6Addr4, "wifi2", rtc::ADAPTER_TYPE_WIFI);
AddInterface(kClientIPv6Addr5, "cell1", rtc::ADAPTER_TYPE_CELLULAR_3G);
// To simplify the test, only gather UDP host candidates.
allocator().set_flags(PORTALLOCATOR_ENABLE_IPV6 | PORTALLOCATOR_DISABLE_TCP |
PORTALLOCATOR_DISABLE_STUN |
PORTALLOCATOR_DISABLE_RELAY |
PORTALLOCATOR_ENABLE_IPV6_ON_WIFI);
ASSERT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
session_->StartGettingPorts();
EXPECT_TRUE_SIMULATED_WAIT(candidate_allocation_done_,
kDefaultAllocationTimeout, fake_clock);
EXPECT_EQ(2U, candidates_.size());
// ethe1 and wifi1 were selected.
EXPECT_TRUE(HasCandidate(candidates_, "local", "udp", kClientIPv6Addr));
EXPECT_TRUE(HasCandidate(candidates_, "local", "udp", kClientIPv6Addr3));
}
TEST_F(BasicPortAllocatorTest,
Select3DifferentIntefacesIfDiversifyIpv6InterfacesEnabled) {
webrtc::test::ScopedKeyValueConfig field_trials(
field_trials_,
"WebRTC-IPv6NetworkResolutionFixes/"
"Enabled,DiversifyIpv6Interfaces:true/");
allocator().set_max_ipv6_networks(3);
AddInterface(kClientIPv6Addr, "ethe1", rtc::ADAPTER_TYPE_ETHERNET);
AddInterface(kClientIPv6Addr2, "ethe2", rtc::ADAPTER_TYPE_ETHERNET);
AddInterface(kClientIPv6Addr3, "wifi1", rtc::ADAPTER_TYPE_WIFI);
AddInterface(kClientIPv6Addr4, "wifi2", rtc::ADAPTER_TYPE_WIFI);
AddInterface(kClientIPv6Addr5, "cell1", rtc::ADAPTER_TYPE_CELLULAR_3G);
// To simplify the test, only gather UDP host candidates.
allocator().set_flags(PORTALLOCATOR_ENABLE_IPV6 | PORTALLOCATOR_DISABLE_TCP |
PORTALLOCATOR_DISABLE_STUN |
PORTALLOCATOR_DISABLE_RELAY |
PORTALLOCATOR_ENABLE_IPV6_ON_WIFI);
ASSERT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
session_->StartGettingPorts();
EXPECT_TRUE_SIMULATED_WAIT(candidate_allocation_done_,
kDefaultAllocationTimeout, fake_clock);
EXPECT_EQ(3U, candidates_.size());
// ethe1, wifi1, and cell1 were selected.
EXPECT_TRUE(HasCandidate(candidates_, "local", "udp", kClientIPv6Addr));
EXPECT_TRUE(HasCandidate(candidates_, "local", "udp", kClientIPv6Addr3));
EXPECT_TRUE(HasCandidate(candidates_, "local", "udp", kClientIPv6Addr5));
}
TEST_F(BasicPortAllocatorTest,
Select4DifferentIntefacesIfDiversifyIpv6InterfacesEnabled) {
webrtc::test::ScopedKeyValueConfig field_trials(
field_trials_,
"WebRTC-IPv6NetworkResolutionFixes/"
"Enabled,DiversifyIpv6Interfaces:true/");
allocator().set_max_ipv6_networks(4);
AddInterface(kClientIPv6Addr, "ethe1", rtc::ADAPTER_TYPE_ETHERNET);
AddInterface(kClientIPv6Addr2, "ethe2", rtc::ADAPTER_TYPE_ETHERNET);
AddInterface(kClientIPv6Addr3, "wifi1", rtc::ADAPTER_TYPE_WIFI);
AddInterface(kClientIPv6Addr4, "wifi2", rtc::ADAPTER_TYPE_WIFI);
AddInterface(kClientIPv6Addr5, "cell1", rtc::ADAPTER_TYPE_CELLULAR_3G);
// To simplify the test, only gather UDP host candidates.
allocator().set_flags(PORTALLOCATOR_ENABLE_IPV6 | PORTALLOCATOR_DISABLE_TCP |
PORTALLOCATOR_DISABLE_STUN |
PORTALLOCATOR_DISABLE_RELAY |
PORTALLOCATOR_ENABLE_IPV6_ON_WIFI);
ASSERT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
session_->StartGettingPorts();
EXPECT_TRUE_SIMULATED_WAIT(candidate_allocation_done_,
kDefaultAllocationTimeout, fake_clock);
EXPECT_EQ(4U, candidates_.size());
// ethe1, ethe2, wifi1, and cell1 were selected.
EXPECT_TRUE(HasCandidate(candidates_, "local", "udp", kClientIPv6Addr));
EXPECT_TRUE(HasCandidate(candidates_, "local", "udp", kClientIPv6Addr2));
EXPECT_TRUE(HasCandidate(candidates_, "local", "udp", kClientIPv6Addr3));
EXPECT_TRUE(HasCandidate(candidates_, "local", "udp", kClientIPv6Addr5));
}
} // namespace cricket

View File

@ -212,9 +212,11 @@ PeerConnectionFactory::CreatePeerConnectionOrError(
network_thread());
}
if (!dependencies.allocator) {
const FieldTrialsView* trials =
dependencies.trials ? dependencies.trials.get() : &field_trials();
dependencies.allocator = std::make_unique<cricket::BasicPortAllocator>(
context_->default_network_manager(), context_->default_socket_factory(),
configuration.turn_customizer);
configuration.turn_customizer, /*relay_port_factory=*/nullptr, trials);
dependencies.allocator->SetPortRange(
configuration.port_allocator_config.min_port,
configuration.port_allocator_config.max_port);