diff options
author | mbelshe@chromium.org <mbelshe@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-04 03:21:31 +0000 |
---|---|---|
committer | mbelshe@chromium.org <mbelshe@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-04 03:21:31 +0000 |
commit | 76ff86af64d9260bc6042b3ab80adf78cc1a1582 (patch) | |
tree | a8c81194db224fcef75c6696a9c06def27171ad8 | |
parent | 211486bd44160962954c2b10874323f4ac6c838e (diff) | |
download | chromium_src-76ff86af64d9260bc6042b3ab80adf78cc1a1582.zip chromium_src-76ff86af64d9260bc6042b3ab80adf78cc1a1582.tar.gz chromium_src-76ff86af64d9260bc6042b3ab80adf78cc1a1582.tar.bz2 |
Add an IPEndPoint class as a simple class for dealing with struct sockaddr.
BUG=none
TEST=ip_endpoint_unittest
Review URL: http://codereview.chromium.org/6592096
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@76868 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | net/base/ip_endpoint.cc | 102 | ||||
-rw-r--r-- | net/base/ip_endpoint.h | 53 | ||||
-rw-r--r-- | net/base/ip_endpoint_unittest.cc | 141 | ||||
-rw-r--r-- | net/net.gyp | 3 |
4 files changed, 299 insertions, 0 deletions
diff --git a/net/base/ip_endpoint.cc b/net/base/ip_endpoint.cc new file mode 100644 index 0000000..116af2b --- /dev/null +++ b/net/base/ip_endpoint.cc @@ -0,0 +1,102 @@ +// Copyright (c) 2011 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/ip_endpoint.h" + +#include "base/logging.h" +#if defined(OS_WIN) +#include <winsock2.h> +#elif defined(OS_POSIX) +#include <netinet/in.h> +#endif + +namespace net { + +const size_t kIPv4AddressSize = 4; +const size_t kIPv6AddressSize = 16; + +IPEndPoint::IPEndPoint() : port_(0) {} + +IPEndPoint::IPEndPoint(const IPAddressNumber& address, int port) + : address_(address), + port_(port) {} + +IPEndPoint::IPEndPoint(const IPEndPoint& endpoint) { + address_ = endpoint.address_; + port_ = endpoint.port_; +} + +bool IPEndPoint::ToSockaddr(struct sockaddr* address, + size_t* address_length) const { + DCHECK(address); + DCHECK(address_length); + switch (address_.size()) { + case kIPv4AddressSize: { + if (*address_length < sizeof(struct sockaddr_in)) + return false; + *address_length = sizeof(struct sockaddr_in); + struct sockaddr_in* addr = reinterpret_cast<struct sockaddr_in*>(address); + memset(addr, 0, sizeof(struct sockaddr_in)); + addr->sin_family = AF_INET; + addr->sin_port = htons(port_); + memcpy(&addr->sin_addr, &address_[0], kIPv4AddressSize); + break; + } + case kIPv6AddressSize: { + if (*address_length < sizeof(struct sockaddr_in6)) + return false; + *address_length = sizeof(struct sockaddr_in6); + struct sockaddr_in6* addr6 = + reinterpret_cast<struct sockaddr_in6*>(address); + memset(addr6, 0, sizeof(struct sockaddr_in6)); + addr6->sin6_family = AF_INET6; + addr6->sin6_port = htons(port_); + memcpy(&addr6->sin6_addr, &address_[0], kIPv6AddressSize); + break; + } + default: { + NOTREACHED() << "Bad IP address"; + break; + } + } + return true; +} + +bool IPEndPoint::FromSockAddr(const struct sockaddr* address, + size_t address_length) { + DCHECK(address); + switch (address->sa_family) { + case AF_INET: { + const struct sockaddr_in* addr = + reinterpret_cast<const struct sockaddr_in*>(address); + port_ = ntohs(addr->sin_port); + const char* bytes = reinterpret_cast<const char*>(&addr->sin_addr); + address_.assign(&bytes[0], &bytes[kIPv4AddressSize]); + break; + } + case AF_INET6: { + const struct sockaddr_in6* addr = + reinterpret_cast<const struct sockaddr_in6*>(address); + port_ = ntohs(addr->sin6_port); + const char* bytes = reinterpret_cast<const char*>(&addr->sin6_addr); + address_.assign(&bytes[0], &bytes[kIPv6AddressSize]); + break; + } + default: { + NOTREACHED() << "Bad IP address"; + break; + } + } + return true; +} + +bool IPEndPoint::operator<(const IPEndPoint& that) const { + return address_ < that.address_ || port_ < that.port_; +} + +bool IPEndPoint::operator==(const IPEndPoint& that) const { + return address_ == that.address_ && port_ == that.port_; +} + +} // namespace net diff --git a/net/base/ip_endpoint.h b/net/base/ip_endpoint.h new file mode 100644 index 0000000..66aea71 --- /dev/null +++ b/net/base/ip_endpoint.h @@ -0,0 +1,53 @@ +// Copyright (c) 2011 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. + +#ifndef NET_BASE_IP_ENDPOINT_H_ +#define NET_BASE_IP_ENDPOINT_H_ +#pragma once + +#include "base/basictypes.h" +#include "net/base/net_util.h" + +struct sockaddr; + +namespace net { + +// An IPEndPoint represents the address of a transport endpoint: +// * IP address (either v4 or v6) +// * Port +class IPEndPoint { + public: + IPEndPoint(); + IPEndPoint(const IPAddressNumber& address, int port); + IPEndPoint(const IPEndPoint& endpoint); + + const IPAddressNumber& address() const { return address_; } + int port() const { return port_; } + + // Convert to a provided sockaddr struct. + // |address| is the sockaddr to copy into. Should be at least + // sizeof(struct sockaddr_storage) bytes. + // |address_length| is an input/output parameter. On input, it is the + // size of data in |address| available. On output, it is the size of + // the address that was copied into |address|. + // Returns true on success, false on failure. + bool ToSockaddr(struct sockaddr* address, size_t* address_length) const; + + // Convert from a sockaddr struct. + // |address| is the address. + // |address_length| is the length of |address|. + // Returns true on success, false on failure. + bool FromSockAddr(const struct sockaddr* address, size_t address_length); + + bool operator<(const IPEndPoint& that) const; + bool operator==(const IPEndPoint& that) const; + + private: + IPAddressNumber address_; + int port_; +}; + +} // namespace net + +#endif // NET_BASE_IP_ENDPOINT_H_ diff --git a/net/base/ip_endpoint_unittest.cc b/net/base/ip_endpoint_unittest.cc new file mode 100644 index 0000000..b9fe48b --- /dev/null +++ b/net/base/ip_endpoint_unittest.cc @@ -0,0 +1,141 @@ +// Copyright (c) 2011 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/ip_endpoint.h" + +#include "net/base/net_util.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/platform_test.h" +#if defined(OS_WIN) +#include <winsock2.h> +#elif defined(OS_POSIX) +#include <netinet/in.h> +#endif + +namespace net { + +namespace { + +struct TestData { + std::string host; + bool ipv6; + IPAddressNumber ip_address; +} tests[] = { + { "127.0.00.1", false}, + { "192.168.1.1", false }, + { "::1", true }, + { "2001:db8:0::42", true }, +}; +int test_count = ARRAYSIZE_UNSAFE(tests); + +class IPEndPointTest : public PlatformTest { + public: + virtual void SetUp() { + // This is where we populate the TestData. + for (int index = 0; index < test_count; ++index) { + EXPECT_TRUE(ParseIPLiteralToNumber(tests[index].host, + &tests[index].ip_address)); + } + } +}; + +TEST_F(IPEndPointTest, Constructor) { + IPEndPoint endpoint; + EXPECT_EQ(0, endpoint.port()); + + for (int index = 0; index < test_count; ++index) { + IPEndPoint endpoint(tests[index].ip_address, 80); + EXPECT_EQ(80, endpoint.port()); + EXPECT_EQ(tests[index].ip_address, endpoint.address()); + } +} + +TEST_F(IPEndPointTest, Assignment) { + for (int index = 0; index < test_count; ++index) { + IPEndPoint src(tests[index].ip_address, index); + IPEndPoint dest = src; + + EXPECT_EQ(src.port(), dest.port()); + EXPECT_EQ(src.address(), dest.address()); + } +} + +TEST_F(IPEndPointTest, Copy) { + for (int index = 0; index < test_count; ++index) { + IPEndPoint src(tests[index].ip_address, index); + IPEndPoint dest(src); + + EXPECT_EQ(src.port(), dest.port()); + EXPECT_EQ(src.address(), dest.address()); + } +} + +TEST_F(IPEndPointTest, ToFromSockaddr) { + for (int index = 0; index < test_count; ++index) { + IPEndPoint ip_endpoint(tests[index].ip_address, index); + + // Convert to a sockaddr. + struct sockaddr_storage addr; + size_t addr_len = sizeof(addr); + struct sockaddr* sockaddr = reinterpret_cast<struct sockaddr*>(&addr); + EXPECT_TRUE(ip_endpoint.ToSockaddr(sockaddr, &addr_len)); + + // Basic verification. + size_t expected_size = tests[index].ipv6 ? + sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); + EXPECT_EQ(expected_size, addr_len); + EXPECT_EQ(ip_endpoint.port(), GetPortFromSockaddr(sockaddr, addr_len)); + + // And convert back to an IPEndPoint. + IPEndPoint ip_endpoint2; + EXPECT_TRUE(ip_endpoint2.FromSockAddr(sockaddr, addr_len)); + EXPECT_EQ(ip_endpoint.port(), ip_endpoint2.port()); + EXPECT_EQ(ip_endpoint.address(), ip_endpoint2.address()); + } +} + +TEST_F(IPEndPointTest, ToSockaddrBufTooSmall) { + for (int index = 0; index < test_count; ++index) { + IPEndPoint ip_endpoint(tests[index].ip_address, index); + + struct sockaddr_storage addr; + size_t addr_len = index; // size is too small! + struct sockaddr* sockaddr = reinterpret_cast<struct sockaddr*>(&addr); + EXPECT_FALSE(ip_endpoint.ToSockaddr(sockaddr, &addr_len)); + } +} + +TEST_F(IPEndPointTest, Equality) { + for (int index = 0; index < test_count; ++index) { + IPEndPoint src(tests[index].ip_address, index); + IPEndPoint dest(src); + EXPECT_TRUE(src == dest); + } +} + +TEST_F(IPEndPointTest, LessThan) { + // Vary by port. + IPEndPoint ip_endpoint1(tests[0].ip_address, 100); + IPEndPoint ip_endpoint2(tests[0].ip_address, 1000); + EXPECT_TRUE(ip_endpoint1 < ip_endpoint2); + + // IPv4 vs IPv6 + ip_endpoint1 = IPEndPoint(tests[0].ip_address, 80); + ip_endpoint2 = IPEndPoint(tests[2].ip_address, 80); + EXPECT_FALSE(ip_endpoint1 < ip_endpoint2); + + // IPv4 vs IPv4 + ip_endpoint1 = IPEndPoint(tests[0].ip_address, 80); + ip_endpoint2 = IPEndPoint(tests[1].ip_address, 80); + EXPECT_TRUE(ip_endpoint1 < ip_endpoint2); + + // IPv6 vs IPv6 + ip_endpoint1 = IPEndPoint(tests[2].ip_address, 80); + ip_endpoint2 = IPEndPoint(tests[3].ip_address, 80); + EXPECT_TRUE(ip_endpoint1 < ip_endpoint2); +} + +} // namespace + +} // namespace net diff --git a/net/net.gyp b/net/net.gyp index f5f2dbb..1aff097 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -97,6 +97,8 @@ 'base/host_resolver_proc.h', 'base/io_buffer.cc', 'base/io_buffer.h', + 'base/ip_endpoint.cc', + 'base/ip_endpoint.h', 'base/keygen_handler.cc', 'base/keygen_handler.h', 'base/keygen_handler_mac.cc', @@ -865,6 +867,7 @@ 'base/host_cache_unittest.cc', 'base/host_mapping_rules_unittest.cc', 'base/host_resolver_impl_unittest.cc', + 'base/ip_endpoint_unittest.cc', 'base/keygen_handler_unittest.cc', 'base/listen_socket_unittest.cc', 'base/listen_socket_unittest.h', |