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