278 lines
9.4 KiB
C++
278 lines
9.4 KiB
C++
// Copyright 2012 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "net/base/address_list.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include "base/strings/string_util.h"
|
|
#include "base/sys_byteorder.h"
|
|
#include "net/base/ip_address.h"
|
|
#include "net/base/sockaddr_storage.h"
|
|
#include "net/base/sys_addrinfo.h"
|
|
#include "testing/gmock/include/gmock/gmock.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
|
|
using ::testing::ElementsAre;
|
|
using ::testing::UnorderedElementsAre;
|
|
|
|
namespace net {
|
|
namespace {
|
|
|
|
const char kCanonicalHostname[] = "canonical.bar.com";
|
|
|
|
TEST(AddressListTest, Canonical) {
|
|
// Create an addrinfo with a canonical name.
|
|
struct sockaddr_in address;
|
|
// The contents of address do not matter for this test,
|
|
// so just zero-ing them out for consistency.
|
|
memset(&address, 0x0, sizeof(address));
|
|
// But we need to set the family.
|
|
address.sin_family = AF_INET;
|
|
struct addrinfo ai;
|
|
memset(&ai, 0x0, sizeof(ai));
|
|
ai.ai_family = AF_INET;
|
|
ai.ai_socktype = SOCK_STREAM;
|
|
ai.ai_addrlen = sizeof(address);
|
|
ai.ai_addr = reinterpret_cast<sockaddr*>(&address);
|
|
ai.ai_canonname = const_cast<char *>(kCanonicalHostname);
|
|
|
|
// Copy the addrinfo struct into an AddressList object and
|
|
// make sure it seems correct.
|
|
AddressList addrlist1 = AddressList::CreateFromAddrinfo(&ai);
|
|
EXPECT_THAT(addrlist1.dns_aliases(),
|
|
UnorderedElementsAre("canonical.bar.com"));
|
|
|
|
// Copy the AddressList to another one.
|
|
AddressList addrlist2 = addrlist1;
|
|
EXPECT_THAT(addrlist2.dns_aliases(),
|
|
UnorderedElementsAre("canonical.bar.com"));
|
|
}
|
|
|
|
TEST(AddressListTest, CreateFromAddrinfo) {
|
|
// Create an 4-element addrinfo.
|
|
const unsigned kNumElements = 4;
|
|
SockaddrStorage storage[kNumElements];
|
|
struct addrinfo ai[kNumElements];
|
|
for (unsigned i = 0; i < kNumElements; ++i) {
|
|
struct sockaddr_in* addr =
|
|
reinterpret_cast<struct sockaddr_in*>(storage[i].addr);
|
|
storage[i].addr_len = sizeof(struct sockaddr_in);
|
|
// Populating the address with { i, i, i, i }.
|
|
memset(&addr->sin_addr, i, IPAddress::kIPv4AddressSize);
|
|
addr->sin_family = AF_INET;
|
|
// Set port to i << 2;
|
|
addr->sin_port = base::HostToNet16(static_cast<uint16_t>(i << 2));
|
|
memset(&ai[i], 0x0, sizeof(ai[i]));
|
|
ai[i].ai_family = addr->sin_family;
|
|
ai[i].ai_socktype = SOCK_STREAM;
|
|
ai[i].ai_addrlen = storage[i].addr_len;
|
|
ai[i].ai_addr = storage[i].addr;
|
|
if (i + 1 < kNumElements)
|
|
ai[i].ai_next = &ai[i + 1];
|
|
}
|
|
|
|
AddressList list = AddressList::CreateFromAddrinfo(&ai[0]);
|
|
|
|
ASSERT_EQ(kNumElements, list.size());
|
|
for (size_t i = 0; i < list.size(); ++i) {
|
|
EXPECT_EQ(ADDRESS_FAMILY_IPV4, list[i].GetFamily());
|
|
// Only check the first byte of the address.
|
|
EXPECT_EQ(i, list[i].address().bytes()[0]);
|
|
EXPECT_EQ(static_cast<int>(i << 2), list[i].port());
|
|
}
|
|
|
|
// Check if operator= works.
|
|
AddressList copy;
|
|
copy = list;
|
|
ASSERT_EQ(kNumElements, copy.size());
|
|
|
|
// Check if copy is independent.
|
|
copy[1] = IPEndPoint(copy[2].address(), 0xBEEF);
|
|
// Original should be unchanged.
|
|
EXPECT_EQ(1u, list[1].address().bytes()[0]);
|
|
EXPECT_EQ(1 << 2, list[1].port());
|
|
}
|
|
|
|
TEST(AddressListTest, CreateFromIPAddressList) {
|
|
struct TestData {
|
|
std::string ip_address;
|
|
const char* in_addr;
|
|
int ai_family;
|
|
size_t ai_addrlen;
|
|
size_t in_addr_offset;
|
|
size_t in_addr_size;
|
|
} tests[] = {
|
|
{ "127.0.0.1",
|
|
"\x7f\x00\x00\x01",
|
|
AF_INET,
|
|
sizeof(struct sockaddr_in),
|
|
offsetof(struct sockaddr_in, sin_addr),
|
|
sizeof(struct in_addr),
|
|
},
|
|
{ "2001:db8:0::42",
|
|
"\x20\x01\x0d\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x42",
|
|
AF_INET6,
|
|
sizeof(struct sockaddr_in6),
|
|
offsetof(struct sockaddr_in6, sin6_addr),
|
|
sizeof(struct in6_addr),
|
|
},
|
|
{ "192.168.1.1",
|
|
"\xc0\xa8\x01\x01",
|
|
AF_INET,
|
|
sizeof(struct sockaddr_in),
|
|
offsetof(struct sockaddr_in, sin_addr),
|
|
sizeof(struct in_addr),
|
|
},
|
|
};
|
|
const std::string kCanonicalName = "canonical.example.com";
|
|
|
|
// Construct a list of ip addresses.
|
|
IPAddressList ip_list;
|
|
for (const auto& test : tests) {
|
|
IPAddress ip_address;
|
|
ASSERT_TRUE(ip_address.AssignFromIPLiteral(test.ip_address));
|
|
ip_list.push_back(ip_address);
|
|
}
|
|
|
|
// Wrap the canonical name in an alias vector.
|
|
std::vector<std::string> aliases({kCanonicalName});
|
|
|
|
AddressList test_list =
|
|
AddressList::CreateFromIPAddressList(ip_list, std::move(aliases));
|
|
std::string canonical_name;
|
|
EXPECT_THAT(test_list.dns_aliases(), UnorderedElementsAre(kCanonicalName));
|
|
EXPECT_EQ(std::size(tests), test_list.size());
|
|
}
|
|
|
|
TEST(AddressListTest, GetCanonicalNameWhenUnset) {
|
|
const IPAddress kAddress(1, 2, 3, 4);
|
|
const IPEndPoint kEndpoint(kAddress, 0);
|
|
AddressList addrlist(kEndpoint);
|
|
|
|
EXPECT_TRUE(addrlist.dns_aliases().empty());
|
|
}
|
|
|
|
TEST(AddressListTest, SetDefaultCanonicalNameThenSetDnsAliases) {
|
|
const IPAddress kAddress(1, 2, 3, 4);
|
|
const IPEndPoint kEndpoint(kAddress, 0);
|
|
AddressList addrlist(kEndpoint);
|
|
|
|
addrlist.SetDefaultCanonicalName();
|
|
|
|
EXPECT_THAT(addrlist.dns_aliases(), UnorderedElementsAre("1.2.3.4"));
|
|
|
|
std::vector<std::string> aliases({"alias1", "alias2", "alias3"});
|
|
addrlist.SetDnsAliases(std::move(aliases));
|
|
|
|
// Setting the aliases after setting the default canonical name
|
|
// replaces the default canonical name.
|
|
EXPECT_THAT(addrlist.dns_aliases(),
|
|
UnorderedElementsAre("alias1", "alias2", "alias3"));
|
|
}
|
|
|
|
TEST(AddressListTest, SetDefaultCanonicalNameThenAppendDnsAliases) {
|
|
const IPAddress kAddress(1, 2, 3, 4);
|
|
const IPEndPoint kEndpoint(kAddress, 0);
|
|
AddressList addrlist(kEndpoint);
|
|
|
|
addrlist.SetDefaultCanonicalName();
|
|
|
|
EXPECT_THAT(addrlist.dns_aliases(), UnorderedElementsAre("1.2.3.4"));
|
|
|
|
std::vector<std::string> aliases({"alias1", "alias2", "alias3"});
|
|
addrlist.AppendDnsAliases(std::move(aliases));
|
|
|
|
// Appending the aliases after setting the default canonical name
|
|
// does not replace the default canonical name.
|
|
EXPECT_THAT(addrlist.dns_aliases(),
|
|
UnorderedElementsAre("1.2.3.4", "alias1", "alias2", "alias3"));
|
|
}
|
|
|
|
TEST(AddressListTest, DnsAliases) {
|
|
const IPAddress kAddress(1, 2, 3, 4);
|
|
const IPEndPoint kEndpoint(kAddress, 0);
|
|
std::vector<std::string> aliases({"alias1", "alias2", "alias3"});
|
|
AddressList addrlist(kEndpoint, std::move(aliases));
|
|
|
|
EXPECT_THAT(addrlist.dns_aliases(),
|
|
UnorderedElementsAre("alias1", "alias2", "alias3"));
|
|
|
|
std::vector<std::string> more_aliases({"alias4", "alias5", "alias6"});
|
|
addrlist.AppendDnsAliases(std::move(more_aliases));
|
|
|
|
EXPECT_THAT(addrlist.dns_aliases(),
|
|
UnorderedElementsAre("alias1", "alias2", "alias3", "alias4",
|
|
"alias5", "alias6"));
|
|
|
|
std::vector<std::string> new_aliases({"alias7", "alias8", "alias9"});
|
|
addrlist.SetDnsAliases(std::move(new_aliases));
|
|
|
|
EXPECT_THAT(addrlist.dns_aliases(),
|
|
UnorderedElementsAre("alias7", "alias8", "alias9"));
|
|
}
|
|
|
|
TEST(AddressListTest, DeduplicatesEmptyAddressList) {
|
|
AddressList empty;
|
|
empty.Deduplicate();
|
|
EXPECT_EQ(empty.size(), 0u);
|
|
}
|
|
|
|
TEST(AddressListTest, DeduplicatesSingletonAddressList) {
|
|
AddressList singleton;
|
|
singleton.push_back(IPEndPoint());
|
|
singleton.Deduplicate();
|
|
EXPECT_THAT(singleton.endpoints(), ElementsAre(IPEndPoint()));
|
|
}
|
|
|
|
TEST(AddressListTest, DeduplicatesLongerAddressList) {
|
|
AddressList several;
|
|
several.endpoints() = {IPEndPoint(IPAddress(0, 0, 0, 1), 0),
|
|
IPEndPoint(IPAddress(0, 0, 0, 2), 0),
|
|
IPEndPoint(IPAddress(0, 0, 0, 2), 0),
|
|
IPEndPoint(IPAddress(0, 0, 0, 3), 0),
|
|
IPEndPoint(IPAddress(0, 0, 0, 2), 0),
|
|
IPEndPoint(IPAddress(0, 0, 0, 1), 0),
|
|
IPEndPoint(IPAddress(0, 0, 0, 2), 0),
|
|
IPEndPoint(IPAddress(0, 0, 0, 3), 0),
|
|
IPEndPoint(IPAddress(0, 0, 0, 2), 0)};
|
|
several.Deduplicate();
|
|
|
|
// Deduplication should preserve the order of the first instances
|
|
// of the unique addresses.
|
|
EXPECT_THAT(several.endpoints(),
|
|
ElementsAre(IPEndPoint(IPAddress(0, 0, 0, 1), 0),
|
|
IPEndPoint(IPAddress(0, 0, 0, 2), 0),
|
|
IPEndPoint(IPAddress(0, 0, 0, 3), 0)));
|
|
}
|
|
|
|
// Test that, for every permutation of a list of endpoints, deduplication
|
|
// produces the same results as a naive reference implementation.
|
|
TEST(AddressListTest, DeduplicatePreservesOrder) {
|
|
std::vector<IPEndPoint> permutation = {IPEndPoint(IPAddress(0, 0, 0, 1), 0),
|
|
IPEndPoint(IPAddress(0, 0, 0, 1), 0),
|
|
IPEndPoint(IPAddress(0, 0, 0, 2), 0),
|
|
IPEndPoint(IPAddress(0, 0, 0, 2), 0),
|
|
IPEndPoint(IPAddress(0, 0, 0, 3), 0)};
|
|
ASSERT_TRUE(std::is_sorted(permutation.begin(), permutation.end()));
|
|
|
|
do {
|
|
std::vector<IPEndPoint> expected;
|
|
std::set<IPEndPoint> set;
|
|
for (const IPEndPoint& endpoint : permutation) {
|
|
if (set.insert(endpoint).second)
|
|
expected.push_back(endpoint);
|
|
}
|
|
EXPECT_EQ(expected.size(), 3u);
|
|
|
|
AddressList address_list;
|
|
address_list.endpoints() = permutation;
|
|
address_list.Deduplicate();
|
|
EXPECT_EQ(address_list.endpoints(), expected);
|
|
} while (std::next_permutation(permutation.begin(), permutation.end()));
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace net
|