// Copyright (c) 2012 The Chromium Authors. All rights reserved. // 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 "base/strings/string_util.h" #include "base/sys_byteorder.h" #include "net/base/net_util.h" #include "net/base/sys_addrinfo.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { namespace { static 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(&address); ai.ai_canonname = const_cast(kCanonicalHostname); // Copy the addrinfo struct into an AddressList object and // make sure it seems correct. AddressList addrlist1 = AddressList::CreateFromAddrinfo(&ai); EXPECT_EQ("canonical.bar.com", addrlist1.canonical_name()); // Copy the AddressList to another one. AddressList addrlist2 = addrlist1; EXPECT_EQ("canonical.bar.com", addrlist2.canonical_name()); } 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(storage[i].addr); storage[i].addr_len = sizeof(struct sockaddr_in); // Populating the address with { i, i, i, i }. memset(&addr->sin_addr, i, kIPv4AddressSize); addr->sin_family = AF_INET; // Set port to i << 2; addr->sin_port = base::HostToNet16(static_cast(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()[0]); EXPECT_EQ(static_cast(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()[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 (size_t i = 0; i < arraysize(tests); ++i) { IPAddressNumber ip_number; ASSERT_TRUE(ParseIPLiteralToNumber(tests[i].ip_address, &ip_number)); ip_list.push_back(ip_number); } AddressList test_list = AddressList::CreateFromIPAddressList(ip_list, kCanonicalName); std::string canonical_name; EXPECT_EQ(kCanonicalName, test_list.canonical_name()); EXPECT_EQ(arraysize(tests), test_list.size()); } } // namespace } // namespace net