| Index: webrtc/p2p/base/p2ptransportchannel_unittest.cc
|
| diff --git a/webrtc/p2p/base/p2ptransportchannel_unittest.cc b/webrtc/p2p/base/p2ptransportchannel_unittest.cc
|
| index f2c7de5b442be0e97d192396cc2e854fe25a8cda..d2a3e5c5cfa17bba98731bfb8187c0ce33b90216 100644
|
| --- a/webrtc/p2p/base/p2ptransportchannel_unittest.cc
|
| +++ b/webrtc/p2p/base/p2ptransportchannel_unittest.cc
|
| @@ -1750,3 +1750,181 @@ TEST_F(P2PTransportChannelPingTest, TestReceivingStateChange) {
|
| EXPECT_TRUE_WAIT(ch.receiving(), 1000);
|
| EXPECT_TRUE_WAIT(!ch.receiving(), 1000);
|
| }
|
| +
|
| +// The controlled side will select a connection as the "best connection" based
|
| +// on priority until the controlling side nominates a connection, at which
|
| +// point the controlled side will select that connection as the
|
| +// "best connection".
|
| +TEST_F(P2PTransportChannelPingTest, TestSelectConnectionBeforeNomination) {
|
| + cricket::FakePortAllocator pa(rtc::Thread::Current(), nullptr);
|
| + cricket::P2PTransportChannel ch("receiving state change", 1, nullptr, &pa);
|
| + PrepareChannel(&ch);
|
| + ch.SetIceRole(cricket::ICEROLE_CONTROLLED);
|
| + ch.Connect();
|
| + ch.OnCandidate(CreateCandidate("1.1.1.1", 1, 1));
|
| + cricket::Connection* conn1 = WaitForConnectionTo(&ch, "1.1.1.1", 1);
|
| + ASSERT_TRUE(conn1 != nullptr);
|
| + EXPECT_EQ(conn1, ch.best_connection());
|
| +
|
| + // When a higher priority candidate comes in, the new connection is chosen
|
| + // as the best connection.
|
| + ch.OnCandidate(CreateCandidate("2.2.2.2", 2, 10));
|
| + cricket::Connection* conn2 = WaitForConnectionTo(&ch, "2.2.2.2", 2);
|
| + ASSERT_TRUE(conn1 != nullptr);
|
| + EXPECT_EQ(conn2, ch.best_connection());
|
| +
|
| + // If a stun request with use-candidate attribute arrives, the receiving
|
| + // connection will be set as the best connection, even though
|
| + // its priority is lower.
|
| + ch.OnCandidate(CreateCandidate("3.3.3.3", 3, 1));
|
| + cricket::Connection* conn3 = WaitForConnectionTo(&ch, "3.3.3.3", 3);
|
| + 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.
|
| + // But if it is nominated via use_candidate, it is chosen as the best
|
| + // connection.
|
| + conn3->set_nominated(true);
|
| + conn3->SignalNominated(conn3);
|
| + EXPECT_EQ(conn3, ch.best_connection());
|
| +
|
| + // Even if another higher priority candidate arrives,
|
| + // it will not be set as the best connection because the best connection
|
| + // is nominated by the controlling side.
|
| + ch.OnCandidate(CreateCandidate("4.4.4.4", 4, 100));
|
| + cricket::Connection* conn4 = WaitForConnectionTo(&ch, "4.4.4.4", 4);
|
| + ASSERT_TRUE(conn4 != nullptr);
|
| + EXPECT_EQ(conn3, ch.best_connection());
|
| + // But if it is nominated via use_candidate and writable, it will be set as
|
| + // the best connection.
|
| + conn4->set_nominated(true);
|
| + conn4->SignalNominated(conn4);
|
| + // Not switched yet because conn4 is not writable.
|
| + EXPECT_EQ(conn3, ch.best_connection());
|
| + // The best connection switches after conn4 becomes writable.
|
| + conn4->ReceivedPingResponse();
|
| + EXPECT_EQ(conn4, ch.best_connection());
|
| +}
|
| +
|
| +// 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.
|
| +TEST_F(P2PTransportChannelPingTest, TestSelectConnectionFromUnknownAddress) {
|
| + cricket::FakePortAllocator pa(rtc::Thread::Current(), nullptr);
|
| + cricket::P2PTransportChannel ch("receiving state change", 1, nullptr, &pa);
|
| + PrepareChannel(&ch);
|
| + ch.SetIceRole(cricket::ICEROLE_CONTROLLED);
|
| + ch.Connect();
|
| + // A minimal STUN message with prflx priority.
|
| + cricket::IceMessage request;
|
| + request.SetType(cricket::STUN_BINDING_REQUEST);
|
| + request.AddAttribute(new cricket::StunByteStringAttribute(
|
| + cricket::STUN_ATTR_USERNAME, kIceUfrag[1]));
|
| + uint32 prflx_priority = cricket::ICE_TYPE_PREFERENCE_PRFLX << 24;
|
| + request.AddAttribute(new cricket::StunUInt32Attribute(
|
| + cricket::STUN_ATTR_PRIORITY, prflx_priority));
|
| + cricket::Port* port = 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_EQ(conn1, ch.best_connection());
|
| + conn1->ReceivedPingResponse();
|
| + EXPECT_EQ(conn1, ch.best_connection());
|
| +
|
| + // Another connection is nominated via use_candidate.
|
| + ch.OnCandidate(CreateCandidate("2.2.2.2", 2, 1));
|
| + cricket::Connection* conn2 = WaitForConnectionTo(&ch, "2.2.2.2", 2);
|
| + ASSERT_TRUE(conn2 != nullptr);
|
| + // Because it has a lower priority, the best connection is still conn1.
|
| + 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->set_nominated(true);
|
| + conn2->SignalNominated(conn2);
|
| + EXPECT_EQ(conn2, ch.best_connection());
|
| +
|
| + // Another request with unknown address, it will not be set as the best
|
| + // connection because the best connection was nominated by the controlling
|
| + // side.
|
| + port->SignalUnknownAddress(port, rtc::SocketAddress("3.3.3.3", 3),
|
| + cricket::PROTO_UDP, &request, kIceUfrag[1], false);
|
| + cricket::Connection* conn3 = WaitForConnectionTo(&ch, "3.3.3.3", 3);
|
| + ASSERT_TRUE(conn3 != nullptr);
|
| + conn3->ReceivedPingResponse(); // Become writable.
|
| + EXPECT_EQ(conn2, ch.best_connection());
|
| +
|
| + // However if the request contains use_candidate attribute, it will be
|
| + // selected as the best connection.
|
| + request.AddAttribute(
|
| + new cricket::StunByteStringAttribute(cricket::STUN_ATTR_USE_CANDIDATE));
|
| + port->SignalUnknownAddress(port, rtc::SocketAddress("4.4.4.4", 4),
|
| + cricket::PROTO_UDP, &request, kIceUfrag[1], false);
|
| + cricket::Connection* conn4 = WaitForConnectionTo(&ch, "4.4.4.4", 4);
|
| + ASSERT_TRUE(conn4 != nullptr);
|
| + // 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());
|
| +}
|
| +
|
| +// The controlled side will select a connection as the "best connection"
|
| +// based on media received until the controlling side nominates a connection,
|
| +// at which point the controlled side will select that connection as
|
| +// the "best connection".
|
| +TEST_F(P2PTransportChannelPingTest, TestSelectConnectionBasedOnMediaReceived) {
|
| + cricket::FakePortAllocator pa(rtc::Thread::Current(), nullptr);
|
| + cricket::P2PTransportChannel ch("receiving state change", 1, nullptr, &pa);
|
| + PrepareChannel(&ch);
|
| + ch.SetIceRole(cricket::ICEROLE_CONTROLLED);
|
| + ch.Connect();
|
| + ch.OnCandidate(CreateCandidate("1.1.1.1", 1, 10));
|
| + cricket::Connection* conn1 = WaitForConnectionTo(&ch, "1.1.1.1", 1);
|
| + ASSERT_TRUE(conn1 != nullptr);
|
| + EXPECT_EQ(conn1, ch.best_connection());
|
| +
|
| + // If a data packet is received on conn2, the best connection should
|
| + // switch to conn2 because the controlled side must mirror the media path
|
| + // chosen by the controlling side.
|
| + ch.OnCandidate(CreateCandidate("2.2.2.2", 2, 1));
|
| + cricket::Connection* conn2 = WaitForConnectionTo(&ch, "2.2.2.2", 2);
|
| + ASSERT_TRUE(conn2 != nullptr);
|
| + conn2->ReceivedPing(); // Become readable.
|
| + // Do not switch because it is not writable.
|
| + conn2->OnReadPacket("ABC", 3, rtc::CreatePacketTime(0));
|
| + EXPECT_EQ(conn1, ch.best_connection());
|
| +
|
| + conn2->ReceivedPingResponse(); // Become writable.
|
| + // Switch because it is writable.
|
| + conn2->OnReadPacket("DEF", 3, rtc::CreatePacketTime(0));
|
| + EXPECT_EQ(conn2, ch.best_connection());
|
| +
|
| + // Now another STUN message with an unknown address and use_candidate will
|
| + // nominate the best connection.
|
| + cricket::IceMessage request;
|
| + request.SetType(cricket::STUN_BINDING_REQUEST);
|
| + request.AddAttribute(new cricket::StunByteStringAttribute(
|
| + cricket::STUN_ATTR_USERNAME, kIceUfrag[1]));
|
| + uint32 prflx_priority = cricket::ICE_TYPE_PREFERENCE_PRFLX << 24;
|
| + request.AddAttribute(new cricket::StunUInt32Attribute(
|
| + cricket::STUN_ATTR_PRIORITY, prflx_priority));
|
| + request.AddAttribute(
|
| + new cricket::StunByteStringAttribute(cricket::STUN_ATTR_USE_CANDIDATE));
|
| + cricket::Port* port = GetPort(&ch);
|
| + port->SignalUnknownAddress(port, rtc::SocketAddress("3.3.3.3", 3),
|
| + cricket::PROTO_UDP, &request, kIceUfrag[1], false);
|
| + 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.
|
| + 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->OnReadPacket("XYZ", 3, rtc::CreatePacketTime(0));
|
| + EXPECT_EQ(conn3, ch.best_connection());
|
| +}
|
|
|