aboutsummaryrefslogtreecommitdiff
path: root/webrtc/p2p/base/p2ptransportchannel_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'webrtc/p2p/base/p2ptransportchannel_unittest.cc')
-rw-r--r--webrtc/p2p/base/p2ptransportchannel_unittest.cc230
1 files changed, 198 insertions, 32 deletions
diff --git a/webrtc/p2p/base/p2ptransportchannel_unittest.cc b/webrtc/p2p/base/p2ptransportchannel_unittest.cc
index 37cda7c661..90ddd43714 100644
--- a/webrtc/p2p/base/p2ptransportchannel_unittest.cc
+++ b/webrtc/p2p/base/p2ptransportchannel_unittest.cc
@@ -101,10 +101,12 @@ enum {
};
static cricket::IceConfig CreateIceConfig(int receiving_timeout_ms,
- bool gather_continually) {
+ bool gather_continually,
+ int backup_ping_interval = -1) {
cricket::IceConfig config;
config.receiving_timeout_ms = receiving_timeout_ms;
config.gather_continually = gather_continually;
+ config.backup_connection_ping_interval = backup_ping_interval;
return config;
}
@@ -650,6 +652,21 @@ class P2PTransportChannelTestBase : public testing::Test,
GetEndpoint(endpoint)->save_candidates_ = true;
}
+ // Tcp candidate verification has to be done when they are generated.
+ void VerifySavedTcpCandidates(int endpoint, const std::string& tcptype) {
+ for (auto& data : GetEndpoint(endpoint)->saved_candidates_) {
+ EXPECT_EQ(data->candidate.protocol(), cricket::TCP_PROTOCOL_NAME);
+ EXPECT_EQ(data->candidate.tcptype(), tcptype);
+ if (data->candidate.tcptype() == cricket::TCPTYPE_ACTIVE_STR) {
+ EXPECT_EQ(data->candidate.address().port(), cricket::DISCARD_PORT);
+ } else if (data->candidate.tcptype() == cricket::TCPTYPE_PASSIVE_STR) {
+ EXPECT_NE(data->candidate.address().port(), cricket::DISCARD_PORT);
+ } else {
+ FAIL() << "Unknown tcptype: " << data->candidate.tcptype();
+ }
+ }
+ }
+
void ResumeCandidates(int endpoint) {
Endpoint* ed = GetEndpoint(endpoint);
std::vector<CandidateData*>::iterator it = ed->saved_candidates_.begin();
@@ -825,12 +842,12 @@ class P2PTransportChannelTest : public P2PTransportChannelTestBase {
rtc::SocketAddress(), rtc::SocketAddress(),
rtc::SocketAddress()));
- cricket::RelayServerConfig relay_server(cricket::RELAY_TURN);
- relay_server.credentials = kRelayCredentials;
- relay_server.ports.push_back(
+ cricket::RelayServerConfig turn_server(cricket::RELAY_TURN);
+ turn_server.credentials = kRelayCredentials;
+ turn_server.ports.push_back(
cricket::ProtocolAddress(kTurnUdpIntAddr, cricket::PROTO_UDP, false));
- GetEndpoint(0)->allocator_->AddRelay(relay_server);
- GetEndpoint(1)->allocator_->AddRelay(relay_server);
+ GetEndpoint(0)->allocator_->AddTurnServer(turn_server);
+ GetEndpoint(1)->allocator_->AddTurnServer(turn_server);
int delay = kMinimumStepDelay;
ConfigureEndpoint(0, config1);
@@ -1290,8 +1307,19 @@ TEST_F(P2PTransportChannelTest, TestTcpConnectionsFromActiveToPassive) {
SetAllowTcpListen(0, true); // actpass.
SetAllowTcpListen(1, false); // active.
+ // Pause candidate so we could verify the candidate properties.
+ PauseCandidates(0);
+ PauseCandidates(1);
CreateChannels(1);
+ // Verify tcp candidates.
+ VerifySavedTcpCandidates(0, cricket::TCPTYPE_PASSIVE_STR);
+ VerifySavedTcpCandidates(1, cricket::TCPTYPE_ACTIVE_STR);
+
+ // Resume candidates.
+ ResumeCandidates(0);
+ ResumeCandidates(1);
+
EXPECT_TRUE_WAIT(ep1_ch1()->receiving() && ep1_ch1()->writable() &&
ep2_ch1()->receiving() && ep2_ch1()->writable(),
1000);
@@ -1300,12 +1328,6 @@ TEST_F(P2PTransportChannelTest, TestTcpConnectionsFromActiveToPassive) {
LocalCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[0]) &&
RemoteCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[1]));
- std::string kTcpProtocol = "tcp";
- EXPECT_EQ(kTcpProtocol, RemoteCandidate(ep1_ch1())->protocol());
- EXPECT_EQ(kTcpProtocol, LocalCandidate(ep1_ch1())->protocol());
- EXPECT_EQ(kTcpProtocol, RemoteCandidate(ep2_ch1())->protocol());
- EXPECT_EQ(kTcpProtocol, LocalCandidate(ep2_ch1())->protocol());
-
TestSendRecv(1);
DestroyChannels();
}
@@ -1539,19 +1561,19 @@ TEST_F(P2PTransportChannelMultihomedTest, TestFailoverControlledSide) {
// Create channels and let them go writable, as usual.
CreateChannels(1);
- // Make the receiving timeout shorter for testing.
- cricket::IceConfig config = CreateIceConfig(1000, false);
- ep1_ch1()->SetIceConfig(config);
- ep2_ch1()->SetIceConfig(config);
-
- EXPECT_TRUE_WAIT(ep1_ch1()->receiving() && ep1_ch1()->writable() &&
- ep2_ch1()->receiving() && ep2_ch1()->writable(),
- 1000);
+ EXPECT_TRUE_WAIT_MARGIN(ep1_ch1()->receiving() && ep1_ch1()->writable() &&
+ ep2_ch1()->receiving() && ep2_ch1()->writable(),
+ 1000, 1000);
EXPECT_TRUE(
ep1_ch1()->best_connection() && ep2_ch1()->best_connection() &&
LocalCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[0]) &&
RemoteCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[1]));
+ // Make the receiving timeout shorter for testing.
+ cricket::IceConfig config = CreateIceConfig(1000, false);
+ ep1_ch1()->SetIceConfig(config);
+ ep2_ch1()->SetIceConfig(config);
+
// Blackhole any traffic to or from the public addrs.
LOG(LS_INFO) << "Failing over...";
fw()->AddRule(false, rtc::FP_ANY, rtc::FD_ANY, kPublicAddrs[1]);
@@ -1591,18 +1613,19 @@ TEST_F(P2PTransportChannelMultihomedTest, TestFailoverControllingSide) {
// Create channels and let them go writable, as usual.
CreateChannels(1);
- // Make the receiving timeout shorter for testing.
- cricket::IceConfig config = CreateIceConfig(1000, false);
- ep1_ch1()->SetIceConfig(config);
- ep2_ch1()->SetIceConfig(config);
- EXPECT_TRUE_WAIT(ep1_ch1()->receiving() && ep1_ch1()->writable() &&
- ep2_ch1()->receiving() && ep2_ch1()->writable(),
- 1000);
+ EXPECT_TRUE_WAIT_MARGIN(ep1_ch1()->receiving() && ep1_ch1()->writable() &&
+ ep2_ch1()->receiving() && ep2_ch1()->writable(),
+ 1000, 1000);
EXPECT_TRUE(
ep1_ch1()->best_connection() && ep2_ch1()->best_connection() &&
LocalCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[0]) &&
RemoteCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[1]));
+ // Make the receiving timeout shorter for testing.
+ cricket::IceConfig config = CreateIceConfig(1000, false);
+ ep1_ch1()->SetIceConfig(config);
+ ep2_ch1()->SetIceConfig(config);
+
// Blackhole any traffic to or from the public addrs.
LOG(LS_INFO) << "Failing over...";
fw()->AddRule(false, rtc::FP_ANY, rtc::FD_ANY, kPublicAddrs[0]);
@@ -1627,6 +1650,43 @@ TEST_F(P2PTransportChannelMultihomedTest, TestFailoverControllingSide) {
DestroyChannels();
}
+// Test that the backup connection is pinged at a rate no faster than
+// what was configured.
+TEST_F(P2PTransportChannelMultihomedTest, TestPingBackupConnectionRate) {
+ AddAddress(0, kPublicAddrs[0]);
+ // Adding alternate address will make sure |kPublicAddrs| has the higher
+ // priority than others. This is due to FakeNetwork::AddInterface method.
+ AddAddress(1, kAlternateAddrs[1]);
+ AddAddress(1, kPublicAddrs[1]);
+
+ // Use only local ports for simplicity.
+ SetAllocatorFlags(0, kOnlyLocalPorts);
+ SetAllocatorFlags(1, kOnlyLocalPorts);
+
+ // Create channels and let them go writable, as usual.
+ CreateChannels(1);
+ EXPECT_TRUE_WAIT_MARGIN(ep1_ch1()->receiving() && ep1_ch1()->writable() &&
+ ep2_ch1()->receiving() && ep2_ch1()->writable(),
+ 1000, 1000);
+ int backup_ping_interval = 2000;
+ ep2_ch1()->SetIceConfig(CreateIceConfig(2000, false, backup_ping_interval));
+ // After the state becomes COMPLETED, the backup connection will be pinged
+ // once every |backup_ping_interval| milliseconds.
+ ASSERT_TRUE_WAIT(ep2_ch1()->GetState() == cricket::STATE_COMPLETED, 1000);
+ const std::vector<cricket::Connection*>& connections =
+ ep2_ch1()->connections();
+ ASSERT_EQ(2U, connections.size());
+ cricket::Connection* backup_conn = connections[1];
+ EXPECT_TRUE_WAIT(backup_conn->writable(), 3000);
+ uint32_t last_ping_response_ms = backup_conn->last_ping_response_received();
+ EXPECT_TRUE_WAIT(
+ last_ping_response_ms < backup_conn->last_ping_response_received(), 5000);
+ int time_elapsed =
+ backup_conn->last_ping_response_received() - last_ping_response_ms;
+ LOG(LS_INFO) << "Time elapsed: " << time_elapsed;
+ EXPECT_GE(time_elapsed, backup_ping_interval);
+}
+
TEST_F(P2PTransportChannelMultihomedTest, TestGetState) {
AddAddress(0, kAlternateAddrs[0]);
AddAddress(0, kPublicAddrs[0]);
@@ -1707,12 +1767,14 @@ class P2PTransportChannelPingTest : public testing::Test,
cricket::Candidate CreateCandidate(const std::string& ip,
int port,
- int priority) {
+ int priority,
+ const std::string& ufrag = "") {
cricket::Candidate c;
c.set_address(rtc::SocketAddress(ip, port));
c.set_component(1);
c.set_protocol(cricket::UDP_PROTOCOL_NAME);
c.set_priority(priority);
+ c.set_username(ufrag);
return c;
}
@@ -1796,6 +1858,62 @@ TEST_F(P2PTransportChannelPingTest, TestNoTriggeredChecksWhenWritable) {
EXPECT_EQ(conn2, ch.FindNextPingableConnection());
}
+// Test adding remote candidates with different ufrags. If a remote candidate
+// is added with an old ufrag, it will be discarded. If it is added with a
+// ufrag that was not seen before, it will be used to create connections
+// although the ICE pwd in the remote candidate will be set when the ICE
+// credentials arrive. If a remote candidate is added with the current ICE
+// ufrag, its pwd and generation will be set properly.
+TEST_F(P2PTransportChannelPingTest, TestAddRemoteCandidateWithVariousUfrags) {
+ cricket::FakePortAllocator pa(rtc::Thread::Current(), nullptr);
+ cricket::P2PTransportChannel ch("add candidate", 1, nullptr, &pa);
+ PrepareChannel(&ch);
+ ch.Connect();
+ ch.MaybeStartGathering();
+ // Add a candidate with a future ufrag.
+ ch.AddRemoteCandidate(CreateCandidate("1.1.1.1", 1, 1, kIceUfrag[2]));
+ cricket::Connection* conn1 = WaitForConnectionTo(&ch, "1.1.1.1", 1);
+ ASSERT_TRUE(conn1 != nullptr);
+ const cricket::Candidate& candidate = conn1->remote_candidate();
+ EXPECT_EQ(kIceUfrag[2], candidate.username());
+ EXPECT_TRUE(candidate.password().empty());
+ EXPECT_TRUE(ch.FindNextPingableConnection() == nullptr);
+
+ // Set the remote credentials with the "future" ufrag.
+ // This should set the ICE pwd in the remote candidate of |conn1|, making
+ // it pingable.
+ ch.SetRemoteIceCredentials(kIceUfrag[2], kIcePwd[2]);
+ EXPECT_EQ(kIceUfrag[2], candidate.username());
+ EXPECT_EQ(kIcePwd[2], candidate.password());
+ EXPECT_EQ(conn1, ch.FindNextPingableConnection());
+
+ // Add a candidate with an old ufrag. No connection will be created.
+ ch.AddRemoteCandidate(CreateCandidate("2.2.2.2", 2, 2, kIceUfrag[1]));
+ rtc::Thread::Current()->ProcessMessages(500);
+ EXPECT_TRUE(GetConnectionTo(&ch, "2.2.2.2", 2) == nullptr);
+
+ // Add a candidate with the current ufrag, its pwd and generation will be
+ // assigned, even if the generation is not set.
+ ch.AddRemoteCandidate(CreateCandidate("3.3.3.3", 3, 0, kIceUfrag[2]));
+ cricket::Connection* conn3 = nullptr;
+ ASSERT_TRUE_WAIT((conn3 = GetConnectionTo(&ch, "3.3.3.3", 3)) != nullptr,
+ 3000);
+ const cricket::Candidate& new_candidate = conn3->remote_candidate();
+ EXPECT_EQ(kIcePwd[2], new_candidate.password());
+ EXPECT_EQ(1U, new_candidate.generation());
+
+ // Check that the pwd of all remote candidates are properly assigned.
+ for (const cricket::RemoteCandidate& candidate : ch.remote_candidates()) {
+ EXPECT_TRUE(candidate.username() == kIceUfrag[1] ||
+ candidate.username() == kIceUfrag[2]);
+ if (candidate.username() == kIceUfrag[1]) {
+ EXPECT_EQ(kIcePwd[1], candidate.password());
+ } else if (candidate.username() == kIceUfrag[2]) {
+ EXPECT_EQ(kIcePwd[2], candidate.password());
+ }
+ }
+}
+
TEST_F(P2PTransportChannelPingTest, ConnectionResurrection) {
cricket::FakePortAllocator pa(rtc::Thread::Current(), nullptr);
cricket::P2PTransportChannel ch("connection resurrection", 1, nullptr, &pa);
@@ -1868,7 +1986,7 @@ TEST_F(P2PTransportChannelPingTest, TestReceivingStateChange) {
conn1->ReceivedPing();
conn1->OnReadPacket("ABC", 3, rtc::CreatePacketTime(0));
- EXPECT_TRUE_WAIT(ch.best_connection() != nullptr, 1000)
+ EXPECT_TRUE_WAIT(ch.best_connection() != nullptr, 1000);
EXPECT_TRUE_WAIT(ch.receiving(), 1000);
EXPECT_TRUE_WAIT(!ch.receiving(), 1000);
}
@@ -1932,7 +2050,8 @@ TEST_F(P2PTransportChannelPingTest, TestSelectConnectionBeforeNomination) {
// The controlled side will select a connection as the "best connection" based
// on requests from an unknown address before the controlling side nominates
// a connection, and will nominate a connection from an unknown address if the
-// request contains the use_candidate attribute.
+// request contains the use_candidate attribute. Plus, it will also sends back
+// a ping response and set the ICE pwd in the remote candidate appropriately.
TEST_F(P2PTransportChannelPingTest, TestSelectConnectionFromUnknownAddress) {
cricket::FakePortAllocator pa(rtc::Thread::Current(), nullptr);
cricket::P2PTransportChannel ch("receiving state change", 1, nullptr, &pa);
@@ -1948,14 +2067,16 @@ TEST_F(P2PTransportChannelPingTest, TestSelectConnectionFromUnknownAddress) {
uint32_t prflx_priority = cricket::ICE_TYPE_PREFERENCE_PRFLX << 24;
request.AddAttribute(new cricket::StunUInt32Attribute(
cricket::STUN_ATTR_PRIORITY, prflx_priority));
- cricket::Port* port = GetPort(&ch);
+ cricket::TestUDPPort* port = static_cast<cricket::TestUDPPort*>(GetPort(&ch));
port->SignalUnknownAddress(port, rtc::SocketAddress("1.1.1.1", 1),
cricket::PROTO_UDP, &request, kIceUfrag[1], false);
cricket::Connection* conn1 = WaitForConnectionTo(&ch, "1.1.1.1", 1);
ASSERT_TRUE(conn1 != nullptr);
+ EXPECT_TRUE(port->sent_binding_response());
EXPECT_EQ(conn1, ch.best_connection());
conn1->ReceivedPingResponse();
EXPECT_EQ(conn1, ch.best_connection());
+ port->set_sent_binding_response(false);
// Another connection is nominated via use_candidate.
ch.AddRemoteCandidate(CreateCandidate("2.2.2.2", 2, 1));
@@ -1977,8 +2098,10 @@ TEST_F(P2PTransportChannelPingTest, TestSelectConnectionFromUnknownAddress) {
cricket::PROTO_UDP, &request, kIceUfrag[1], false);
cricket::Connection* conn3 = WaitForConnectionTo(&ch, "3.3.3.3", 3);
ASSERT_TRUE(conn3 != nullptr);
+ EXPECT_TRUE(port->sent_binding_response());
conn3->ReceivedPingResponse(); // Become writable.
EXPECT_EQ(conn2, ch.best_connection());
+ port->set_sent_binding_response(false);
// However if the request contains use_candidate attribute, it will be
// selected as the best connection.
@@ -1988,10 +2111,23 @@ TEST_F(P2PTransportChannelPingTest, TestSelectConnectionFromUnknownAddress) {
cricket::PROTO_UDP, &request, kIceUfrag[1], false);
cricket::Connection* conn4 = WaitForConnectionTo(&ch, "4.4.4.4", 4);
ASSERT_TRUE(conn4 != nullptr);
+ 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.
EXPECT_EQ(conn4, ch.best_connection());
+
+ // Test that the request from an unknown address contains a ufrag from an old
+ // generation.
+ port->set_sent_binding_response(false);
+ ch.SetRemoteIceCredentials(kIceUfrag[2], kIcePwd[2]);
+ ch.SetRemoteIceCredentials(kIceUfrag[3], kIcePwd[3]);
+ port->SignalUnknownAddress(port, rtc::SocketAddress("5.5.5.5", 5),
+ cricket::PROTO_UDP, &request, kIceUfrag[2], false);
+ cricket::Connection* conn5 = WaitForConnectionTo(&ch, "5.5.5.5", 5);
+ ASSERT_TRUE(conn5 != nullptr);
+ EXPECT_TRUE(port->sent_binding_response());
+ EXPECT_EQ(kIcePwd[2], conn5->remote_candidate().password());
}
// The controlled side will select a connection as the "best connection"
@@ -2114,7 +2250,9 @@ TEST_F(P2PTransportChannelPingTest, TestGetState) {
EXPECT_TRUE_WAIT(conn2->pruned(), 1000);
EXPECT_EQ(cricket::TransportChannelState::STATE_COMPLETED, ch.GetState());
conn1->Prune(); // All connections are pruned.
- EXPECT_EQ(cricket::TransportChannelState::STATE_FAILED, ch.GetState());
+ // Need to wait until the channel state is updated.
+ EXPECT_EQ_WAIT(cricket::TransportChannelState::STATE_FAILED, ch.GetState(),
+ 1000);
}
// Test that when a low-priority connection is pruned, it is not deleted
@@ -2190,3 +2328,31 @@ TEST_F(P2PTransportChannelPingTest, TestDeleteConnectionsIfAllWriteTimedout) {
conn3->Prune();
EXPECT_TRUE_WAIT(ch.connections().empty(), 1000);
}
+
+// Test that after a port allocator session is started, it will be stopped
+// when a new connection becomes writable and receiving. Also test that this
+// holds even if the transport channel did not lose the writability.
+TEST_F(P2PTransportChannelPingTest, TestStopPortAllocatorSessions) {
+ cricket::FakePortAllocator pa(rtc::Thread::Current(), nullptr);
+ cricket::P2PTransportChannel ch("test channel", 1, nullptr, &pa);
+ PrepareChannel(&ch);
+ ch.SetIceConfig(CreateIceConfig(2000, false));
+ ch.Connect();
+ ch.MaybeStartGathering();
+ ch.AddRemoteCandidate(CreateCandidate("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
+ EXPECT_TRUE(!ch.allocator_session()->IsGettingPorts());
+
+ // Restart gathering even if the transport channel is still writable.
+ // It should stop getting ports after a new connection becomes strongly
+ // connected.
+ ch.SetIceCredentials(kIceUfrag[1], kIcePwd[1]);
+ ch.MaybeStartGathering();
+ ch.AddRemoteCandidate(CreateCandidate("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
+ EXPECT_TRUE(!ch.allocator_session()->IsGettingPorts());
+}