gfe-relnote: Replace QuicIpAddress with a standalone implementation. No functional change, not flag protected.
This historically used platform representation out of convenience; making it platform-agnostic would make porting QUIC easier to new applications.
The file itself needs to be moved to quic/core, and the impl can be deleted; that wil; be done in a separate CL.
PiperOrigin-RevId: 251779401
Change-Id: Idc75704b8785d9b7b6b7870bf006c7f8dda83473
diff --git a/quic/platform/api/quic_ip_address.cc b/quic/platform/api/quic_ip_address.cc
index 3b48c47..ebc71e1 100644
--- a/quic/platform/api/quic_ip_address.cc
+++ b/quic/platform/api/quic_ip_address.cc
@@ -4,35 +4,83 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
+#include <algorithm>
+#include <cstring>
#include <string>
+#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
+
namespace quic {
+static int ToPlatformAddressFamily(IpAddressFamily family) {
+ switch (family) {
+ case IpAddressFamily::IP_V4:
+ return AF_INET;
+ case IpAddressFamily::IP_V6:
+ return AF_INET6;
+ case IpAddressFamily::IP_UNSPEC:
+ return AF_UNSPEC;
+ }
+}
+
QuicIpAddress QuicIpAddress::Loopback4() {
- return QuicIpAddress(QuicIpAddressImpl::Loopback4());
+ QuicIpAddress result;
+ result.family_ = IpAddressFamily::IP_V4;
+ result.address_.bytes[0] = 127;
+ result.address_.bytes[1] = 0;
+ result.address_.bytes[2] = 0;
+ result.address_.bytes[3] = 1;
+ return result;
}
QuicIpAddress QuicIpAddress::Loopback6() {
- return QuicIpAddress(QuicIpAddressImpl::Loopback6());
+ QuicIpAddress result;
+ result.family_ = IpAddressFamily::IP_V6;
+ uint8_t* bytes = result.address_.bytes;
+ memset(bytes, 0, 15);
+ bytes[15] = 1;
+ return result;
}
QuicIpAddress QuicIpAddress::Any4() {
- return QuicIpAddress(QuicIpAddressImpl::Any4());
+ in_addr address;
+ memset(&address, 0, sizeof(address));
+ return QuicIpAddress(address);
}
QuicIpAddress QuicIpAddress::Any6() {
- return QuicIpAddress(QuicIpAddressImpl::Any6());
+ in6_addr address;
+ memset(&address, 0, sizeof(address));
+ return QuicIpAddress(address);
}
-QuicIpAddress::QuicIpAddress(const QuicIpAddressImpl& impl) : impl_(impl) {}
+QuicIpAddress::QuicIpAddress() : family_(IpAddressFamily::IP_UNSPEC) {}
QuicIpAddress::QuicIpAddress(const in_addr& ipv4_address)
- : impl_(ipv4_address) {}
+ : family_(IpAddressFamily::IP_V4) {
+ address_.v4 = ipv4_address;
+}
QuicIpAddress::QuicIpAddress(const in6_addr& ipv6_address)
- : impl_(ipv6_address) {}
+ : family_(IpAddressFamily::IP_V6) {
+ address_.v6 = ipv6_address;
+}
bool operator==(QuicIpAddress lhs, QuicIpAddress rhs) {
- return lhs.impl_ == rhs.impl_;
+ if (lhs.family_ != rhs.family_) {
+ return false;
+ }
+ switch (lhs.family_) {
+ case IpAddressFamily::IP_V4:
+ return std::equal(lhs.address_.bytes,
+ lhs.address_.bytes + QuicIpAddress::kIPv4AddressSize,
+ rhs.address_.bytes);
+ case IpAddressFamily::IP_V6:
+ return std::equal(lhs.address_.bytes,
+ lhs.address_.bytes + QuicIpAddress::kIPv6AddressSize,
+ rhs.address_.bytes);
+ case IpAddressFamily::IP_UNSPEC:
+ return true;
+ }
}
bool operator!=(QuicIpAddress lhs, QuicIpAddress rhs) {
@@ -40,60 +88,141 @@
}
bool QuicIpAddress::IsInitialized() const {
- return impl_.IsInitialized();
+ return family_ != IpAddressFamily::IP_UNSPEC;
}
IpAddressFamily QuicIpAddress::address_family() const {
- return impl_.address_family();
+ return family_;
}
int QuicIpAddress::AddressFamilyToInt() const {
- return impl_.AddressFamilyToInt();
+ return ToPlatformAddressFamily(family_);
}
std::string QuicIpAddress::ToPackedString() const {
- return impl_.ToPackedString();
+ switch (family_) {
+ case IpAddressFamily::IP_V4:
+ return std::string(address_.chars, sizeof(address_.v4));
+ case IpAddressFamily::IP_V6:
+ return std::string(address_.chars, sizeof(address_.v6));
+ case IpAddressFamily::IP_UNSPEC:
+ return "";
+ }
}
std::string QuicIpAddress::ToString() const {
- return impl_.ToString();
+ if (!IsInitialized()) {
+ return "";
+ }
+
+ char buffer[INET6_ADDRSTRLEN] = {0};
+ const char* result =
+ inet_ntop(AddressFamilyToInt(), address_.bytes, buffer, sizeof(buffer));
+ QUIC_BUG_IF(result == nullptr) << "Failed to convert an IP address to string";
+ return buffer;
}
+static const uint8_t kMappedAddressPrefix[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+};
+
QuicIpAddress QuicIpAddress::Normalized() const {
- return QuicIpAddress(impl_.Normalized());
+ if (!IsIPv6()) {
+ return *this;
+ }
+ if (!std::equal(std::begin(kMappedAddressPrefix),
+ std::end(kMappedAddressPrefix), address_.bytes)) {
+ return *this;
+ }
+
+ in_addr result;
+ memcpy(&result, &address_.bytes[12], sizeof(result));
+ return QuicIpAddress(result);
}
QuicIpAddress QuicIpAddress::DualStacked() const {
- return QuicIpAddress(impl_.DualStacked());
+ if (!IsIPv4()) {
+ return *this;
+ }
+
+ QuicIpAddress result;
+ result.family_ = IpAddressFamily::IP_V6;
+ memcpy(result.address_.bytes, kMappedAddressPrefix,
+ sizeof(kMappedAddressPrefix));
+ memcpy(result.address_.bytes + 12, address_.bytes, kIPv4AddressSize);
+ return result;
}
bool QuicIpAddress::FromPackedString(const char* data, size_t length) {
- return impl_.FromPackedString(data, length);
+ switch (length) {
+ case kIPv4AddressSize:
+ family_ = IpAddressFamily::IP_V4;
+ break;
+ case kIPv6AddressSize:
+ family_ = IpAddressFamily::IP_V6;
+ break;
+ default:
+ return false;
+ }
+ memcpy(address_.chars, data, length);
+ return true;
}
bool QuicIpAddress::FromString(std::string str) {
- return impl_.FromString(str);
+ for (IpAddressFamily family :
+ {IpAddressFamily::IP_V6, IpAddressFamily::IP_V4}) {
+ int result =
+ inet_pton(ToPlatformAddressFamily(family), str.c_str(), address_.bytes);
+ if (result > 0) {
+ family_ = family;
+ return true;
+ }
+ }
+ return false;
}
bool QuicIpAddress::IsIPv4() const {
- return impl_.IsIPv4();
+ return family_ == IpAddressFamily::IP_V4;
}
bool QuicIpAddress::IsIPv6() const {
- return impl_.IsIPv6();
+ return family_ == IpAddressFamily::IP_V6;
}
bool QuicIpAddress::InSameSubnet(const QuicIpAddress& other,
int subnet_length) {
- return impl_.InSameSubnet(other.impl_, subnet_length);
+ if (!IsInitialized()) {
+ QUIC_BUG << "Attempting to do subnet matching on undefined address";
+ return false;
+ }
+ if ((IsIPv4() && subnet_length > 32) || (IsIPv6() && subnet_length > 128)) {
+ QUIC_BUG << "Subnet mask is out of bounds";
+ return false;
+ }
+
+ int bytes_to_check = subnet_length / 8;
+ int bits_to_check = subnet_length % 8;
+ const uint8_t* const lhs = address_.bytes;
+ const uint8_t* const rhs = other.address_.bytes;
+ if (!std::equal(lhs, lhs + bytes_to_check, rhs)) {
+ return false;
+ }
+ if (bits_to_check == 0) {
+ return true;
+ }
+ DCHECK_LT(static_cast<size_t>(bytes_to_check), sizeof(address_.bytes));
+ int mask = (~0) << (8 - bits_to_check);
+ return (lhs[bytes_to_check] & mask) == (rhs[bytes_to_check] & mask);
}
in_addr QuicIpAddress::GetIPv4() const {
- return impl_.GetIPv4();
+ DCHECK(IsIPv4());
+ return address_.v4;
}
in6_addr QuicIpAddress::GetIPv6() const {
- return impl_.GetIPv6();
+ DCHECK(IsIPv6());
+ return address_.v6;
}
} // namespace quic
diff --git a/quic/platform/api/quic_ip_address.h b/quic/platform/api/quic_ip_address.h
index 6d507b4..e1a1076 100644
--- a/quic/platform/api/quic_ip_address.h
+++ b/quic/platform/api/quic_ip_address.h
@@ -9,6 +9,7 @@
#include <winsock2.h>
#include <ws2tcpip.h>
#else
+#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
@@ -17,18 +18,18 @@
#include <string>
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
-#include "net/quic/platform/impl/quic_ip_address_impl.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address_family.h"
namespace quic {
+// Represents an IP address.
class QUIC_EXPORT_PRIVATE QuicIpAddress {
- // A class representing an IPv4 or IPv6 address in QUIC. The actual
- // implementation (platform dependent) of an IP address is in
- // QuicIpAddressImpl.
public:
+ // Sizes of IP addresses of different types, in bytes.
enum : size_t {
- kIPv4AddressSize = QuicIpAddressImpl::kIPv4AddressSize,
- kIPv6AddressSize = QuicIpAddressImpl::kIPv6AddressSize
+ kIPv4AddressSize = 32 / 8,
+ kIPv6AddressSize = 128 / 8,
+ kMaxAddressSize = kIPv6AddressSize,
};
// TODO(fayang): Remove Loopback*() and use TestLoopback*() in tests.
@@ -37,9 +38,8 @@
static QuicIpAddress Any4();
static QuicIpAddress Any6();
- QuicIpAddress() = default;
+ QuicIpAddress();
QuicIpAddress(const QuicIpAddress& other) = default;
- explicit QuicIpAddress(const QuicIpAddressImpl& impl);
explicit QuicIpAddress(const in_addr& ipv4_address);
explicit QuicIpAddress(const in6_addr& ipv6_address);
QuicIpAddress& operator=(const QuicIpAddress& other) = default;
@@ -77,9 +77,20 @@
in6_addr GetIPv6() const;
private:
- QuicIpAddressImpl impl_;
+ union {
+ in_addr v4;
+ in6_addr v6;
+ uint8_t bytes[kMaxAddressSize];
+ char chars[kMaxAddressSize];
+ } address_;
+ IpAddressFamily family_;
};
+inline std::ostream& operator<<(std::ostream& os, const QuicIpAddress address) {
+ os << address.ToString();
+ return os;
+}
+
} // namespace quic
#endif // QUICHE_QUIC_PLATFORM_API_QUIC_IP_ADDRESS_H_
diff --git a/quic/platform/api/quic_ip_address_test.cc b/quic/platform/api/quic_ip_address_test.cc
index 6942427..7dfe243 100644
--- a/quic/platform/api/quic_ip_address_test.cc
+++ b/quic/platform/api/quic_ip_address_test.cc
@@ -56,6 +56,84 @@
EXPECT_EQ(0xff01u, *(v6_address_ptr + 5));
EXPECT_EQ(0x23feu, *(v6_address_ptr + 6));
EXPECT_EQ(0x6745u, *(v6_address_ptr + 7));
+
+ EXPECT_EQ(ip_address, ip_address.Normalized());
+ EXPECT_EQ(ip_address, ip_address.DualStacked());
+}
+
+TEST(QuicIpAddressTest, FromPackedString) {
+ QuicIpAddress loopback4, loopback6;
+ const char loopback4_packed[] = "\x7f\0\0\x01";
+ const char loopback6_packed[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01";
+ EXPECT_TRUE(loopback4.FromPackedString(loopback4_packed, 4));
+ EXPECT_TRUE(loopback6.FromPackedString(loopback6_packed, 16));
+ EXPECT_EQ(loopback4, QuicIpAddress::Loopback4());
+ EXPECT_EQ(loopback6, QuicIpAddress::Loopback6());
+}
+
+TEST(QuicIpAddressTest, MappedAddress) {
+ QuicIpAddress ipv4_address;
+ QuicIpAddress mapped_address;
+
+ EXPECT_TRUE(ipv4_address.FromString("127.0.0.1"));
+ EXPECT_TRUE(mapped_address.FromString("::ffff:7f00:1"));
+
+ EXPECT_EQ(mapped_address, ipv4_address.DualStacked());
+ EXPECT_EQ(ipv4_address, mapped_address.Normalized());
+}
+
+TEST(QuicIpAddressTest, Subnets) {
+ struct {
+ const char* address1;
+ const char* address2;
+ int subnet_size;
+ bool same_subnet;
+ } test_cases[] = {
+ {"127.0.0.1", "127.0.0.2", 24, true},
+ {"8.8.8.8", "127.0.0.1", 24, false},
+ {"8.8.8.8", "127.0.0.1", 16, false},
+ {"8.8.8.8", "127.0.0.1", 8, false},
+ {"8.8.8.8", "127.0.0.1", 2, false},
+ {"8.8.8.8", "127.0.0.1", 1, true},
+
+ {"127.0.0.1", "127.0.0.128", 24, true},
+ {"127.0.0.1", "127.0.0.128", 25, false},
+ {"127.0.0.1", "127.0.0.127", 25, true},
+
+ {"127.0.0.1", "127.0.0.0", 30, true},
+ {"127.0.0.1", "127.0.0.1", 30, true},
+ {"127.0.0.1", "127.0.0.2", 30, true},
+ {"127.0.0.1", "127.0.0.3", 30, true},
+ {"127.0.0.1", "127.0.0.4", 30, false},
+
+ {"127.0.0.1", "127.0.0.2", 31, false},
+ {"127.0.0.1", "127.0.0.0", 31, true},
+
+ {"::1", "fe80::1", 8, false},
+ {"::1", "fe80::1", 1, false},
+ {"::1", "fe80::1", 0, true},
+ {"fe80::1", "fe80::2", 126, true},
+ {"fe80::1", "fe80::2", 127, false},
+ };
+
+ for (const auto& test_case : test_cases) {
+ QuicIpAddress address1, address2;
+ ASSERT_TRUE(address1.FromString(test_case.address1));
+ ASSERT_TRUE(address2.FromString(test_case.address2));
+ EXPECT_EQ(test_case.same_subnet,
+ address1.InSameSubnet(address2, test_case.subnet_size))
+ << "Addresses: " << test_case.address1 << ", " << test_case.address2
+ << "; subnet: /" << test_case.subnet_size;
+ }
+}
+
+TEST(QuicIpAddress, LoopbackAddresses) {
+ QuicIpAddress loopback4;
+ QuicIpAddress loopback6;
+ ASSERT_TRUE(loopback4.FromString("127.0.0.1"));
+ ASSERT_TRUE(loopback6.FromString("::1"));
+ EXPECT_EQ(loopback4, QuicIpAddress::Loopback4());
+ EXPECT_EQ(loopback6, QuicIpAddress::Loopback6());
}
} // namespace