Index: webrtc/p2p/base/p2ptransportchannel_unittest.cc |
diff --git a/webrtc/p2p/base/p2ptransportchannel_unittest.cc b/webrtc/p2p/base/p2ptransportchannel_unittest.cc |
index 587f971f1e7bcdf57f8b2f25217fb97451bccb57..227e913c2e4c7a0044b50eaf79ae4010e7a53807 100644 |
--- a/webrtc/p2p/base/p2ptransportchannel_unittest.cc |
+++ b/webrtc/p2p/base/p2ptransportchannel_unittest.cc |
@@ -44,6 +44,7 @@ static const int kDefaultTimeout = 1000; |
static const int kOnlyLocalPorts = cricket::PORTALLOCATOR_DISABLE_STUN | |
cricket::PORTALLOCATOR_DISABLE_RELAY | |
cricket::PORTALLOCATOR_DISABLE_TCP; |
+static const int LOW_RTT = 20; |
// Addresses on the public internet. |
static const SocketAddress kPublicAddrs[2] = |
{ SocketAddress("11.11.11.11", 0), SocketAddress("22.22.22.22", 0) }; |
@@ -2077,13 +2078,103 @@ TEST_F(P2PTransportChannelPingTest, TestAllConnectionsPingedSufficiently) { |
// Low-priority connection becomes writable so that the other connection |
// is not pruned. |
- conn1->ReceivedPingResponse(); |
+ conn1->ReceivedPingResponse(LOW_RTT); |
EXPECT_TRUE_WAIT( |
conn1->num_pings_sent() >= MIN_PINGS_AT_WEAK_PING_INTERVAL && |
conn2->num_pings_sent() >= MIN_PINGS_AT_WEAK_PING_INTERVAL, |
kDefaultTimeout); |
} |
+// Verify that the connections are pinged at the right time. |
+TEST_F(P2PTransportChannelPingTest, TestStunPingIntervals) { |
+ rtc::ScopedFakeClock clock; |
+ int RTT_RATIO = 4; |
+ int SCHEDULING_RANGE = 200; |
+ int RTT_RANGE = 10; |
+ |
+ cricket::FakePortAllocator pa(rtc::Thread::Current(), nullptr); |
+ cricket::P2PTransportChannel ch("TestChannel", 1, &pa); |
+ PrepareChannel(&ch); |
+ ch.Connect(); |
+ ch.MaybeStartGathering(); |
+ ch.AddRemoteCandidate(CreateHostCandidate("1.1.1.1", 1, 1)); |
+ cricket::Connection* conn = WaitForConnectionTo(&ch, "1.1.1.1", 1); |
+ |
+ ASSERT_TRUE(conn != nullptr); |
+ SIMULATED_WAIT(conn->num_pings_sent() == 1, kDefaultTimeout, clock); |
+ |
+ // Initializing. |
+ |
+ int64_t start = clock.TimeNanos(); |
+ SIMULATED_WAIT(conn->num_pings_sent() >= MIN_PINGS_AT_WEAK_PING_INTERVAL, |
+ kDefaultTimeout, clock); |
+ int64_t ping_interval_ms = (clock.TimeNanos() - start) / |
+ rtc::kNumNanosecsPerMillisec / |
+ (MIN_PINGS_AT_WEAK_PING_INTERVAL - 1); |
+ EXPECT_EQ(ping_interval_ms, cricket::WEAK_PING_INTERVAL); |
+ |
+ // Stabilizing. |
+ |
+ conn->ReceivedPingResponse(LOW_RTT); |
+ int ping_sent_before = conn->num_pings_sent(); |
+ start = clock.TimeNanos(); |
+ // The connection becomes strong but not stable because we haven't been able |
+ // to converge the RTT. |
+ SIMULATED_WAIT(conn->num_pings_sent() == ping_sent_before + 1, 3000, clock); |
+ ping_interval_ms = (clock.TimeNanos() - start) / rtc::kNumNanosecsPerMillisec; |
+ EXPECT_GE(ping_interval_ms, |
+ cricket::STABILIZING_WRITABLE_CONNECTION_PING_INTERVAL); |
+ EXPECT_LE(ping_interval_ms, |
+ cricket::STABILIZING_WRITABLE_CONNECTION_PING_INTERVAL + |
+ SCHEDULING_RANGE); |
+ |
+ // Stabilized. |
+ |
+ // The connection becomes stable after receiving more than RTT_RATIO rtt |
+ // samples. |
+ for (int i = 0; i < RTT_RATIO; i++) { |
+ conn->ReceivedPingResponse(LOW_RTT); |
+ } |
+ ping_sent_before = conn->num_pings_sent(); |
+ start = clock.TimeNanos(); |
+ SIMULATED_WAIT(conn->num_pings_sent() == ping_sent_before + 1, 3000, clock); |
+ ping_interval_ms = (clock.TimeNanos() - start) / rtc::kNumNanosecsPerMillisec; |
+ EXPECT_GE(ping_interval_ms, |
+ cricket::STABLE_WRITABLE_CONNECTION_PING_INTERVAL); |
+ EXPECT_LE( |
+ ping_interval_ms, |
+ cricket::STABLE_WRITABLE_CONNECTION_PING_INTERVAL + SCHEDULING_RANGE); |
+ |
+ // Destabilized. |
+ |
+ conn->ReceivedPingResponse(LOW_RTT); |
+ // Create a in-flight ping. |
+ conn->Ping(clock.TimeNanos() / rtc::kNumNanosecsPerMillisec); |
+ start = clock.TimeNanos(); |
+ // In-flight ping timeout and the connection will be unstable. |
+ SIMULATED_WAIT( |
+ !conn->stable(clock.TimeNanos() / rtc::kNumNanosecsPerMillisec), 3000, |
+ clock); |
+ int64_t duration_ms = |
+ (clock.TimeNanos() - start) / rtc::kNumNanosecsPerMillisec; |
+ EXPECT_GE(duration_ms, 2 * conn->rtt() - RTT_RANGE); |
+ EXPECT_LE(duration_ms, 2 * conn->rtt() + RTT_RANGE); |
+ // The connection become unstable due to not receiving ping responses. |
+ ping_sent_before = conn->num_pings_sent(); |
+ SIMULATED_WAIT(conn->num_pings_sent() == ping_sent_before + 1, 3000, clock); |
+ // The interval is expected to be |
+ // STABILIZING_WRITABLE_CONNECTION_PING_INTERVAL. |
+ start = clock.TimeNanos(); |
+ ping_sent_before = conn->num_pings_sent(); |
+ SIMULATED_WAIT(conn->num_pings_sent() == ping_sent_before + 1, 3000, clock); |
+ ping_interval_ms = (clock.TimeNanos() - start) / rtc::kNumNanosecsPerMillisec; |
+ EXPECT_GE(ping_interval_ms, |
+ cricket::STABILIZING_WRITABLE_CONNECTION_PING_INTERVAL); |
+ EXPECT_LE(ping_interval_ms, |
+ cricket::STABILIZING_WRITABLE_CONNECTION_PING_INTERVAL + |
+ SCHEDULING_RANGE); |
+} |
+ |
TEST_F(P2PTransportChannelPingTest, TestNoTriggeredChecksWhenWritable) { |
cricket::FakePortAllocator pa(rtc::Thread::Current(), nullptr); |
cricket::P2PTransportChannel ch("trigger checks", 1, &pa); |
@@ -2100,7 +2191,7 @@ TEST_F(P2PTransportChannelPingTest, TestNoTriggeredChecksWhenWritable) { |
EXPECT_EQ(conn2, FindNextPingableConnectionAndPingIt(&ch)); |
EXPECT_EQ(conn1, FindNextPingableConnectionAndPingIt(&ch)); |
- conn1->ReceivedPingResponse(); |
+ conn1->ReceivedPingResponse(LOW_RTT); |
ASSERT_TRUE(conn1->writable()); |
conn1->ReceivedPing(); |
@@ -2200,7 +2291,7 @@ TEST_F(P2PTransportChannelPingTest, ConnectionResurrection) { |
cricket::Connection* conn2 = WaitForConnectionTo(&ch, "2.2.2.2", 2); |
ASSERT_TRUE(conn2 != nullptr); |
conn2->ReceivedPing(); |
- conn2->ReceivedPingResponse(); |
+ conn2->ReceivedPingResponse(LOW_RTT); |
// Wait for conn1 to be pruned. |
EXPECT_TRUE_WAIT(conn1->pruned(), 3000); |
@@ -2303,7 +2394,7 @@ TEST_F(P2PTransportChannelPingTest, TestSelectConnectionBeforeNomination) { |
ASSERT_TRUE(conn3 != nullptr); |
// Because it has a lower priority, the best connection is still conn2. |
EXPECT_EQ(conn2, ch.best_connection()); |
- conn3->ReceivedPingResponse(); // Become writable. |
+ conn3->ReceivedPingResponse(LOW_RTT); // Become writable. |
// But if it is nominated via use_candidate, it is chosen as the best |
// connection. |
conn3->set_nominated(true); |
@@ -2329,7 +2420,7 @@ TEST_F(P2PTransportChannelPingTest, TestSelectConnectionBeforeNomination) { |
EXPECT_EQ(conn3, ch.best_connection()); |
reset_channel_ready_to_send(); |
// The best connection switches after conn4 becomes writable. |
- conn4->ReceivedPingResponse(); |
+ conn4->ReceivedPingResponse(LOW_RTT); |
EXPECT_EQ(conn4, ch.best_connection()); |
EXPECT_EQ(conn4, last_selected_candidate_pair()); |
EXPECT_EQ(last_packet_id, last_sent_packet_id()); |
@@ -2364,7 +2455,7 @@ TEST_F(P2PTransportChannelPingTest, TestSelectConnectionFromUnknownAddress) { |
ASSERT_TRUE(conn1 != nullptr); |
EXPECT_TRUE(port->sent_binding_response()); |
EXPECT_EQ(conn1, ch.best_connection()); |
- conn1->ReceivedPingResponse(); |
+ conn1->ReceivedPingResponse(LOW_RTT); |
EXPECT_EQ(conn1, ch.best_connection()); |
port->set_sent_binding_response(false); |
@@ -2376,7 +2467,7 @@ TEST_F(P2PTransportChannelPingTest, TestSelectConnectionFromUnknownAddress) { |
EXPECT_EQ(conn1, ch.best_connection()); |
// When it is nominated via use_candidate and writable, it is chosen as the |
// best connection. |
- conn2->ReceivedPingResponse(); // Become writable. |
+ conn2->ReceivedPingResponse(LOW_RTT); // Become writable. |
conn2->set_nominated(true); |
conn2->SignalNominated(conn2); |
EXPECT_EQ(conn2, ch.best_connection()); |
@@ -2389,7 +2480,7 @@ TEST_F(P2PTransportChannelPingTest, TestSelectConnectionFromUnknownAddress) { |
cricket::Connection* conn3 = WaitForConnectionTo(&ch, "3.3.3.3", 3); |
ASSERT_TRUE(conn3 != nullptr); |
EXPECT_TRUE(port->sent_binding_response()); |
- conn3->ReceivedPingResponse(); // Become writable. |
+ conn3->ReceivedPingResponse(LOW_RTT); // Become writable. |
EXPECT_EQ(conn2, ch.best_connection()); |
port->set_sent_binding_response(false); |
@@ -2404,7 +2495,7 @@ TEST_F(P2PTransportChannelPingTest, TestSelectConnectionFromUnknownAddress) { |
EXPECT_TRUE(port->sent_binding_response()); |
// conn4 is not the best connection yet because it is not writable. |
EXPECT_EQ(conn2, ch.best_connection()); |
- conn4->ReceivedPingResponse(); // Become writable. |
+ conn4->ReceivedPingResponse(LOW_RTT); // Become writable. |
EXPECT_EQ(conn4, ch.best_connection()); |
// Test that the request from an unknown address contains a ufrag from an old |
@@ -2447,7 +2538,7 @@ TEST_F(P2PTransportChannelPingTest, TestSelectConnectionBasedOnMediaReceived) { |
conn2->OnReadPacket("ABC", 3, rtc::CreatePacketTime(0)); |
EXPECT_EQ(conn1, ch.best_connection()); |
- conn2->ReceivedPingResponse(); // Become writable. |
+ conn2->ReceivedPingResponse(LOW_RTT); // Become writable. |
// Switch because it is writable. |
conn2->OnReadPacket("DEF", 3, rtc::CreatePacketTime(0)); |
EXPECT_EQ(conn2, ch.best_connection()); |
@@ -2469,13 +2560,13 @@ TEST_F(P2PTransportChannelPingTest, TestSelectConnectionBasedOnMediaReceived) { |
cricket::Connection* conn3 = WaitForConnectionTo(&ch, "3.3.3.3", 3); |
ASSERT_TRUE(conn3 != nullptr); |
EXPECT_EQ(conn2, ch.best_connection()); // Not writable yet. |
- conn3->ReceivedPingResponse(); // Become writable. |
+ conn3->ReceivedPingResponse(LOW_RTT); // Become writable. |
EXPECT_EQ(conn3, ch.best_connection()); |
// Now another data packet will not switch the best connection because the |
// best connection was nominated by the controlling side. |
conn2->ReceivedPing(); |
- conn2->ReceivedPingResponse(); |
+ conn2->ReceivedPingResponse(LOW_RTT); |
conn2->OnReadPacket("XYZ", 3, rtc::CreatePacketTime(0)); |
EXPECT_EQ(conn3, ch.best_connection()); |
} |
@@ -2532,14 +2623,14 @@ TEST_F(P2PTransportChannelPingTest, TestDontPruneWhenWeak) { |
cricket::Connection* conn1 = WaitForConnectionTo(&ch, "1.1.1.1", 1); |
ASSERT_TRUE(conn1 != nullptr); |
EXPECT_EQ(conn1, ch.best_connection()); |
- conn1->ReceivedPingResponse(); // Becomes writable and receiving |
+ conn1->ReceivedPingResponse(LOW_RTT); // Becomes writable and receiving |
// When a higher-priority, nominated candidate comes in, the connections with |
// lower-priority are pruned. |
ch.AddRemoteCandidate(CreateHostCandidate("2.2.2.2", 2, 10)); |
cricket::Connection* conn2 = WaitForConnectionTo(&ch, "2.2.2.2", 2); |
ASSERT_TRUE(conn2 != nullptr); |
- conn2->ReceivedPingResponse(); // Becomes writable and receiving |
+ conn2->ReceivedPingResponse(LOW_RTT); // Becomes writable and receiving |
conn2->set_nominated(true); |
conn2->SignalNominated(conn2); |
EXPECT_TRUE_WAIT(conn1->pruned(), 3000); |
@@ -2575,7 +2666,7 @@ TEST_F(P2PTransportChannelPingTest, TestGetState) { |
// Now there are two connections, so the transport channel is connecting. |
EXPECT_EQ(cricket::TransportChannelState::STATE_CONNECTING, ch.GetState()); |
// |conn1| becomes writable and receiving; it then should prune |conn2|. |
- conn1->ReceivedPingResponse(); |
+ conn1->ReceivedPingResponse(LOW_RTT); |
EXPECT_TRUE_WAIT(conn2->pruned(), 1000); |
EXPECT_EQ(cricket::TransportChannelState::STATE_COMPLETED, ch.GetState()); |
conn1->Prune(); // All connections are pruned. |
@@ -2597,7 +2688,7 @@ TEST_F(P2PTransportChannelPingTest, TestConnectionPrunedAgain) { |
cricket::Connection* conn1 = WaitForConnectionTo(&ch, "1.1.1.1", 1); |
ASSERT_TRUE(conn1 != nullptr); |
EXPECT_EQ(conn1, ch.best_connection()); |
- conn1->ReceivedPingResponse(); // Becomes writable and receiving |
+ conn1->ReceivedPingResponse(LOW_RTT); // Becomes writable and receiving |
// Add a low-priority connection |conn2|, which will be pruned, but it will |
// not be deleted right away. Once the current best connection becomes not |
@@ -2616,12 +2707,12 @@ TEST_F(P2PTransportChannelPingTest, TestConnectionPrunedAgain) { |
conn2 = WaitForConnectionTo(&ch, "2.2.2.2", 2); |
ASSERT_TRUE(conn2 != nullptr); |
EXPECT_EQ_WAIT(cricket::Connection::STATE_INPROGRESS, conn2->state(), 1000); |
- conn2->ReceivedPingResponse(); |
+ conn2->ReceivedPingResponse(LOW_RTT); |
EXPECT_EQ_WAIT(conn2, ch.best_connection(), 1000); |
EXPECT_EQ(cricket::TransportChannelState::STATE_CONNECTING, ch.GetState()); |
// When |conn1| comes back again, |conn2| will be pruned again. |
- conn1->ReceivedPingResponse(); |
+ conn1->ReceivedPingResponse(LOW_RTT); |
EXPECT_EQ_WAIT(conn1, ch.best_connection(), 1000); |
EXPECT_TRUE_WAIT(!conn2->active(), 1000); |
EXPECT_EQ(cricket::TransportChannelState::STATE_COMPLETED, ch.GetState()); |
@@ -2672,7 +2763,7 @@ TEST_F(P2PTransportChannelPingTest, TestStopPortAllocatorSessions) { |
ch.AddRemoteCandidate(CreateHostCandidate("1.1.1.1", 1, 100)); |
cricket::Connection* conn1 = WaitForConnectionTo(&ch, "1.1.1.1", 1); |
ASSERT_TRUE(conn1 != nullptr); |
- conn1->ReceivedPingResponse(); // Becomes writable and receiving |
+ conn1->ReceivedPingResponse(LOW_RTT); // Becomes writable and receiving |
EXPECT_TRUE(!ch.allocator_session()->IsGettingPorts()); |
// Start a new session. Even though conn1, which belongs to an older |
@@ -2681,7 +2772,7 @@ TEST_F(P2PTransportChannelPingTest, TestStopPortAllocatorSessions) { |
ch.SetIceCredentials(kIceUfrag[1], kIcePwd[1]); |
ch.MaybeStartGathering(); |
conn1->Prune(); |
- conn1->ReceivedPingResponse(); |
+ conn1->ReceivedPingResponse(LOW_RTT); |
EXPECT_TRUE(ch.allocator_session()->IsGettingPorts()); |
// But if a new connection created from the new session becomes writable, |
@@ -2689,7 +2780,7 @@ TEST_F(P2PTransportChannelPingTest, TestStopPortAllocatorSessions) { |
ch.AddRemoteCandidate(CreateHostCandidate("2.2.2.2", 2, 100)); |
cricket::Connection* conn2 = WaitForConnectionTo(&ch, "2.2.2.2", 2); |
ASSERT_TRUE(conn2 != nullptr); |
- conn2->ReceivedPingResponse(); // Becomes writable and receiving |
+ conn2->ReceivedPingResponse(LOW_RTT); // Becomes writable and receiving |
EXPECT_TRUE(!ch.allocator_session()->IsGettingPorts()); |
} |
@@ -2715,13 +2806,14 @@ class P2PTransportChannelMostLikelyToWorkFirstTest |
cricket::P2PTransportChannel& StartTransportChannel( |
bool prioritize_most_likely_to_work, |
- int max_strong_interval) { |
+ int stable_writable_connection_ping_interval) { |
channel_.reset( |
new cricket::P2PTransportChannel("checks", 1, nullptr, allocator())); |
cricket::IceConfig config = channel_->config(); |
config.prioritize_most_likely_candidate_pairs = |
prioritize_most_likely_to_work; |
- config.max_strong_interval = max_strong_interval; |
+ config.stable_writable_connection_ping_interval = |
+ stable_writable_connection_ping_interval; |
channel_->SetIceConfig(config); |
PrepareChannel(channel_.get()); |
channel_->Connect(); |
@@ -2797,7 +2889,7 @@ TEST_F(P2PTransportChannelMostLikelyToWorkFirstTest, |
cricket::Connection* conn3 = WaitForConnectionTo(&ch, "1.1.1.1", 1); |
EXPECT_EQ(conn3->local_candidate().type(), cricket::LOCAL_PORT_TYPE); |
EXPECT_EQ(conn3->remote_candidate().type(), cricket::RELAY_PORT_TYPE); |
- conn3->ReceivedPingResponse(); |
+ conn3->ReceivedPingResponse(LOW_RTT); |
ASSERT_TRUE(conn3->writable()); |
conn3->ReceivedPing(); |
@@ -2814,7 +2906,7 @@ TEST_F(P2PTransportChannelMostLikelyToWorkFirstTest, |
// pingable connection. |
EXPECT_TRUE_WAIT(conn3 == ch.best_connection(), 5000); |
WAIT(false, max_strong_interval + 100); |
- conn3->ReceivedPingResponse(); |
+ conn3->ReceivedPingResponse(LOW_RTT); |
ASSERT_TRUE(conn3->writable()); |
EXPECT_EQ(conn3, FindNextPingableConnectionAndPingIt(&ch)); |