Signal to remove remote candidates if ports are pruned.
Previously when a Turn port is pruned, if its candidate has been sent to the remote side, the remote side will keep the candidate and use that to create connections. We now signal the remote side to remove the candidates so that at least no new connection will be created using the removed candidates. Also updated the virtual socket server to better support our test cases. 1. Allow the virtual socket server to set transit delay for packets sent from a given IP address. 2. Ensure the ordered packet delivery for each socket (Previously the delivery order is enforced on the whole test case, so if a udp packet gets delayed based on its IP address, all TCP packets sent after the UDP packet will be delayed at least until the UDP packet is received). BUG=webrtc:6380 R=deadbeef@webrtc.org, pthatcher@webrtc.org, skvlad@webrtc.org Review URL: https://codereview.webrtc.org/2261523004 . Cr-Commit-Position: refs/heads/master@{#14297}
This commit is contained in:
parent
042041bf95
commit
c67e0f5753
@ -528,7 +528,6 @@ VirtualSocketServer::VirtualSocketServer(SocketServer* ss)
|
||||
server_owned_(false),
|
||||
msg_queue_(NULL),
|
||||
stop_on_idle_(false),
|
||||
network_delay_(0),
|
||||
next_ipv4_(kInitialNextIPv4),
|
||||
next_ipv6_(kInitialNextIPv6),
|
||||
next_port_(kFirstEphemeralPort),
|
||||
@ -541,7 +540,6 @@ VirtualSocketServer::VirtualSocketServer(SocketServer* ss)
|
||||
delay_mean_(0),
|
||||
delay_stddev_(0),
|
||||
delay_samples_(NUM_SAMPLES),
|
||||
delay_dist_(NULL),
|
||||
drop_prob_(0.0) {
|
||||
if (!server_) {
|
||||
server_ = new PhysicalSocketServer();
|
||||
@ -553,7 +551,6 @@ VirtualSocketServer::VirtualSocketServer(SocketServer* ss)
|
||||
VirtualSocketServer::~VirtualSocketServer() {
|
||||
delete bindings_;
|
||||
delete connections_;
|
||||
delete delay_dist_;
|
||||
if (server_owned_) {
|
||||
delete server_;
|
||||
}
|
||||
@ -781,7 +778,7 @@ static double Random() {
|
||||
int VirtualSocketServer::Connect(VirtualSocket* socket,
|
||||
const SocketAddress& remote_addr,
|
||||
bool use_delay) {
|
||||
uint32_t delay = use_delay ? GetRandomTransitDelay() : 0;
|
||||
uint32_t delay = use_delay ? GetTransitDelay(socket) : 0;
|
||||
VirtualSocket* remote = LookupBinding(remote_addr);
|
||||
if (!CanInteractWith(socket, remote)) {
|
||||
LOG(LS_INFO) << "Address family mismatch between "
|
||||
@ -803,7 +800,7 @@ bool VirtualSocketServer::Disconnect(VirtualSocket* socket) {
|
||||
if (socket) {
|
||||
// If we simulate packets being delayed, we should simulate the
|
||||
// equivalent of a FIN being delayed as well.
|
||||
uint32_t delay = GetRandomTransitDelay();
|
||||
uint32_t delay = GetTransitDelay(socket);
|
||||
// Remove the mapping.
|
||||
msg_queue_->PostDelayed(RTC_FROM_HERE, delay, socket, MSG_ID_DISCONNECT);
|
||||
return true;
|
||||
@ -947,7 +944,7 @@ void VirtualSocketServer::AddPacketToNetwork(VirtualSocket* sender,
|
||||
sender->network_.push_back(entry);
|
||||
|
||||
// Find the delay for crossing the many virtual hops of the network.
|
||||
uint32_t transit_delay = GetRandomTransitDelay();
|
||||
uint32_t transit_delay = GetTransitDelay(sender);
|
||||
|
||||
// When the incoming packet is from a binding of the any address, translate it
|
||||
// to the default route here such that the recipient will see the default
|
||||
@ -964,12 +961,12 @@ void VirtualSocketServer::AddPacketToNetwork(VirtualSocket* sender,
|
||||
int64_t ts = TimeAfter(send_delay + transit_delay);
|
||||
if (ordered) {
|
||||
// Ensure that new packets arrive after previous ones
|
||||
// TODO: consider ordering on a per-socket basis, since this
|
||||
// introduces artificial delay.
|
||||
ts = std::max(ts, network_delay_);
|
||||
ts = std::max(ts, sender->last_delivery_time_);
|
||||
// A socket should not have both ordered and unordered delivery, so its last
|
||||
// delivery time only needs to be updated when it has ordered delivery.
|
||||
sender->last_delivery_time_ = ts;
|
||||
}
|
||||
msg_queue_->PostAt(RTC_FROM_HERE, ts, recipient, MSG_ID_PACKET, p);
|
||||
network_delay_ = std::max(ts, network_delay_);
|
||||
}
|
||||
|
||||
void VirtualSocketServer::PurgeNetworkPackets(VirtualSocket* socket,
|
||||
@ -1016,8 +1013,7 @@ void VirtualSocketServer::UpdateDelayDistribution() {
|
||||
// We take a lock just to make sure we don't leak memory.
|
||||
{
|
||||
CritScope cs(&delay_crit_);
|
||||
delete delay_dist_;
|
||||
delay_dist_ = dist;
|
||||
delay_dist_.reset(dist);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1060,10 +1056,16 @@ VirtualSocketServer::Function* VirtualSocketServer::CreateDistribution(
|
||||
return Resample(Invert(Accumulate(f)), 0, 1, samples);
|
||||
}
|
||||
|
||||
uint32_t VirtualSocketServer::GetRandomTransitDelay() {
|
||||
uint32_t VirtualSocketServer::GetTransitDelay(Socket* socket) {
|
||||
// Use the delay based on the address if it is set.
|
||||
auto iter = delay_by_ip_.find(socket->GetLocalAddress().ipaddr());
|
||||
if (iter != delay_by_ip_.end()) {
|
||||
return static_cast<uint32_t>(iter->second);
|
||||
}
|
||||
// Otherwise, use the delay from the distribution distribution.
|
||||
size_t index = rand() % delay_dist_->size();
|
||||
double delay = (*delay_dist_)[index].second;
|
||||
//LOG_F(LS_INFO) << "random[" << index << "] = " << delay;
|
||||
// LOG_F(LS_INFO) << "random[" << index << "] = " << delay;
|
||||
return static_cast<uint32_t>(delay);
|
||||
}
|
||||
|
||||
|
||||
@ -112,6 +112,10 @@ class VirtualSocketServer : public SocketServer, public sigslot::has_slots<> {
|
||||
bool Wait(int cms, bool process_io) override;
|
||||
void WakeUp() override;
|
||||
|
||||
void SetDelayOnAddress(const rtc::SocketAddress& address, int delay_ms) {
|
||||
delay_by_ip_[address.ipaddr()] = delay_ms;
|
||||
}
|
||||
|
||||
typedef std::pair<double, double> Point;
|
||||
typedef std::vector<Point> Function;
|
||||
|
||||
@ -194,8 +198,10 @@ class VirtualSocketServer : public SocketServer, public sigslot::has_slots<> {
|
||||
// Computes the number of milliseconds required to send a packet of this size.
|
||||
uint32_t SendDelay(uint32_t size);
|
||||
|
||||
// Returns a random transit delay chosen from the appropriate distribution.
|
||||
uint32_t GetRandomTransitDelay();
|
||||
// If the delay has been set for the address of the socket, returns the set
|
||||
// delay. Otherwise, returns a random transit delay chosen from the
|
||||
// appropriate distribution.
|
||||
uint32_t GetTransitDelay(Socket* socket);
|
||||
|
||||
// Basic operations on functions. Those that return a function also take
|
||||
// ownership of the function given (and hence, may modify or delete it).
|
||||
@ -243,7 +249,6 @@ class VirtualSocketServer : public SocketServer, public sigslot::has_slots<> {
|
||||
bool server_owned_;
|
||||
MessageQueue* msg_queue_;
|
||||
bool stop_on_idle_;
|
||||
int64_t network_delay_;
|
||||
in_addr next_ipv4_;
|
||||
in6_addr next_ipv6_;
|
||||
uint16_t next_port_;
|
||||
@ -260,7 +265,10 @@ class VirtualSocketServer : public SocketServer, public sigslot::has_slots<> {
|
||||
uint32_t delay_mean_;
|
||||
uint32_t delay_stddev_;
|
||||
uint32_t delay_samples_;
|
||||
Function* delay_dist_;
|
||||
|
||||
std::map<rtc::IPAddress, int> delay_by_ip_;
|
||||
std::unique_ptr<Function> delay_dist_;
|
||||
|
||||
CriticalSection delay_crit_;
|
||||
|
||||
double drop_prob_;
|
||||
@ -358,6 +366,9 @@ class VirtualSocket : public AsyncSocket,
|
||||
// Network model that enforces bandwidth and capacity constraints
|
||||
NetworkQueue network_;
|
||||
size_t network_size_;
|
||||
// The scheduled delivery time of the last packet sent on this socket.
|
||||
// It is used to ensure ordered delivery of packets sent on this socket.
|
||||
int64_t last_delivery_time_ = 0;
|
||||
|
||||
// Data which has been received from the network
|
||||
RecvBuffer recv_buffer_;
|
||||
|
||||
@ -314,7 +314,12 @@ void BasicPortAllocatorSession::RegatherOnFailedNetworks() {
|
||||
}
|
||||
// Remove ports from being used locally and send signaling to remove
|
||||
// the candidates on the remote side.
|
||||
RemovePortsAndCandidates(failed_networks);
|
||||
std::vector<PortData*> ports_to_prune = GetUnprunedPorts(failed_networks);
|
||||
if (!ports_to_prune.empty()) {
|
||||
LOG(LS_INFO) << "Prune " << ports_to_prune.size()
|
||||
<< " ports because their networks failed";
|
||||
PrunePortsAndRemoveCandidates(ports_to_prune);
|
||||
}
|
||||
|
||||
if (allocation_started_ && network_manager_started_) {
|
||||
DoAllocate();
|
||||
@ -615,7 +620,12 @@ void BasicPortAllocatorSession::OnNetworksChanged() {
|
||||
failed_networks.push_back(sequence->network());
|
||||
}
|
||||
}
|
||||
RemovePortsAndCandidates(failed_networks);
|
||||
std::vector<PortData*> ports_to_prune = GetUnprunedPorts(failed_networks);
|
||||
if (!ports_to_prune.empty()) {
|
||||
LOG(LS_INFO) << "Prune " << ports_to_prune.size()
|
||||
<< " ports because their networks were gone";
|
||||
PrunePortsAndRemoveCandidates(ports_to_prune);
|
||||
}
|
||||
|
||||
if (!network_manager_started_) {
|
||||
LOG(LS_INFO) << "Network manager is started";
|
||||
@ -757,29 +767,32 @@ bool BasicPortAllocatorSession::PruneTurnPorts(Port* newly_pairable_turn_port) {
|
||||
RTC_CHECK(best_turn_port != nullptr);
|
||||
|
||||
bool pruned = false;
|
||||
std::vector<PortInterface*> pruned_ports;
|
||||
std::vector<PortData*> ports_to_prune;
|
||||
for (PortData& data : ports_) {
|
||||
if (data.port()->Network()->name() == network_name &&
|
||||
data.port()->Type() == RELAY_PORT_TYPE && !data.pruned() &&
|
||||
ComparePort(data.port(), best_turn_port) < 0) {
|
||||
data.set_pruned();
|
||||
pruned = true;
|
||||
data.port()->Prune();
|
||||
if (data.port() != newly_pairable_turn_port) {
|
||||
pruned_ports.push_back(data.port());
|
||||
// These ports will be pruned in PrunePortsAndRemoveCandidates.
|
||||
ports_to_prune.push_back(&data);
|
||||
} else {
|
||||
data.Prune();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!pruned_ports.empty()) {
|
||||
LOG(LS_INFO) << "Pruned " << pruned_ports.size() << " ports";
|
||||
SignalPortsPruned(this, pruned_ports);
|
||||
|
||||
if (!ports_to_prune.empty()) {
|
||||
LOG(LS_INFO) << "Prune " << ports_to_prune.size()
|
||||
<< " low-priority TURN ports";
|
||||
PrunePortsAndRemoveCandidates(ports_to_prune);
|
||||
}
|
||||
return pruned;
|
||||
}
|
||||
|
||||
void BasicPortAllocatorSession::PruneAllPorts() {
|
||||
for (PortData& data : ports_) {
|
||||
data.port()->Prune();
|
||||
data.Prune();
|
||||
}
|
||||
}
|
||||
|
||||
@ -942,32 +955,41 @@ BasicPortAllocatorSession::PortData* BasicPortAllocatorSession::FindPort(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Removes ports and candidates created on a given list of networks.
|
||||
void BasicPortAllocatorSession::RemovePortsAndCandidates(
|
||||
std::vector<BasicPortAllocatorSession::PortData*>
|
||||
BasicPortAllocatorSession::GetUnprunedPorts(
|
||||
const std::vector<rtc::Network*>& networks) {
|
||||
std::vector<PortInterface*> ports_to_remove;
|
||||
std::vector<Candidate> candidates_to_remove;
|
||||
for (PortData& data : ports_) {
|
||||
if (std::find(networks.begin(), networks.end(),
|
||||
data.sequence()->network()) == networks.end()) {
|
||||
continue;
|
||||
std::vector<PortData*> unpruned_ports;
|
||||
for (PortData& port : ports_) {
|
||||
if (!port.pruned() &&
|
||||
std::find(networks.begin(), networks.end(),
|
||||
port.sequence()->network()) != networks.end()) {
|
||||
unpruned_ports.push_back(&port);
|
||||
}
|
||||
}
|
||||
return unpruned_ports;
|
||||
}
|
||||
|
||||
void BasicPortAllocatorSession::PrunePortsAndRemoveCandidates(
|
||||
const std::vector<PortData*>& port_data_list) {
|
||||
std::vector<PortInterface*> pruned_ports;
|
||||
std::vector<Candidate> removed_candidates;
|
||||
for (PortData* data : port_data_list) {
|
||||
// Prune the port so that it may be destroyed.
|
||||
data.port()->Prune();
|
||||
ports_to_remove.push_back(data.port());
|
||||
if (data.has_pairable_candidate()) {
|
||||
GetCandidatesFromPort(data, &candidates_to_remove);
|
||||
data->Prune();
|
||||
pruned_ports.push_back(data->port());
|
||||
if (data->has_pairable_candidate()) {
|
||||
GetCandidatesFromPort(*data, &removed_candidates);
|
||||
// Mark the port as having no pairable candidates so that its candidates
|
||||
// won't be removed multiple times.
|
||||
data.set_has_pairable_candidate(false);
|
||||
data->set_has_pairable_candidate(false);
|
||||
}
|
||||
}
|
||||
if (!ports_to_remove.empty()) {
|
||||
LOG(LS_INFO) << "Removed " << ports_to_remove.size() << " ports";
|
||||
SignalPortsPruned(this, ports_to_remove);
|
||||
if (!pruned_ports.empty()) {
|
||||
SignalPortsPruned(this, pruned_ports);
|
||||
}
|
||||
if (!candidates_to_remove.empty()) {
|
||||
SignalCandidatesRemoved(this, candidates_to_remove);
|
||||
if (!removed_candidates.empty()) {
|
||||
LOG(LS_INFO) << "Removed " << removed_candidates.size() << " candidates";
|
||||
SignalCandidatesRemoved(this, removed_candidates);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -142,8 +142,13 @@ class BasicPortAllocatorSession : public PortAllocatorSession,
|
||||
return has_pairable_candidate_ && state_ != STATE_ERROR &&
|
||||
state_ != STATE_PRUNED;
|
||||
}
|
||||
|
||||
void set_pruned() { state_ = STATE_PRUNED; }
|
||||
// Sets the state to "PRUNED" and prunes the Port.
|
||||
void Prune() {
|
||||
state_ = STATE_PRUNED;
|
||||
if (port()) {
|
||||
port()->Prune();
|
||||
}
|
||||
}
|
||||
void set_has_pairable_candidate(bool has_pairable_candidate) {
|
||||
if (has_pairable_candidate) {
|
||||
ASSERT(state_ == STATE_INPROGRESS);
|
||||
@ -201,8 +206,12 @@ class BasicPortAllocatorSession : public PortAllocatorSession,
|
||||
// in order to avoid leaking any information.
|
||||
Candidate SanitizeRelatedAddress(const Candidate& c) const;
|
||||
|
||||
// Removes the ports and candidates on given networks.
|
||||
void RemovePortsAndCandidates(const std::vector<rtc::Network*>& networks);
|
||||
std::vector<PortData*> GetUnprunedPorts(
|
||||
const std::vector<rtc::Network*>& networks);
|
||||
// Prunes ports and signal the remote side to remove the candidates that
|
||||
// were previously signaled from these ports.
|
||||
void PrunePortsAndRemoveCandidates(
|
||||
const std::vector<PortData*>& port_data_list);
|
||||
// Gets filtered and sanitized candidates generated from a port and
|
||||
// append to |candidates|.
|
||||
void GetCandidatesFromPort(const PortData& data,
|
||||
|
||||
@ -79,7 +79,7 @@ static const char kIcePwd0[] = "TESTICEPWD00000000000000";
|
||||
|
||||
static const char kContentName[] = "test content";
|
||||
|
||||
static const int kDefaultAllocationTimeout = 1000;
|
||||
static const int kDefaultAllocationTimeout = 3000;
|
||||
static const char kTurnUsername[] = "test";
|
||||
static const char kTurnPassword[] = "test";
|
||||
|
||||
@ -243,6 +243,8 @@ class BasicPortAllocatorTest : public testing::Test,
|
||||
&BasicPortAllocatorTest::OnPortsPruned);
|
||||
session->SignalCandidatesReady.connect(
|
||||
this, &BasicPortAllocatorTest::OnCandidatesReady);
|
||||
session->SignalCandidatesRemoved.connect(
|
||||
this, &BasicPortAllocatorTest::OnCandidatesRemoved);
|
||||
session->SignalCandidatesAllocationDone.connect(
|
||||
this, &BasicPortAllocatorTest::OnCandidatesAllocationDone);
|
||||
return session;
|
||||
@ -404,6 +406,8 @@ class BasicPortAllocatorTest : public testing::Test,
|
||||
EXPECT_EQ(total_ports, ports_.size());
|
||||
}
|
||||
|
||||
rtc::VirtualSocketServer* virtual_socket_server() { return vss_.get(); }
|
||||
|
||||
protected:
|
||||
BasicPortAllocator& allocator() { return *allocator_; }
|
||||
|
||||
@ -446,6 +450,21 @@ class BasicPortAllocatorTest : public testing::Test,
|
||||
}
|
||||
}
|
||||
|
||||
void OnCandidatesRemoved(PortAllocatorSession* session,
|
||||
const std::vector<Candidate>& removed_candidates) {
|
||||
auto new_end = std::remove_if(
|
||||
candidates_.begin(), candidates_.end(),
|
||||
[removed_candidates](Candidate& candidate) {
|
||||
for (const Candidate& removed_candidate : removed_candidates) {
|
||||
if (candidate.MatchesForRemoval(removed_candidate)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
candidates_.erase(new_end, candidates_.end());
|
||||
}
|
||||
|
||||
bool HasRelayAddress(const ProtocolAddress& proto_addr) {
|
||||
for (size_t i = 0; i < allocator_->turn_servers().size(); ++i) {
|
||||
RelayServerConfig server_config = allocator_->turn_servers()[i];
|
||||
@ -479,6 +498,143 @@ class BasicPortAllocatorTest : public testing::Test,
|
||||
allocator().set_step_delay(kMinimumStepDelay);
|
||||
}
|
||||
|
||||
void TestUdpTurnPortPrunesTcpTurnPort() {
|
||||
turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TCP);
|
||||
AddInterface(kClientAddr);
|
||||
allocator_.reset(new BasicPortAllocator(&network_manager_));
|
||||
allocator_->SetConfiguration(allocator_->stun_servers(),
|
||||
allocator_->turn_servers(), 0, true);
|
||||
AddTurnServers(kTurnUdpIntAddr, kTurnTcpIntAddr);
|
||||
allocator_->set_step_delay(kMinimumStepDelay);
|
||||
allocator_->set_flags(allocator().flags() |
|
||||
PORTALLOCATOR_ENABLE_SHARED_SOCKET |
|
||||
PORTALLOCATOR_DISABLE_TCP);
|
||||
|
||||
EXPECT_TRUE(CreateSession(ICE_CANDIDATE_COMPONENT_RTP));
|
||||
session_->StartGettingPorts();
|
||||
EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
|
||||
// Only 2 ports (one STUN and one TURN) are actually being used.
|
||||
EXPECT_EQ(2U, session_->ReadyPorts().size());
|
||||
// We have verified that each port, when it is added to |ports_|, it is
|
||||
// found in |ready_ports|, and when it is pruned, it is not found in
|
||||
// |ready_ports|, so we only need to verify the content in one of them.
|
||||
EXPECT_EQ(2U, ports_.size());
|
||||
EXPECT_EQ(1, CountPorts(ports_, "local", PROTO_UDP, kClientAddr));
|
||||
EXPECT_EQ(1, CountPorts(ports_, "relay", PROTO_UDP, kClientAddr));
|
||||
EXPECT_EQ(0, CountPorts(ports_, "relay", PROTO_TCP, kClientAddr));
|
||||
|
||||
// Now that we remove candidates when a TURN port is pruned, |candidates_|
|
||||
// should only contains two candidates regardless whether the TCP TURN port
|
||||
// is created before or after the UDP turn port.
|
||||
EXPECT_EQ(2U, candidates_.size());
|
||||
// There will only be 2 candidates in |ready_candidates| because it only
|
||||
// includes the candidates in the ready ports.
|
||||
const std::vector<Candidate>& ready_candidates =
|
||||
session_->ReadyCandidates();
|
||||
EXPECT_EQ(2U, ready_candidates.size());
|
||||
EXPECT_PRED4(HasCandidate, ready_candidates, "local", "udp", kClientAddr);
|
||||
EXPECT_PRED4(HasCandidate, ready_candidates, "relay", "udp",
|
||||
rtc::SocketAddress(kTurnUdpExtAddr.ipaddr(), 0));
|
||||
}
|
||||
|
||||
void TestIPv6TurnPortPrunesIPv4TurnPort() {
|
||||
turn_server_.AddInternalSocket(kTurnUdpIntIPv6Addr, PROTO_UDP);
|
||||
// Add two IP addresses on the same interface.
|
||||
AddInterface(kClientAddr, "net1");
|
||||
AddInterface(kClientIPv6Addr, "net1");
|
||||
allocator_.reset(new BasicPortAllocator(&network_manager_));
|
||||
allocator_->SetConfiguration(allocator_->stun_servers(),
|
||||
allocator_->turn_servers(), 0, true);
|
||||
AddTurnServers(kTurnUdpIntIPv6Addr, rtc::SocketAddress());
|
||||
AddTurnServers(kTurnUdpIntAddr, rtc::SocketAddress());
|
||||
|
||||
allocator_->set_step_delay(kMinimumStepDelay);
|
||||
allocator_->set_flags(
|
||||
allocator().flags() | PORTALLOCATOR_ENABLE_SHARED_SOCKET |
|
||||
PORTALLOCATOR_ENABLE_IPV6 | PORTALLOCATOR_DISABLE_TCP);
|
||||
|
||||
EXPECT_TRUE(CreateSession(ICE_CANDIDATE_COMPONENT_RTP));
|
||||
session_->StartGettingPorts();
|
||||
EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
|
||||
// Three ports (one IPv4 STUN, one IPv6 STUN and one TURN) will be ready.
|
||||
EXPECT_EQ(3U, session_->ReadyPorts().size());
|
||||
EXPECT_EQ(3U, ports_.size());
|
||||
EXPECT_EQ(1, CountPorts(ports_, "local", PROTO_UDP, kClientAddr));
|
||||
EXPECT_EQ(1, CountPorts(ports_, "local", PROTO_UDP, kClientIPv6Addr));
|
||||
EXPECT_EQ(1, CountPorts(ports_, "relay", PROTO_UDP, kClientIPv6Addr));
|
||||
EXPECT_EQ(0, CountPorts(ports_, "relay", PROTO_UDP, kClientAddr));
|
||||
|
||||
// Now that we remove candidates when a TURN port is pruned, there will be
|
||||
// exactly 3 candidates in both |candidates_| and |ready_candidates|.
|
||||
EXPECT_EQ(3U, candidates_.size());
|
||||
const std::vector<Candidate>& ready_candidates =
|
||||
session_->ReadyCandidates();
|
||||
EXPECT_EQ(3U, ready_candidates.size());
|
||||
EXPECT_PRED4(HasCandidate, ready_candidates, "local", "udp", kClientAddr);
|
||||
EXPECT_PRED4(HasCandidate, ready_candidates, "relay", "udp",
|
||||
rtc::SocketAddress(kTurnUdpExtAddr.ipaddr(), 0));
|
||||
}
|
||||
|
||||
void TestEachInterfaceHasItsOwnTurnPorts() {
|
||||
turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TCP);
|
||||
turn_server_.AddInternalSocket(kTurnUdpIntIPv6Addr, PROTO_UDP);
|
||||
turn_server_.AddInternalSocket(kTurnTcpIntIPv6Addr, PROTO_TCP);
|
||||
// Add two interfaces both having IPv4 and IPv6 addresses.
|
||||
AddInterface(kClientAddr, "net1", rtc::ADAPTER_TYPE_WIFI);
|
||||
AddInterface(kClientIPv6Addr, "net1", rtc::ADAPTER_TYPE_WIFI);
|
||||
AddInterface(kClientAddr2, "net2", rtc::ADAPTER_TYPE_CELLULAR);
|
||||
AddInterface(kClientIPv6Addr2, "net2", rtc::ADAPTER_TYPE_CELLULAR);
|
||||
allocator_.reset(new BasicPortAllocator(&network_manager_));
|
||||
allocator_->SetConfiguration(allocator_->stun_servers(),
|
||||
allocator_->turn_servers(), 0, true);
|
||||
// Have both UDP/TCP and IPv4/IPv6 TURN ports.
|
||||
AddTurnServers(kTurnUdpIntAddr, kTurnTcpIntAddr);
|
||||
AddTurnServers(kTurnUdpIntIPv6Addr, kTurnTcpIntIPv6Addr);
|
||||
|
||||
allocator_->set_step_delay(kMinimumStepDelay);
|
||||
allocator_->set_flags(allocator().flags() |
|
||||
PORTALLOCATOR_ENABLE_SHARED_SOCKET |
|
||||
PORTALLOCATOR_ENABLE_IPV6);
|
||||
EXPECT_TRUE(CreateSession(ICE_CANDIDATE_COMPONENT_RTP));
|
||||
session_->StartGettingPorts();
|
||||
EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
|
||||
// 10 ports (4 STUN and 1 TURN ports on each interface) will be ready to
|
||||
// use.
|
||||
EXPECT_EQ(10U, session_->ReadyPorts().size());
|
||||
EXPECT_EQ(10U, ports_.size());
|
||||
EXPECT_EQ(1, CountPorts(ports_, "local", PROTO_UDP, kClientAddr));
|
||||
EXPECT_EQ(1, CountPorts(ports_, "local", PROTO_UDP, kClientAddr2));
|
||||
EXPECT_EQ(1, CountPorts(ports_, "local", PROTO_UDP, kClientIPv6Addr));
|
||||
EXPECT_EQ(1, CountPorts(ports_, "local", PROTO_UDP, kClientIPv6Addr2));
|
||||
EXPECT_EQ(1, CountPorts(ports_, "local", PROTO_TCP, kClientAddr));
|
||||
EXPECT_EQ(1, CountPorts(ports_, "local", PROTO_TCP, kClientAddr2));
|
||||
EXPECT_EQ(1, CountPorts(ports_, "local", PROTO_TCP, kClientIPv6Addr));
|
||||
EXPECT_EQ(1, CountPorts(ports_, "local", PROTO_TCP, kClientIPv6Addr2));
|
||||
EXPECT_EQ(1, CountPorts(ports_, "relay", PROTO_UDP, kClientIPv6Addr));
|
||||
EXPECT_EQ(1, CountPorts(ports_, "relay", PROTO_UDP, kClientIPv6Addr2));
|
||||
|
||||
// Now that we remove candidates when TURN ports are pruned, there will be
|
||||
// exactly 10 candidates in |candidates_|.
|
||||
EXPECT_EQ(10U, candidates_.size());
|
||||
const std::vector<Candidate>& ready_candidates =
|
||||
session_->ReadyCandidates();
|
||||
EXPECT_EQ(10U, ready_candidates.size());
|
||||
EXPECT_PRED4(HasCandidate, ready_candidates, "local", "udp", kClientAddr);
|
||||
EXPECT_PRED4(HasCandidate, ready_candidates, "local", "udp", kClientAddr2);
|
||||
EXPECT_PRED4(HasCandidate, ready_candidates, "local", "udp",
|
||||
kClientIPv6Addr);
|
||||
EXPECT_PRED4(HasCandidate, ready_candidates, "local", "udp",
|
||||
kClientIPv6Addr2);
|
||||
EXPECT_PRED4(HasCandidate, ready_candidates, "local", "tcp", kClientAddr);
|
||||
EXPECT_PRED4(HasCandidate, ready_candidates, "local", "tcp", kClientAddr2);
|
||||
EXPECT_PRED4(HasCandidate, ready_candidates, "local", "tcp",
|
||||
kClientIPv6Addr);
|
||||
EXPECT_PRED4(HasCandidate, ready_candidates, "local", "tcp",
|
||||
kClientIPv6Addr2);
|
||||
EXPECT_PRED4(HasCandidate, ready_candidates, "relay", "udp",
|
||||
rtc::SocketAddress(kTurnUdpExtAddr.ipaddr(), 0));
|
||||
}
|
||||
|
||||
std::unique_ptr<rtc::PhysicalSocketServer> pss_;
|
||||
std::unique_ptr<rtc::VirtualSocketServer> vss_;
|
||||
std::unique_ptr<rtc::FirewallSocketServer> fss_;
|
||||
@ -1211,142 +1367,72 @@ TEST_F(BasicPortAllocatorTest, TestSharedSocketWithoutNatUsingTurn) {
|
||||
EXPECT_EQ(3U, candidates_.size());
|
||||
}
|
||||
|
||||
// Test that if prune_turn_ports is set, TCP TurnPort will not
|
||||
// be used if UDP TurnPort is used.
|
||||
TEST_F(BasicPortAllocatorTest, TestUdpTurnPortPrunesTcpTurnPorts) {
|
||||
turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TCP);
|
||||
AddInterface(kClientAddr);
|
||||
allocator_.reset(new BasicPortAllocator(&network_manager_));
|
||||
allocator_->SetConfiguration(allocator_->stun_servers(),
|
||||
allocator_->turn_servers(), 0, true);
|
||||
AddTurnServers(kTurnUdpIntAddr, kTurnTcpIntAddr);
|
||||
allocator_->set_step_delay(kMinimumStepDelay);
|
||||
allocator_->set_flags(allocator().flags() |
|
||||
PORTALLOCATOR_ENABLE_SHARED_SOCKET |
|
||||
PORTALLOCATOR_DISABLE_TCP);
|
||||
// Test that if prune_turn_ports is set, TCP TURN port will not be used
|
||||
// if UDP TurnPort is used, given that TCP TURN port becomes ready first.
|
||||
TEST_F(BasicPortAllocatorTest,
|
||||
TestUdpTurnPortPrunesTcpTurnPortWithTcpPortReadyFirst) {
|
||||
// UDP has longer delay than TCP so that TCP TURN port becomes ready first.
|
||||
virtual_socket_server()->SetDelayOnAddress(kTurnUdpIntAddr, 200);
|
||||
virtual_socket_server()->SetDelayOnAddress(kTurnTcpIntAddr, 100);
|
||||
|
||||
EXPECT_TRUE(CreateSession(ICE_CANDIDATE_COMPONENT_RTP));
|
||||
session_->StartGettingPorts();
|
||||
EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
|
||||
// Only 2 ports (one STUN and one TURN) are actually being used.
|
||||
EXPECT_EQ(2U, session_->ReadyPorts().size());
|
||||
// We have verified that each port, when it is added to |ports_|, it is found
|
||||
// in |ready_ports|, and when it is pruned, it is not found in |ready_ports|,
|
||||
// so we only need to verify the content in one of them.
|
||||
EXPECT_EQ(2U, ports_.size());
|
||||
EXPECT_EQ(1, CountPorts(ports_, "local", PROTO_UDP, kClientAddr));
|
||||
EXPECT_EQ(1, CountPorts(ports_, "relay", PROTO_UDP, kClientAddr));
|
||||
EXPECT_EQ(0, CountPorts(ports_, "relay", PROTO_TCP, kClientAddr));
|
||||
|
||||
// We don't remove candidates, so the size of |candidates_| will depend on
|
||||
// when the TCP TURN port becomes ready. If it is ready after the UDP TURN
|
||||
// port becomes ready, its candidates will be used there will be 3 candidates.
|
||||
// Otherwise there will be only 2 candidates.
|
||||
EXPECT_LE(2U, candidates_.size());
|
||||
// There will only be 2 candidates in |ready_candidates| because it only
|
||||
// includes the candidates in the ready ports.
|
||||
const std::vector<Candidate>& ready_candidates = session_->ReadyCandidates();
|
||||
EXPECT_EQ(2U, ready_candidates.size());
|
||||
EXPECT_PRED4(HasCandidate, ready_candidates, "local", "udp", kClientAddr);
|
||||
EXPECT_PRED4(HasCandidate, ready_candidates, "relay", "udp",
|
||||
rtc::SocketAddress(kTurnUdpExtAddr.ipaddr(), 0));
|
||||
TestUdpTurnPortPrunesTcpTurnPort();
|
||||
}
|
||||
|
||||
// Tests that if prune_turn_ports is set, IPv4 TurnPort will not
|
||||
// be used if IPv6 TurnPort is used.
|
||||
TEST_F(BasicPortAllocatorTest, TestIPv6TurnPortPrunesIPv4TurnPorts) {
|
||||
turn_server_.AddInternalSocket(kTurnUdpIntIPv6Addr, PROTO_UDP);
|
||||
// Add two IP addresses on the same interface.
|
||||
AddInterface(kClientAddr, "net1");
|
||||
AddInterface(kClientIPv6Addr, "net1");
|
||||
allocator_.reset(new BasicPortAllocator(&network_manager_));
|
||||
allocator_->SetConfiguration(allocator_->stun_servers(),
|
||||
allocator_->turn_servers(), 0, true);
|
||||
AddTurnServers(kTurnUdpIntIPv6Addr, rtc::SocketAddress());
|
||||
// Test that if prune_turn_ports is set, TCP TURN port will not be used
|
||||
// if UDP TurnPort is used, given that UDP TURN port becomes ready first.
|
||||
TEST_F(BasicPortAllocatorTest,
|
||||
TestUdpTurnPortPrunesTcpTurnPortsWithUdpPortReadyFirst) {
|
||||
// UDP has shorter delay than TCP so that UDP TURN port becomes ready first.
|
||||
virtual_socket_server()->SetDelayOnAddress(kTurnUdpIntAddr, 100);
|
||||
virtual_socket_server()->SetDelayOnAddress(kTurnTcpIntAddr, 200);
|
||||
|
||||
allocator_->set_step_delay(kMinimumStepDelay);
|
||||
allocator_->set_flags(allocator().flags() |
|
||||
PORTALLOCATOR_ENABLE_SHARED_SOCKET |
|
||||
PORTALLOCATOR_ENABLE_IPV6 | PORTALLOCATOR_DISABLE_TCP);
|
||||
TestUdpTurnPortPrunesTcpTurnPort();
|
||||
}
|
||||
|
||||
EXPECT_TRUE(CreateSession(ICE_CANDIDATE_COMPONENT_RTP));
|
||||
session_->StartGettingPorts();
|
||||
EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
|
||||
// Three ports (one IPv4 STUN, one IPv6 STUN and one TURN) will be ready.
|
||||
EXPECT_EQ(3U, session_->ReadyPorts().size());
|
||||
EXPECT_EQ(3U, ports_.size());
|
||||
EXPECT_EQ(1, CountPorts(ports_, "local", PROTO_UDP, kClientAddr));
|
||||
EXPECT_EQ(1, CountPorts(ports_, "local", PROTO_UDP, kClientIPv6Addr));
|
||||
EXPECT_EQ(1, CountPorts(ports_, "relay", PROTO_UDP, kClientIPv6Addr));
|
||||
EXPECT_EQ(0, CountPorts(ports_, "relay", PROTO_UDP, kClientAddr));
|
||||
// Tests that if prune_turn_ports is set, IPv4 TurnPort will not be used
|
||||
// if IPv6 TurnPort is used, given that IPv4 TURN port becomes ready first.
|
||||
TEST_F(BasicPortAllocatorTest,
|
||||
TestIPv6TurnPortPrunesIPv4TurnPortWithIPv4PortReadyFirst) {
|
||||
// IPv6 has longer delay than IPv4, so that IPv4 TURN port becomes ready
|
||||
// first.
|
||||
virtual_socket_server()->SetDelayOnAddress(kTurnUdpIntAddr, 100);
|
||||
virtual_socket_server()->SetDelayOnAddress(kTurnUdpIntIPv6Addr, 200);
|
||||
|
||||
// We don't remove candidates, so there may be more than 3 elemenets in
|
||||
// |candidates_|, although |ready_candidates| only includes the candidates
|
||||
// in |ready_ports|.
|
||||
EXPECT_LE(3U, candidates_.size());
|
||||
const std::vector<Candidate>& ready_candidates = session_->ReadyCandidates();
|
||||
EXPECT_EQ(3U, ready_candidates.size());
|
||||
EXPECT_PRED4(HasCandidate, ready_candidates, "local", "udp", kClientAddr);
|
||||
EXPECT_PRED4(HasCandidate, ready_candidates, "relay", "udp",
|
||||
rtc::SocketAddress(kTurnUdpExtAddr.ipaddr(), 0));
|
||||
TestIPv6TurnPortPrunesIPv4TurnPort();
|
||||
}
|
||||
|
||||
// Tests that if prune_turn_ports is set, IPv4 TurnPort will not be used
|
||||
// if IPv6 TurnPort is used, given that IPv6 TURN port becomes ready first.
|
||||
TEST_F(BasicPortAllocatorTest,
|
||||
TestIPv6TurnPortPrunesIPv4TurnPortWithIPv6PortReadyFirst) {
|
||||
// IPv6 has longer delay than IPv4, so that IPv6 TURN port becomes ready
|
||||
// first.
|
||||
virtual_socket_server()->SetDelayOnAddress(kTurnUdpIntAddr, 200);
|
||||
virtual_socket_server()->SetDelayOnAddress(kTurnUdpIntIPv6Addr, 100);
|
||||
|
||||
TestIPv6TurnPortPrunesIPv4TurnPort();
|
||||
}
|
||||
|
||||
// Tests that if prune_turn_ports is set, each network interface
|
||||
// will has its own set of TurnPorts based on their priorities.
|
||||
TEST_F(BasicPortAllocatorTest, TestEachInterfaceHasItsOwnTurnPorts) {
|
||||
turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TCP);
|
||||
turn_server_.AddInternalSocket(kTurnUdpIntIPv6Addr, PROTO_UDP);
|
||||
turn_server_.AddInternalSocket(kTurnTcpIntIPv6Addr, PROTO_TCP);
|
||||
// Add two interfaces both having IPv4 and IPv6 addresses.
|
||||
AddInterface(kClientAddr, "net1", rtc::ADAPTER_TYPE_WIFI);
|
||||
AddInterface(kClientIPv6Addr, "net1", rtc::ADAPTER_TYPE_WIFI);
|
||||
AddInterface(kClientAddr2, "net2", rtc::ADAPTER_TYPE_CELLULAR);
|
||||
AddInterface(kClientIPv6Addr2, "net2", rtc::ADAPTER_TYPE_CELLULAR);
|
||||
allocator_.reset(new BasicPortAllocator(&network_manager_));
|
||||
allocator_->SetConfiguration(allocator_->stun_servers(),
|
||||
allocator_->turn_servers(), 0, true);
|
||||
// Have both UDP/TCP and IPv4/IPv6 TURN ports.
|
||||
AddTurnServers(kTurnUdpIntAddr, kTurnTcpIntAddr);
|
||||
AddTurnServers(kTurnUdpIntIPv6Addr, kTurnTcpIntIPv6Addr);
|
||||
// will has its own set of TurnPorts based on their priorities, in the default
|
||||
// case where no transit delay is set.
|
||||
TEST_F(BasicPortAllocatorTest, TestEachInterfaceHasItsOwnTurnPortsNoDelay) {
|
||||
TestEachInterfaceHasItsOwnTurnPorts();
|
||||
}
|
||||
|
||||
allocator_->set_step_delay(kMinimumStepDelay);
|
||||
allocator_->set_flags(allocator().flags() |
|
||||
PORTALLOCATOR_ENABLE_SHARED_SOCKET |
|
||||
PORTALLOCATOR_ENABLE_IPV6);
|
||||
EXPECT_TRUE(CreateSession(ICE_CANDIDATE_COMPONENT_RTP));
|
||||
session_->StartGettingPorts();
|
||||
EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
|
||||
// 10 ports (4 STUN and 1 TURN ports on each interface) will be ready to use.
|
||||
EXPECT_EQ(10U, session_->ReadyPorts().size());
|
||||
EXPECT_EQ(10U, ports_.size());
|
||||
EXPECT_EQ(1, CountPorts(ports_, "local", PROTO_UDP, kClientAddr));
|
||||
EXPECT_EQ(1, CountPorts(ports_, "local", PROTO_UDP, kClientAddr2));
|
||||
EXPECT_EQ(1, CountPorts(ports_, "local", PROTO_UDP, kClientIPv6Addr));
|
||||
EXPECT_EQ(1, CountPorts(ports_, "local", PROTO_UDP, kClientIPv6Addr2));
|
||||
EXPECT_EQ(1, CountPorts(ports_, "local", PROTO_TCP, kClientAddr));
|
||||
EXPECT_EQ(1, CountPorts(ports_, "local", PROTO_TCP, kClientAddr2));
|
||||
EXPECT_EQ(1, CountPorts(ports_, "local", PROTO_TCP, kClientIPv6Addr));
|
||||
EXPECT_EQ(1, CountPorts(ports_, "local", PROTO_TCP, kClientIPv6Addr2));
|
||||
EXPECT_EQ(1, CountPorts(ports_, "relay", PROTO_UDP, kClientIPv6Addr));
|
||||
EXPECT_EQ(1, CountPorts(ports_, "relay", PROTO_UDP, kClientIPv6Addr2));
|
||||
// Tests that if prune_turn_ports is set, each network interface
|
||||
// will has its own set of TurnPorts based on their priorities, given that
|
||||
// IPv4/TCP TURN port becomes ready first.
|
||||
TEST_F(BasicPortAllocatorTest,
|
||||
TestEachInterfaceHasItsOwnTurnPortsWithTcpIPv4ReadyFirst) {
|
||||
// IPv6/UDP have longer delay than IPv4/TCP, so that IPv4/TCP TURN port
|
||||
// becomes ready last.
|
||||
virtual_socket_server()->SetDelayOnAddress(kTurnTcpIntAddr, 10);
|
||||
virtual_socket_server()->SetDelayOnAddress(kTurnUdpIntAddr, 100);
|
||||
virtual_socket_server()->SetDelayOnAddress(kTurnTcpIntIPv6Addr, 20);
|
||||
virtual_socket_server()->SetDelayOnAddress(kTurnUdpIntIPv6Addr, 300);
|
||||
|
||||
// We don't remove candidates, so there may be more than 10 candidates
|
||||
// in |candidates_|.
|
||||
EXPECT_LE(10U, candidates_.size());
|
||||
const std::vector<Candidate>& ready_candidates = session_->ReadyCandidates();
|
||||
EXPECT_EQ(10U, ready_candidates.size());
|
||||
EXPECT_PRED4(HasCandidate, ready_candidates, "local", "udp", kClientAddr);
|
||||
EXPECT_PRED4(HasCandidate, ready_candidates, "local", "udp", kClientAddr2);
|
||||
EXPECT_PRED4(HasCandidate, ready_candidates, "local", "udp", kClientIPv6Addr);
|
||||
EXPECT_PRED4(HasCandidate, ready_candidates, "local", "udp",
|
||||
kClientIPv6Addr2);
|
||||
EXPECT_PRED4(HasCandidate, ready_candidates, "local", "tcp", kClientAddr);
|
||||
EXPECT_PRED4(HasCandidate, ready_candidates, "local", "tcp", kClientAddr2);
|
||||
EXPECT_PRED4(HasCandidate, ready_candidates, "local", "tcp", kClientIPv6Addr);
|
||||
EXPECT_PRED4(HasCandidate, ready_candidates, "local", "tcp",
|
||||
kClientIPv6Addr2);
|
||||
EXPECT_PRED4(HasCandidate, ready_candidates, "relay", "udp",
|
||||
rtc::SocketAddress(kTurnUdpExtAddr.ipaddr(), 0));
|
||||
TestEachInterfaceHasItsOwnTurnPorts();
|
||||
}
|
||||
|
||||
// Testing DNS resolve for the TURN server, this will test AllocationSequence
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user