diff --git a/webrtc/base/virtualsocketserver.cc b/webrtc/base/virtualsocketserver.cc index 87775cd63c..da2cb1d741 100644 --- a/webrtc/base/virtualsocketserver.cc +++ b/webrtc/base/virtualsocketserver.cc @@ -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(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(delay); } diff --git a/webrtc/base/virtualsocketserver.h b/webrtc/base/virtualsocketserver.h index cce0279d32..6782d800a0 100644 --- a/webrtc/base/virtualsocketserver.h +++ b/webrtc/base/virtualsocketserver.h @@ -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 Point; typedef std::vector 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 delay_by_ip_; + std::unique_ptr 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_; diff --git a/webrtc/p2p/client/basicportallocator.cc b/webrtc/p2p/client/basicportallocator.cc index e94feb4d15..dba68f177e 100644 --- a/webrtc/p2p/client/basicportallocator.cc +++ b/webrtc/p2p/client/basicportallocator.cc @@ -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 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 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 pruned_ports; + std::vector 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::GetUnprunedPorts( const std::vector& networks) { - std::vector ports_to_remove; - std::vector candidates_to_remove; - for (PortData& data : ports_) { - if (std::find(networks.begin(), networks.end(), - data.sequence()->network()) == networks.end()) { - continue; + std::vector 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& port_data_list) { + std::vector pruned_ports; + std::vector 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); } } diff --git a/webrtc/p2p/client/basicportallocator.h b/webrtc/p2p/client/basicportallocator.h index 204ff040a1..3044559a0b 100644 --- a/webrtc/p2p/client/basicportallocator.h +++ b/webrtc/p2p/client/basicportallocator.h @@ -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& networks); + std::vector GetUnprunedPorts( + const std::vector& networks); + // Prunes ports and signal the remote side to remove the candidates that + // were previously signaled from these ports. + void PrunePortsAndRemoveCandidates( + const std::vector& port_data_list); // Gets filtered and sanitized candidates generated from a port and // append to |candidates|. void GetCandidatesFromPort(const PortData& data, diff --git a/webrtc/p2p/client/basicportallocator_unittest.cc b/webrtc/p2p/client/basicportallocator_unittest.cc index c9831f525b..cf967a8ae1 100644 --- a/webrtc/p2p/client/basicportallocator_unittest.cc +++ b/webrtc/p2p/client/basicportallocator_unittest.cc @@ -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& 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& 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& 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& 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 pss_; std::unique_ptr vss_; std::unique_ptr 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& 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& 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& 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