using ::testing::_;
using ::testing::DoAll;
using ::testing::Eq;
using ::testing::Field;
using ::testing::IsTrue;
using ::testing::Return;
using ::testing::ReturnPointee;
using ::testing::SetArgPointee;
// Base class for tests connecting a StunPort to a fake STUN server // (StunServer). class StunPortTest : public ::testing::Test {
public:
StunPortTest()
: StunPortTest(kPrivateIP.ipaddr(),
{kStunServerAddr1, kStunServerAddr2},
kNatAddr) {}
Thread* network_thread_;
NATSocketFactory nat_factory_;
BasicPacketSocketFactory nat_socket_factory_; // Note that stun_port_ can refer to socket_, so must be destroyed // before it.
std::unique_ptr<AsyncPacketSocket> socket_;
std::unique_ptr<UDPPort> stun_port_;
std::vector<TestStunServer::StunServerPtr> stun_servers_;
std::unique_ptr<MdnsResponderProvider> mdns_responder_provider_;
std::unique_ptr<NATServer> nat_server_; bool done_; bool error_;
TimeDelta stun_keepalive_delay_;
std::optional<TimeDelta> stun_keepalive_lifetime_;
// Test that we can create a STUN port.
TEST_F(StunPortTest, TestCreateStunPort) {
CreateStunPort(kStunServerAddr1);
EXPECT_EQ(IceCandidateType::kSrflx, port()->Type());
EXPECT_EQ(0U, port()->Candidates().size());
}
// Test that we can create a UDP port.
TEST_F(StunPortTest, TestCreateUdpPort) {
CreateSharedUdpPort(kStunServerAddr1, nullptr);
EXPECT_EQ(IceCandidateType::kHost, port()->Type());
EXPECT_EQ(0U, port()->Candidates().size());
}
// Test that we can get an address from a STUN server.
TEST_F(StunPortTest, TestPrepareAddress) {
CreateStunPort(kStunServerAddr1);
PrepareAddress();
EXPECT_TRUE(WaitUntil([this] { return done(); },
{.timeout = kTimeout, .clock = &time_controller_}));
ASSERT_EQ(1U, port()->Candidates().size());
EXPECT_TRUE(kPublicIP.EqualIPs(port()->Candidates()[0].address()));
std::string expected_server_url = "stun:" + kStunServerAddr1.ToString();
EXPECT_EQ(port()->Candidates()[0].url(), expected_server_url);
}
// Test that we fail properly if we can't get an address.
TEST_F(StunPortTest, TestPrepareAddressFail) {
CreateStunPort(kBadAddr);
PrepareAddress();
EXPECT_TRUE(WaitUntil([this] { return done(); },
{.timeout = kTimeout, .clock = &time_controller_}));
EXPECT_TRUE(error());
EXPECT_EQ(0U, port()->Candidates().size());
EXPECT_EQ(error_event_.error_code, STUN_ERROR_SERVER_NOT_REACHABLE);
EXPECT_NE(error_event_.error_text.find('.'), std::string::npos);
EXPECT_NE(error_event_.address.find(kPrivateIP.HostAsSensitiveURIString()),
std::string::npos);
std::string server_url = "stun:" + kBadAddr.ToString();
EXPECT_EQ(error_event_.url, server_url);
}
// Test that we fail without emitting an error if we try to get an address from // a STUN server with a different address family. IPv4 local, IPv6 STUN.
TEST_F(StunPortTest, TestServerAddressFamilyMismatch) {
CreateStunPort(kStunServerAddrIPv6Addr);
PrepareAddress();
EXPECT_TRUE(WaitUntil([this] { return done(); },
{.timeout = kTimeout, .clock = &time_controller_}));
EXPECT_TRUE(error());
EXPECT_EQ(0U, port()->Candidates().size());
EXPECT_EQ(0, error_event_.error_code);
}
class StunPortWithMockDnsResolverTest : public StunPortTest {
public:
StunPortWithMockDnsResolverTest()
: StunPortTest(), socket_factory_(nat_factory()) {}
// Test that we can get an address from a STUN server specified by a hostname.
TEST_F(StunPortWithMockDnsResolverTest, TestPrepareAddressHostname) {
SetDnsResolverExpectations([](MockAsyncDnsResolver* resolver,
MockAsyncDnsResolverResult* resolver_result) {
EXPECT_CALL(*resolver, Start(kValidHostnameAddr, /*family=*/AF_INET, _))
.WillOnce([](const SocketAddress& /* addr */, int /* family */,
absl::AnyInvocable<void()> callback) { callback(); });
// Test that we handle hostname lookup failures properly. // Test that we fail to get an address from a STUN server specified by an // invalid hostname.
TEST_F(StunPortWithMockDnsResolverTest, TestPrepareAddressHostnameFail) {
SetDnsResolverExpectations([](MockAsyncDnsResolver* resolver,
MockAsyncDnsResolverResult* resolver_result) {
EXPECT_CALL(*resolver, Start(kBadHostnameAddr, /*family=*/AF_INET, _))
.WillOnce([](const SocketAddress& /* addr */, int /* family */,
absl::AnyInvocable<void()> callback) { callback(); });
// This test verifies keepalive response messages don't result in // additional candidate generation.
TEST_F(StunPortTest, TestKeepAliveResponse) {
SetKeepaliveDelay(TimeDelta::Millis(500));
CreateStunPort(kStunServerAddr1);
PrepareAddress();
EXPECT_TRUE(WaitUntil([this] { return done(); },
{.timeout = kTimeout, .clock = &time_controller_}));
ASSERT_EQ(1U, port()->Candidates().size());
EXPECT_TRUE(kPublicIP.EqualIPs(port()->Candidates()[0].address()));
time_controller_.AdvanceTime(TimeDelta::Millis(1000));
EXPECT_EQ(1U, port()->Candidates().size());
}
// Test that a local candidate can be generated using a shared socket.
TEST_F(StunPortTest, TestSharedSocketPrepareAddress) {
CreateSharedUdpPort(kStunServerAddr1, nullptr);
PrepareAddress();
EXPECT_TRUE(WaitUntil([this] { return done(); },
{.timeout = kTimeout, .clock = &time_controller_}));
ASSERT_EQ(2U, port()->Candidates().size());
EXPECT_EQ(port()->Candidates()[0].type(), IceCandidateType::kHost);
EXPECT_TRUE(kPrivateIP.EqualIPs(port()->Candidates()[0].address()));
EXPECT_EQ(port()->Candidates()[1].type(), IceCandidateType::kSrflx);
EXPECT_TRUE(kPublicIP.EqualIPs(port()->Candidates()[1].address()));
}
// Test that we still get a local candidate with invalid stun server hostname. // Also verifing that UDPPort can receive packets when stun address can't be // resolved.
TEST_F(StunPortWithMockDnsResolverTest,
TestSharedSocketPrepareAddressInvalidHostname) {
SetDnsResolverExpectations([](MockAsyncDnsResolver* resolver,
MockAsyncDnsResolverResult* resolver_result) {
EXPECT_CALL(*resolver, Start(kBadHostnameAddr, /*family=*/AF_INET, _))
.WillOnce([](const SocketAddress& /* addr */, int /* family */,
absl::AnyInvocable<void()> callback) { callback(); });
// Send data to port after it's ready. This is to make sure, UDP port can // handle data with unresolved stun server address.
std::string data = "some random data, sending to Port.";
SendData(data.c_str(), data.length()); // No crash is success.
}
// Test that a stun candidate (srflx candidate) is generated whose address is // equal to that of a local candidate if mDNS obfuscation is enabled.
TEST_F(StunPortTest, TestStunCandidateGeneratedWithMdnsObfuscationEnabled) {
EnableMdnsObfuscation();
CreateSharedUdpPort(kStunServerAddr1, nullptr);
PrepareAddress();
EXPECT_TRUE(WaitUntil([this] { return done(); },
{.timeout = kTimeout, .clock = &time_controller_}));
ASSERT_EQ(2U, port()->Candidates().size());
// One of the generated candidates is a local candidate and the other is a // stun candidate.
EXPECT_NE(port()->Candidates()[0].type(), port()->Candidates()[1].type()); if (port()->Candidates()[0].is_local()) {
EXPECT_EQ(kMsdnAddress.HostAsSensitiveURIString(),
port()->Candidates()[0].address().HostAsSensitiveURIString());
EXPECT_TRUE(port()->Candidates()[1].is_stun());
EXPECT_TRUE(kPublicIP.EqualIPs(port()->Candidates()[1].address()));
} else {
EXPECT_TRUE(port()->Candidates()[0].is_stun());
EXPECT_TRUE(kPublicIP.EqualIPs(port()->Candidates()[0].address()));
EXPECT_TRUE(port()->Candidates()[1].is_local());
EXPECT_EQ(kMsdnAddress.HostAsSensitiveURIString(),
port()->Candidates()[1].address().HostAsSensitiveURIString());
}
}
// Test that the same address is added only once if two STUN servers are in // use.
TEST_F(StunPortTest, TestNoDuplicatedAddressWithTwoStunServers) {
ServerAddresses stun_servers;
stun_servers.insert(kStunServerAddr1);
stun_servers.insert(kStunServerAddr2);
CreateStunPort(stun_servers);
EXPECT_EQ(IceCandidateType::kSrflx, port()->Type());
PrepareAddress();
EXPECT_TRUE(WaitUntil([this] { return done(); },
{.timeout = kTimeout, .clock = &time_controller_}));
EXPECT_EQ(1U, port()->Candidates().size());
EXPECT_EQ(port()->Candidates()[0].relay_protocol(), "");
}
// Test that candidates can be allocated for multiple STUN servers, one of // which is not reachable.
TEST_F(StunPortTest, TestMultipleStunServersWithBadServer) {
ServerAddresses stun_servers;
stun_servers.insert(kStunServerAddr1);
stun_servers.insert(kBadAddr);
CreateStunPort(stun_servers);
EXPECT_EQ(IceCandidateType::kSrflx, port()->Type());
PrepareAddress();
EXPECT_TRUE(WaitUntil([this] { return done(); },
{.timeout = kTimeout, .clock = &time_controller_}));
EXPECT_EQ(1U, port()->Candidates().size());
std::string server_url = "stun:" + kBadAddr.ToString();
EXPECT_EQ(error_event_.url, server_url);
}
// Test that two candidates are allocated if the two STUN servers return // different mapped addresses.
TEST_F(StunPortTest, TestTwoCandidatesWithTwoStunServersAcrossNat) { const SocketAddress kStunMappedAddr1("77.77.77.77", 0); const SocketAddress kStunMappedAddr2("88.77.77.77", 0);
stun_server_1()->set_fake_stun_addr(kStunMappedAddr1);
stun_server_2()->set_fake_stun_addr(kStunMappedAddr2);
// Test that the stun_keepalive_lifetime is set correctly based on the network // type on a STUN port. Also test that it will be updated if the network type // changes.
TEST_F(StunPortTest, TestStunPortGetStunKeepaliveLifetime) { // Lifetime for the default (unknown) network type is infinite.
CreateStunPort(kStunServerAddr1);
EXPECT_EQ(port()->stun_keepalive_lifetime(), TimeDelta::PlusInfinity()); // Lifetime for the cellular network is `kHighCostPortKeepaliveLifetime`
SetNetworkType(ADAPTER_TYPE_CELLULAR);
EXPECT_EQ(port()->stun_keepalive_lifetime(), kHighCostPortKeepaliveLifetime);
// Lifetime for the wifi network is infinite.
SetNetworkType(ADAPTER_TYPE_WIFI);
CreateStunPort(kStunServerAddr2);
EXPECT_EQ(port()->stun_keepalive_lifetime(), TimeDelta::PlusInfinity());
}
// Test that the stun_keepalive_lifetime is set correctly based on the network // type on a shared STUN port (UDPPort). Also test that it will be updated // if the network type changes.
TEST_F(StunPortTest, TestUdpPortGetStunKeepaliveLifetime) { // Lifetime for the default (unknown) network type is infinite.
CreateSharedUdpPort(kStunServerAddr1, nullptr);
EXPECT_EQ(port()->stun_keepalive_lifetime(), TimeDelta::PlusInfinity()); // Lifetime for the cellular network is `kHighCostPortKeepaliveLifetime`.
SetNetworkType(ADAPTER_TYPE_CELLULAR);
EXPECT_EQ(port()->stun_keepalive_lifetime(), kHighCostPortKeepaliveLifetime);
// Lifetime for the wifi network type is infinite.
SetNetworkType(ADAPTER_TYPE_WIFI);
CreateSharedUdpPort(kStunServerAddr2, nullptr);
EXPECT_EQ(port()->stun_keepalive_lifetime(), TimeDelta::PlusInfinity());
}
// Test that STUN binding requests will be stopped shortly if the keep-alive // lifetime is short.
TEST_F(StunPortTest, TestStunBindingRequestShortLifetime) {
SetKeepaliveDelay(TimeDelta::Millis(101));
SetKeepaliveLifetime(TimeDelta::Millis(100));
CreateStunPort(kStunServerAddr1);
PrepareAddress();
EXPECT_TRUE(WaitUntil([this] { return done(); },
{.timeout = kTimeout, .clock = &time_controller_}));
EXPECT_TRUE(
WaitUntil([&] { return !HasPendingRequest(STUN_BINDING_REQUEST); },
{.timeout = kTimeout, .clock = &time_controller_}));
}
// Test that by default, the STUN binding requests will last for a long time.
TEST_F(StunPortTest, TestStunBindingRequestLongLifetime) {
SetKeepaliveDelay(TimeDelta::Millis(101));
CreateStunPort(kStunServerAddr1);
PrepareAddress();
EXPECT_TRUE(WaitUntil([this] { return done(); },
{.timeout = kTimeout, .clock = &time_controller_}));
EXPECT_TRUE(WaitUntil([&] { return HasPendingRequest(STUN_BINDING_REQUEST); },
{.timeout = kTimeout, .clock = &time_controller_}));
}
class StunPortIPAddressTypeMetricsTest
: public StunPortWithMockDnsResolverTest,
public ::testing::WithParamInterface<IPAddressTypeTestConfig> {};
// Test that outbound packets inherit the dscp value assigned to the socket.
TEST_F(StunPortTest, TestStunPacketsHaveDscpPacketOption) { auto mocked_socket = std::make_unique<MockAsyncPacketSocket>();
MockAsyncPacketSocket& socket = *mocked_socket;
CreateSharedUdpPort(kStunServerAddr1, std::move(mocked_socket));
// If DSCP is not set on the socket, stun packets should have no value.
EXPECT_CALL(socket, SendTo(_, _, _,
Field(&AsyncSocketPacketOptions::dscp,
Eq(DSCP_NO_CHANGE))))
.WillOnce(Return(100));
PrepareAddress();
port()->request_manager().Clear();
// Once it is set transport wide, they should inherit that value.
port()->SetOption(Socket::OPT_DSCP, DSCP_AF41);
EXPECT_CALL(
socket,
SendTo(_, _, _, Field(&AsyncSocketPacketOptions::dscp, Eq(DSCP_AF41))))
.WillRepeatedly(Return(100));
class StunIPv6PortTest : public StunPortTest {
public:
StunIPv6PortTest()
: StunPortTest(kPrivateIPv6.ipaddr(),
{kStunServerAddrIPv6Addr},
kNatAddrIPv6) {}
};
// Test that we can get an address from a STUN server.
TEST_F(StunIPv6PortTest, TestPrepareAddress) {
CreateStunPort(kStunServerAddrIPv6Addr);
PrepareAddress();
EXPECT_TRUE(WaitUntil([this] { return done(); },
{.timeout = kTimeout, .clock = &time_controller_}));
ASSERT_EQ(1U, port()->Candidates().size());
EXPECT_TRUE(kPublicIPv6.EqualIPs(port()->Candidates()[0].address()));
std::string expected_server_url = "stun:2003:4860:4860::8844:5000";
EXPECT_EQ(port()->Candidates()[0].url(), expected_server_url);
}
// Test that we fail properly if we can't get an address.
TEST_F(StunIPv6PortTest, TestPrepareAddressFail) {
CreateStunPort(kIPv6BadAddr);
PrepareAddress();
EXPECT_TRUE(WaitUntil([this] { return done(); },
{.timeout = kTimeout, .clock = &time_controller_}));
EXPECT_TRUE(error());
EXPECT_EQ(0U, port()->Candidates().size());
EXPECT_EQ(error_event_.error_code, STUN_ERROR_SERVER_NOT_REACHABLE);
EXPECT_NE(error_event_.error_text.find('.'), std::string::npos);
EXPECT_NE(error_event_.address.find(kPrivateIPv6.HostAsSensitiveURIString()),
std::string::npos);
std::string server_url = "stun:" + kIPv6BadAddr.ToString();
EXPECT_EQ(error_event_.url, server_url);
}
// Test that we fail without emitting an error if we try to get an address from // a STUN server with a different address family. IPv6 local, IPv4 STUN.
TEST_F(StunIPv6PortTest, TestServerAddressFamilyMismatch) {
CreateStunPort(kStunServerAddr1);
PrepareAddress();
EXPECT_TRUE(WaitUntil([this] { return error(); },
{.timeout = kTimeout, .clock = &time_controller_}));
EXPECT_EQ(0U, port()->Candidates().size());
EXPECT_EQ(0, error_event_.error_code);
}
class StunIPv6PortTestWithMockDnsResolver : public StunIPv6PortTest {
public:
StunIPv6PortTestWithMockDnsResolver()
: StunIPv6PortTest(), socket_factory_(ss()) {}
// Test that we fail to get an address from a STUN server specified by an // invalid hostname.
TEST_F(StunIPv6PortTestWithMockDnsResolver, TestPrepareAddressHostnameFail) {
SetDnsResolverExpectations([](MockAsyncDnsResolver* resolver,
MockAsyncDnsResolverResult* resolver_result) {
EXPECT_CALL(*resolver, Start(kBadHostnameAddr, /*family=*/AF_INET6, _))
.WillOnce([](const SocketAddress& /* addr */, int /* family */,
absl::AnyInvocable<void()> callback) { callback(); });
// Test that we can get an address from a STUN server specified by a hostname.
TEST_F(StunIPv6PortTestWithMockDnsResolver, TestPrepareAddressHostname) {
SetDnsResolverExpectations([](MockAsyncDnsResolver* resolver,
MockAsyncDnsResolverResult* resolver_result) {
EXPECT_CALL(*resolver, Start(kValidHostnameAddr, /*family=*/AF_INET6, _))
.WillOnce([](const SocketAddress& addr, int family,
absl::AnyInvocable<void()> callback) { callback(); });
// Same as before but with a field trial that changes the priority.
TEST_F(StunIPv6PortTestWithMockDnsResolver,
TestPrepareAddressHostnameWithPriorityAdjustment) {
FieldTrials field_trials = CreateTestFieldTrials( "WebRTC-IncreaseIceCandidatePriorityHostSrflx/Enabled/");
SetDnsResolverExpectations([](MockAsyncDnsResolver* resolver,
MockAsyncDnsResolverResult* resolver_result) {
EXPECT_CALL(*resolver, Start(kValidHostnameAddr, /*family=*/AF_INET6, _))
.WillOnce([](const SocketAddress& addr, int family,
absl::AnyInvocable<void()> callback) { callback(); });
EXPECT_CALL(*resolver, result)
.WillRepeatedly(ReturnPointee(resolver_result));
EXPECT_CALL(*resolver_result, GetError).WillOnce(Return(0));
EXPECT_CALL(*resolver_result, GetResolvedAddress(AF_INET6, _))
.WillOnce(
DoAll(SetArgPointee<1>(kStunServerAddrIPv6Addr), Return(true)));
});
CreateStunPort(kValidHostnameAddr, &field_trials);
PrepareAddress();
EXPECT_TRUE(WaitUntil([this] { return done(); },
{.timeout = kTimeout, .clock = &time_controller_}));
ASSERT_EQ(1U, port()->Candidates().size());
EXPECT_TRUE(kPrivateIPv6.EqualIPs(port()->Candidates()[0].address()));
EXPECT_EQ(kIPv6StunCandidatePriority + (kMaxTurnServers << 8),
port()->Candidates()[0].priority());
}
class StunIPv6PortIPAddressTypeMetricsTest
: public StunIPv6PortTestWithMockDnsResolver,
public ::testing::WithParamInterface<IPAddressTypeTestConfig> {};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.