| Index: native_client_sdk/src/tests/nacl_io_test/host_resolver_test.cc
|
| diff --git a/native_client_sdk/src/tests/nacl_io_test/host_resolver_test.cc b/native_client_sdk/src/tests/nacl_io_test/host_resolver_test.cc
|
| index 9d79e1c5a55502f7f07786048b7231c5bfea9b1f..c3dceb0d5cdf45e54d008f42b089f1af7e93c4f9 100644
|
| --- a/native_client_sdk/src/tests/nacl_io_test/host_resolver_test.cc
|
| +++ b/native_client_sdk/src/tests/nacl_io_test/host_resolver_test.cc
|
| @@ -18,13 +18,56 @@ namespace {
|
|
|
| class HostResolverTest : public ::testing::Test {
|
| public:
|
| - HostResolverTest() : pepper_(NULL) {}
|
| + HostResolverTest() {}
|
| +
|
| + void SetUp() {
|
| + ki_init(NULL);
|
| + }
|
| +
|
| + void TearDown() {
|
| + ki_uninit();
|
| + }
|
| +};
|
| +
|
| +#define FAKE_HOSTNAME "example.com"
|
| +#define FAKE_IP 0x01020304
|
| +
|
| +class FakeHostResolverTest : public ::testing::Test {
|
| + public:
|
| + FakeHostResolverTest() : pepper_(NULL), fake_resolver_(NULL) {}
|
|
|
| void SetUp() {
|
| pepper_ = new FakePepperInterface();
|
| + fake_resolver_ = static_cast<FakeHostResolverInterface*>(
|
| + pepper_->GetHostResolverInterface());
|
| +
|
| + // Seed the fake resolver with some data
|
| + fake_resolver_->fake_hostname = FAKE_HOSTNAME;
|
| + AddFakeAddress(AF_INET);
|
| +
|
| ki_init_interface(NULL, pepper_);
|
| }
|
|
|
| + void AddFakeAddress(int family) {
|
| + if (family == AF_INET) {
|
| + int address_count = fake_resolver_->fake_addresses_v4.size();
|
| + // Each new address we add is FAKE_IP incremented by 1
|
| + // each time to be unique.
|
| + sockaddr_in fake_addr;
|
| + fake_addr.sin_family = family;
|
| + fake_addr.sin_addr.s_addr = htonl(FAKE_IP + address_count);
|
| + fake_resolver_->fake_addresses_v4.push_back(fake_addr);
|
| + } else if (family == AF_INET6) {
|
| + sockaddr_in6 fake_addr;
|
| + fake_addr.sin6_family = family;
|
| + int address_count = fake_resolver_->fake_addresses_v6.size();
|
| + for (uint8_t i = 0; i < 16; i++) {
|
| + fake_addr.sin6_addr.s6_addr[i] = i + address_count;
|
| + }
|
| + fake_resolver_->fake_addresses_v6.push_back(fake_addr);
|
| + }
|
| + }
|
| +
|
| void TearDown() {
|
| ki_uninit();
|
| pepper_ = NULL;
|
| @@ -32,13 +75,241 @@ class HostResolverTest : public ::testing::Test {
|
|
|
| protected:
|
| FakePepperInterface* pepper_;
|
| + FakeHostResolverInterface* fake_resolver_;
|
| };
|
|
|
| } // namespace
|
|
|
| +#define NULL_INFO ((struct addrinfo*)NULL)
|
| +#define NULL_ADDR ((struct sockaddr*)NULL)
|
| #define NULL_HOST (static_cast<hostent*>(NULL))
|
|
|
| -TEST_F(HostResolverTest, GethostbynameNumeric) {
|
| +TEST_F(HostResolverTest, Getaddrinfo_Numeric) {
|
| + struct addrinfo* ai = NULL;
|
| + struct sockaddr_in* in;
|
| + struct addrinfo hints;
|
| +
|
| + // Numberic only
|
| + memset(&hints, 0, sizeof(hints));
|
| + hints.ai_family = AF_INET;
|
| + hints.ai_socktype = SOCK_STREAM;
|
| +
|
| + uint32_t expected_addr = htonl(0x01020304);
|
| + ASSERT_EQ(0, ki_getaddrinfo("1.2.3.4", NULL, &hints, &ai));
|
| + ASSERT_NE(NULL_INFO, ai);
|
| + ASSERT_NE(NULL_ADDR, ai->ai_addr);
|
| + ASSERT_EQ(AF_INET, ai->ai_family);
|
| + ASSERT_EQ(SOCK_STREAM, ai->ai_socktype);
|
| + in = (struct sockaddr_in*)ai->ai_addr;
|
| + ASSERT_EQ(expected_addr, in->sin_addr.s_addr);
|
| + ASSERT_EQ(NULL_INFO, ai->ai_next);
|
| +
|
| + ki_freeaddrinfo(ai);
|
| +}
|
| +
|
| +TEST_F(HostResolverTest, Getaddrinfo_MissingPPAPI) {
|
| + // Verify that full lookups fail due to lack of PPAPI interfaces
|
| + struct addrinfo* ai = NULL;
|
| + ASSERT_EQ(EAI_SYSTEM, ki_getaddrinfo("google.com", NULL, NULL, &ai));
|
| +}
|
| +
|
| +TEST_F(HostResolverTest, Getaddrinfo_Passive) {
|
| + struct addrinfo* ai = NULL;
|
| + struct sockaddr_in* in;
|
| + struct sockaddr_in6* in6;
|
| + struct addrinfo hints;
|
| + memset(&hints, 0, sizeof(hints));
|
| +
|
| + uint32_t expected_port = htons(22);
|
| + in_addr_t expected_addr = htonl(INADDR_ANY);
|
| + in6_addr expected_addr6 = IN6ADDR_ANY_INIT;
|
| +
|
| + // AI_PASSIVE means that the returned address will be a wildcard
|
| + // address suitable for binding and listening. This should not
|
| + // hit PPAPI at all, so we don't need fakes.
|
| + hints.ai_family = AF_INET;
|
| + hints.ai_flags = AI_PASSIVE;
|
| + hints.ai_socktype = SOCK_DGRAM;
|
| + ASSERT_EQ(0, ki_getaddrinfo(NULL, "22", &hints, &ai));
|
| + ASSERT_NE(NULL_INFO, ai);
|
| + ASSERT_NE(NULL_ADDR, ai->ai_addr);
|
| + ASSERT_EQ(NULL_INFO, ai->ai_next);
|
| + in = (struct sockaddr_in*)ai->ai_addr;
|
| + ASSERT_EQ(expected_addr, in->sin_addr.s_addr);
|
| + ASSERT_EQ(expected_port, in->sin_port);
|
| + ASSERT_EQ(AF_INET, in->sin_family);
|
| + ki_freeaddrinfo(ai);
|
| +
|
| + // Same test with AF_INET6
|
| + hints.ai_family = AF_INET6;
|
| + ASSERT_EQ(0, ki_getaddrinfo(NULL, "22", &hints, &ai));
|
| + ASSERT_NE(NULL_INFO, ai);
|
| + ASSERT_NE(NULL_ADDR, ai->ai_addr);
|
| + ASSERT_EQ(NULL_INFO, ai->ai_next);
|
| + in6 = (struct sockaddr_in6*)ai->ai_addr;
|
| + ASSERT_EQ(expected_port, in6->sin6_port);
|
| + ASSERT_EQ(AF_INET6, in6->sin6_family);
|
| + ASSERT_EQ(0, memcmp(in6->sin6_addr.s6_addr,
|
| + &expected_addr6,
|
| + sizeof(expected_addr6)));
|
| + ki_freeaddrinfo(ai);
|
| +}
|
| +
|
| +TEST_F(HostResolverTest, Getaddrinfo_Passive_Any) {
|
| + // Similar to Getaddrinfo_Passive but don't set
|
| + // ai_family in the hints, so we should get muplitple
|
| + // results back for the different families.
|
| + struct addrinfo* ai = NULL;
|
| + struct sockaddr_in* in;
|
| + struct sockaddr_in6* in6;
|
| + struct addrinfo hints;
|
| + memset(&hints, 0, sizeof(hints));
|
| +
|
| + uint32_t expected_port = htons(22);
|
| + in_addr_t expected_addr = htonl(INADDR_ANY);
|
| + in6_addr expected_addr6 = IN6ADDR_ANY_INIT;
|
| +
|
| + hints.ai_flags = AI_PASSIVE;
|
| + hints.ai_socktype = SOCK_DGRAM;
|
| + ASSERT_EQ(0, ki_getaddrinfo(NULL, "22", &hints, &ai));
|
| + ASSERT_NE(NULL_INFO, ai);
|
| + int count = 0;
|
| + bool got_v4 = false;
|
| + bool got_v6 = false;
|
| + while (ai) {
|
| + ASSERT_NE(NULL_ADDR, ai->ai_addr);
|
| + switch (ai->ai_addr->sa_family) {
|
| + case AF_INET:
|
| + in = (struct sockaddr_in*)ai->ai_addr;
|
| + ASSERT_EQ(expected_port, in->sin_port);
|
| + ASSERT_EQ(AF_INET, in->sin_family);
|
| + ASSERT_EQ(expected_addr, in->sin_addr.s_addr);
|
| + got_v4 = true;
|
| + break;
|
| + case AF_INET6:
|
| + in6 = (struct sockaddr_in6*)ai->ai_addr;
|
| + ASSERT_EQ(expected_port, in6->sin6_port);
|
| + ASSERT_EQ(AF_INET6, in6->sin6_family);
|
| + ASSERT_EQ(0, memcmp(in6->sin6_addr.s6_addr,
|
| + &expected_addr6,
|
| + sizeof(expected_addr6)));
|
| + got_v6 = true;
|
| + break;
|
| + default:
|
| + ASSERT_TRUE(false) << "Unknown address type: " << ai->ai_addr;
|
| + break;
|
| + }
|
| + ai = ai->ai_next;
|
| + count++;
|
| + }
|
| +
|
| + ASSERT_EQ(2, count);
|
| + ASSERT_TRUE(got_v4);
|
| + ASSERT_TRUE(got_v6);
|
| +}
|
| +
|
| +TEST_F(FakeHostResolverTest, Getaddrinfo_Lookup) {
|
| + struct addrinfo* ai = NULL;
|
| + struct sockaddr_in* in;
|
| + struct addrinfo hints;
|
| + memset(&hints, 0, sizeof(hints));
|
| +
|
| + in_addr_t expected_addr = htonl(FAKE_IP);
|
| +
|
| + // Lookup the fake hostname using getaddrinfo
|
| + hints.ai_family = AF_INET;
|
| + hints.ai_socktype = SOCK_STREAM;
|
| + ASSERT_EQ(0, ki_getaddrinfo(FAKE_HOSTNAME, NULL, &hints, &ai));
|
| + ASSERT_NE(NULL_INFO, ai);
|
| + ASSERT_NE(NULL_ADDR, ai->ai_addr);
|
| + ASSERT_EQ(AF_INET, ai->ai_family);
|
| + ASSERT_EQ(SOCK_STREAM, ai->ai_socktype);
|
| + in = (struct sockaddr_in*)ai->ai_addr;
|
| + ASSERT_EQ(expected_addr, in->sin_addr.s_addr);
|
| + ASSERT_EQ(NULL_INFO, ai->ai_next);
|
| +
|
| + ki_freeaddrinfo(ai);
|
| +}
|
| +
|
| +TEST_F(FakeHostResolverTest, Getaddrinfo_Multi) {
|
| + struct addrinfo* ai = NULL;
|
| + struct addrinfo hints;
|
| + memset(&hints, 0, sizeof(hints));
|
| +
|
| + // Add four fake address on top of the initial one
|
| + // that the fixture creates.
|
| + AddFakeAddress(AF_INET);
|
| + AddFakeAddress(AF_INET);
|
| + AddFakeAddress(AF_INET6);
|
| + AddFakeAddress(AF_INET6);
|
| +
|
| + hints.ai_socktype = SOCK_STREAM;
|
| +
|
| + // First we test with AF_INET
|
| + hints.ai_family = AF_INET;
|
| + ASSERT_EQ(0, ki_getaddrinfo(FAKE_HOSTNAME, NULL, &hints, &ai));
|
| + ASSERT_NE(NULL_INFO, ai);
|
| +
|
| + // We expect to be returned 3 AF_INET address with
|
| + // address FAKE_IP, FAKE_IP+1 and FAKE_IP+2, since that
|
| + // is that the fake was seeded with.
|
| + uint32_t expected_addr = htonl(FAKE_IP);
|
| + int count = 0;
|
| + struct addrinfo* current = ai;
|
| + while (current != NULL) {
|
| + ASSERT_NE(NULL_ADDR, current->ai_addr);
|
| + ASSERT_EQ(AF_INET, current->ai_family);
|
| + ASSERT_EQ(SOCK_STREAM, current->ai_socktype);
|
| + sockaddr_in* in = (sockaddr_in*)current->ai_addr;
|
| + ASSERT_EQ(expected_addr, in->sin_addr.s_addr);
|
| + expected_addr += htonl(1);
|
| + current = current->ai_next;
|
| + count++;
|
| + }
|
| + ASSERT_EQ(3, count);
|
| + ki_freeaddrinfo(ai);
|
| +
|
| + // Same test but with AF_INET6
|
| + hints.ai_family = AF_INET6;
|
| + ASSERT_EQ(0, ki_getaddrinfo(FAKE_HOSTNAME, NULL, &hints, &ai));
|
| + ASSERT_NE(NULL_INFO, ai);
|
| +
|
| + count = 0;
|
| + current = ai;
|
| + while (current != NULL) {
|
| + ASSERT_NE(NULL_ADDR, current->ai_addr);
|
| + ASSERT_EQ(AF_INET6, current->ai_family);
|
| + ASSERT_EQ(SOCK_STREAM, current->ai_socktype);
|
| + sockaddr_in6* in = (sockaddr_in6*)current->ai_addr;
|
| + for (int i = 0; i < 16; i++) {
|
| + ASSERT_EQ(i + count, in->sin6_addr.s6_addr[i]);
|
| + }
|
| + current = current->ai_next;
|
| + count++;
|
| + }
|
| + ASSERT_EQ(2, count);
|
| + ki_freeaddrinfo(ai);
|
| +
|
| + // Same test but with AF_UNSPEC. Here we expect to get
|
| + // 5 address back: 3 * v4 and 2 * v6.
|
| + hints.ai_family = AF_UNSPEC;
|
| + ASSERT_EQ(0, ki_getaddrinfo(FAKE_HOSTNAME, NULL, &hints, &ai));
|
| + ASSERT_NE(NULL_INFO, ai);
|
| +
|
| + count = 0;
|
| + current = ai;
|
| + while (current != NULL) {
|
| + ASSERT_NE(NULL_ADDR, ai->ai_addr);
|
| + ASSERT_EQ(SOCK_STREAM, ai->ai_socktype);
|
| + current = current->ai_next;
|
| + count++;
|
| + }
|
| + ASSERT_EQ(5, count);
|
| +
|
| + ki_freeaddrinfo(ai);
|
| +}
|
| +
|
| +TEST_F(FakeHostResolverTest, Gethostbyname) {
|
| hostent* host = ki_gethostbyname(FAKE_HOSTNAME);
|
|
|
| // Verify the returned hostent structure
|
| @@ -53,3 +324,40 @@ TEST_F(HostResolverTest, GethostbynameNumeric) {
|
| in_addr_t exptected_addr = htonl(FAKE_IP);
|
| ASSERT_EQ(exptected_addr, *addr_list[0]);
|
| }
|
| +
|
| +TEST_F(FakeHostResolverTest, Gethostbyname_Failure) {
|
| + hostent* host = ki_gethostbyname("nosuchhost.com");
|
| + ASSERT_EQ(NULL_HOST, host);
|
| + ASSERT_EQ(HOST_NOT_FOUND, h_errno);
|
| +}
|
| +
|
| +// Looking up purely numeric hostnames should work without PPAPI
|
| +// so we don't need the fakes for this test
|
| +TEST_F(HostResolverTest, Gethostbyname_Numeric) {
|
| + struct hostent* host = ki_gethostbyname("8.8.8.8");
|
| +
|
| + // Verify the returned hostent structure
|
| + ASSERT_NE(NULL_HOST, host);
|
| + ASSERT_EQ(AF_INET, host->h_addrtype);
|
| + ASSERT_EQ(sizeof(in_addr_t), host->h_length);
|
| + ASSERT_STREQ("8.8.8.8", host->h_name);
|
| +
|
| + in_addr_t** addr_list = reinterpret_cast<in_addr_t**>(host->h_addr_list);
|
| + ASSERT_NE(reinterpret_cast<in_addr_t**>(NULL), addr_list);
|
| + ASSERT_EQ(NULL, addr_list[1]);
|
| + ASSERT_EQ(inet_addr("8.8.8.8"), *addr_list[0]);
|
| +}
|
| +
|
| +// These utility functions are only used for newlib (glibc provides its own
|
| +// implementations of these functions).
|
| +#if !defined(__GLIBC__)
|
| +
|
| +TEST(SocketUtilityFunctions, Hstrerror) {
|
| + EXPECT_STREQ("Unknown error in gethostbyname: 2718.", hstrerror(2718));
|
| +}
|
| +
|
| +TEST(SocketUtilityFunctions, Gai_Strerror) {
|
| + EXPECT_STREQ("Unknown error in getaddrinfo: 2719.", gai_strerror(2719));
|
| +}
|
| +
|
| +#endif // !defined(__GLIBC__)
|
|
|