Add ipv6_only to QuicUdpSocketApi::Create.

This is necessary for iOS compatibility - setting IP_PKTINFO on an IPv6 socket will always fail.  ipv6_only will cause IP_PKTINFO to be skipped for IPv6 sockets.

Testing is also expanded to cover forcing IPv6 on all platforms, as well as to ensure that ipv6_only does not cause breakages on other platforms.

Add ipv6_only for quicudpsocketapi::create.  this does not change default behavior.

PiperOrigin-RevId: 313669717
Change-Id: I0e33b5ff94ceb299e69a50976062f04b4a3452bb
diff --git a/quic/core/quic_udp_socket.h b/quic/core/quic_udp_socket.h
index 04f8435..258de08 100644
--- a/quic/core/quic_udp_socket.h
+++ b/quic/core/quic_udp_socket.h
@@ -163,10 +163,14 @@
  public:
   // Creates a non-blocking udp socket, sets the receive/send buffer and enable
   // receiving of self ip addresses on read.
-  // Return kQuicInvalidSocketFd if failed.
+  // If address_family == AF_INET6 and ipv6_only is true, receiving of IPv4 self
+  // addresses is disabled. This is only necessary for IPv6 sockets on iOS - all
+  // other platforms can ignore this parameter. Return kQuicInvalidSocketFd if
+  // failed.
   QuicUdpSocketFd Create(int address_family,
                          int receive_buffer_size,
-                         int send_buffer_size);
+                         int send_buffer_size,
+                         bool ipv6_only = false);
 
   // Closes |fd|. No-op if |fd| equals to kQuicInvalidSocketFd.
   void Destroy(QuicUdpSocketFd fd);
@@ -238,7 +242,8 @@
   bool SetupSocket(QuicUdpSocketFd fd,
                    int address_family,
                    int receive_buffer_size,
-                   int send_buffer_size);
+                   int send_buffer_size,
+                   bool ipv6_only);
   bool EnableReceiveSelfIpAddressForV4(QuicUdpSocketFd fd);
   bool EnableReceiveSelfIpAddressForV6(QuicUdpSocketFd fd);
 };
diff --git a/quic/core/quic_udp_socket_posix.cc b/quic/core/quic_udp_socket_posix.cc
index b6c58cd..c5ab345 100644
--- a/quic/core/quic_udp_socket_posix.cc
+++ b/quic/core/quic_udp_socket_posix.cc
@@ -239,7 +239,8 @@
 
 QuicUdpSocketFd QuicUdpSocketApi::Create(int address_family,
                                          int receive_buffer_size,
-                                         int send_buffer_size) {
+                                         int send_buffer_size,
+                                         bool ipv6_only) {
   // DCHECK here so the program exits early(before reading packets) in debug
   // mode. This should have been a static_assert, however it can't be done on
   // ios/osx because CMSG_SPACE isn't a constant expression there.
@@ -250,7 +251,8 @@
     return kQuicInvalidSocketFd;
   }
 
-  if (!SetupSocket(fd, address_family, receive_buffer_size, send_buffer_size)) {
+  if (!SetupSocket(fd, address_family, receive_buffer_size, send_buffer_size,
+                   ipv6_only)) {
     Destroy(fd);
     return kQuicInvalidSocketFd;
   }
@@ -261,7 +263,8 @@
 bool QuicUdpSocketApi::SetupSocket(QuicUdpSocketFd fd,
                                    int address_family,
                                    int receive_buffer_size,
-                                   int send_buffer_size) {
+                                   int send_buffer_size,
+                                   bool ipv6_only) {
   // Receive buffer size.
   if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &receive_buffer_size,
                  sizeof(receive_buffer_size)) != 0) {
@@ -276,14 +279,20 @@
     return false;
   }
 
-  if (!EnableReceiveSelfIpAddressForV4(fd)) {
-    QUIC_LOG_FIRST_N(ERROR, 100) << "Failed to enable receiving of self v4 ip";
-    return false;
+  if (!(address_family == AF_INET6 && ipv6_only)) {
+    if (!EnableReceiveSelfIpAddressForV4(fd)) {
+      QUIC_LOG_FIRST_N(ERROR, 100)
+          << "Failed to enable receiving of self v4 ip";
+      return false;
+    }
   }
 
-  if (address_family == AF_INET6 && !EnableReceiveSelfIpAddressForV6(fd)) {
-    QUIC_LOG_FIRST_N(ERROR, 100) << "Failed to enable receiving of self v6 ip";
-    return false;
+  if (address_family == AF_INET6) {
+    if (!EnableReceiveSelfIpAddressForV6(fd)) {
+      QUIC_LOG_FIRST_N(ERROR, 100)
+          << "Failed to enable receiving of self v6 ip";
+      return false;
+    }
   }
 
   return true;
diff --git a/quic/core/quic_udp_socket_test.cc b/quic/core/quic_udp_socket_test.cc
index e43fb10..f54b0ed 100644
--- a/quic/core/quic_udp_socket_test.cc
+++ b/quic/core/quic_udp_socket_test.cc
@@ -3,6 +3,11 @@
 // found in the LICENSE file.
 
 #include "net/third_party/quiche/src/quic/core/quic_udp_socket.h"
+#include <sys/socket.h>
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
 
 #include "net/third_party/quiche/src/quic/core/quic_constants.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
@@ -15,33 +20,49 @@
   char control_buffer[512];
   char packet_buffer[1536];
 };
+
+// Allows IPv6-specific testing.
+struct TestParameters {
+  // If true, the test will only use IPv6.  If false, IPv4 will be used if
+  // possible, with IPv6 used as a fallback.
+  bool force_ipv6;
+  // The value of ipv6_only to be used in QuicUdpSocketApi::Create calls.
+  bool ipv6_only;
+};
 }  // namespace
 
-class QuicUdpSocketTest : public QuicTest {
+class QuicUdpSocketTest : public QuicTestWithParam<TestParameters> {
  protected:
   void SetUp() override {
-    // Try creating AF_INET socket, if it fails because of unsupported address
-    // family then tests are being run under IPv6-only environment, initialize
-    // address family to use for running the test under as AF_INET6 otherwise
-    // initialize it as AF_INET.
-    address_family_ = AF_INET;
-    fd_client_ =
-        api_.Create(address_family_,
-                    /*receive_buffer_size =*/kDefaultSocketReceiveBuffer,
-                    /*send_buffer_size =*/kDefaultSocketReceiveBuffer);
+    const TestParameters& parameters = GetParam();
+    if (!parameters.force_ipv6) {
+      // Try creating AF_INET socket, if it fails because of unsupported address
+      // family then tests are being run under IPv6-only environment, initialize
+      // address family to use for running the test under as AF_INET6 otherwise
+      // initialize it as AF_INET.
+      address_family_ = AF_INET;
+      fd_client_ =
+          api_.Create(address_family_,
+                      /*receive_buffer_size =*/kDefaultSocketReceiveBuffer,
+                      /*send_buffer_size =*/kDefaultSocketReceiveBuffer,
+                      /*ipv6_only =*/parameters.ipv6_only);
+    }
     if (fd_client_ == kQuicInvalidSocketFd) {
+      // Either AF_INET is unsupported, or force_ipv6 is true.
       address_family_ = AF_INET6;
       fd_client_ =
           api_.Create(address_family_,
                       /*receive_buffer_size =*/kDefaultSocketReceiveBuffer,
-                      /*send_buffer_size =*/kDefaultSocketReceiveBuffer);
+                      /*send_buffer_size =*/kDefaultSocketReceiveBuffer,
+                      /*ipv6_only =*/parameters.ipv6_only);
     }
     ASSERT_NE(fd_client_, kQuicInvalidSocketFd);
 
     fd_server_ =
         api_.Create(address_family_,
                     /*receive_buffer_size =*/kDefaultSocketReceiveBuffer,
-                    /*send_buffer_size =*/kDefaultSocketReceiveBuffer);
+                    /*send_buffer_size =*/kDefaultSocketReceiveBuffer,
+                    /*ipv6_only =*/parameters.ipv6_only);
     ASSERT_NE(fd_server_, kQuicInvalidSocketFd);
 
     ASSERT_TRUE(
@@ -114,8 +135,8 @@
   }
 
   QuicUdpSocketApi api_;
-  QuicUdpSocketFd fd_client_;
-  QuicUdpSocketFd fd_server_;
+  QuicUdpSocketFd fd_client_ = kQuicInvalidSocketFd;
+  QuicUdpSocketFd fd_server_ = kQuicInvalidSocketFd;
   QuicSocketAddress server_address_;
   int address_family_;
   char client_packet_buffer_[kEthernetMTU] = {0};
@@ -123,7 +144,22 @@
   char server_control_buffer_[512] = {0};
 };
 
-TEST_F(QuicUdpSocketTest, ReadPacketResultReset) {
+INSTANTIATE_TEST_SUITE_P(
+    PlatformIndependent,
+    QuicUdpSocketTest,
+    testing::Values(TestParameters{/*force_ipv6 =*/false, /*ipv6_only =*/false},
+                    TestParameters{/*force_ipv6 =*/false, /*ipv6_only =*/true},
+                    TestParameters{/*force_ipv6 =*/true, /*ipv6_only =*/true}));
+
+#ifndef TARGET_OS_IPHONE
+// IPv6 on iOS is known to fail without ipv6_only, so should not be tested.
+INSTANTIATE_TEST_SUITE_P(NonIos,
+                         QuicUdpSocketTest,
+                         testing::Values(TestParameters{/*force_ipv6 =*/true,
+                                                        /*ipv6_only =*/false}));
+#endif
+
+TEST_P(QuicUdpSocketTest, ReadPacketResultReset) {
   QuicUdpSocketApi::ReadPacketResult result;
   result.packet_info.SetDroppedPackets(100);
   result.packet_buffer.buffer_len = 100;
@@ -137,7 +173,7 @@
   EXPECT_EQ(200u, result.packet_buffer.buffer_len);
 }
 
-TEST_F(QuicUdpSocketTest, ReadPacketOnly) {
+TEST_P(QuicUdpSocketTest, ReadPacketOnly) {
   const size_t kPacketSize = 512;
   memset(client_packet_buffer_, '-', kPacketSize);
   ASSERT_EQ(WriteResult(WRITE_STATUS_OK, kPacketSize),
@@ -150,7 +186,7 @@
   ASSERT_EQ(0, ComparePacketBuffers(kPacketSize));
 }
 
-TEST_F(QuicUdpSocketTest, ReadTruncated) {
+TEST_P(QuicUdpSocketTest, ReadTruncated) {
   const size_t kPacketSize = kDefaultMaxPacketSize + 1;
   memset(client_packet_buffer_, '*', kPacketSize);
   ASSERT_EQ(WriteResult(WRITE_STATUS_OK, kPacketSize),
@@ -161,7 +197,7 @@
   ASSERT_FALSE(read_result.ok);
 }
 
-TEST_F(QuicUdpSocketTest, ReadDroppedPackets) {
+TEST_P(QuicUdpSocketTest, ReadDroppedPackets) {
   const size_t kPacketSize = kDefaultMaxPacketSize;
   memset(client_packet_buffer_, '-', kPacketSize);
   ASSERT_EQ(WriteResult(WRITE_STATUS_OK, kPacketSize),
@@ -193,7 +229,7 @@
   }
 }
 
-TEST_F(QuicUdpSocketTest, ReadSelfIp) {
+TEST_P(QuicUdpSocketTest, ReadSelfIp) {
   const QuicUdpPacketInfoBit self_ip_bit =
       (address_family_ == AF_INET) ? QuicUdpPacketInfoBit::V4_SELF_IP
                                    : QuicUdpPacketInfoBit::V6_SELF_IP;
@@ -214,7 +250,7 @@
                             : read_result.packet_info.self_v6_ip());
 }
 
-TEST_F(QuicUdpSocketTest, ReadReceiveTimestamp) {
+TEST_P(QuicUdpSocketTest, ReadReceiveTimestamp) {
   const size_t kPacketSize = kDefaultMaxPacketSize;
   memset(client_packet_buffer_, '-', kPacketSize);
   ASSERT_EQ(WriteResult(WRITE_STATUS_OK, kPacketSize),
@@ -249,7 +285,7 @@
       QuicWallTime::FromUNIXSeconds(1577836800).IsBefore(recv_timestamp));
 }
 
-TEST_F(QuicUdpSocketTest, Ttl) {
+TEST_P(QuicUdpSocketTest, Ttl) {
   const size_t kPacketSize = 512;
   memset(client_packet_buffer_, '$', kPacketSize);
   ASSERT_EQ(WriteResult(WRITE_STATUS_OK, kPacketSize),
@@ -282,7 +318,7 @@
   EXPECT_EQ(13, read_result.packet_info.ttl());
 }
 
-TEST_F(QuicUdpSocketTest, ReadMultiplePackets) {
+TEST_P(QuicUdpSocketTest, ReadMultiplePackets) {
   const QuicUdpPacketInfoBit self_ip_bit =
       (address_family_ == AF_INET) ? QuicUdpPacketInfoBit::V4_SELF_IP
                                    : QuicUdpPacketInfoBit::V6_SELF_IP;
@@ -335,7 +371,7 @@
   }
 }
 
-TEST_F(QuicUdpSocketTest, ReadMultiplePacketsSomeTruncated) {
+TEST_P(QuicUdpSocketTest, ReadMultiplePacketsSomeTruncated) {
   const QuicUdpPacketInfoBit self_ip_bit =
       (address_family_ == AF_INET) ? QuicUdpPacketInfoBit::V4_SELF_IP
                                    : QuicUdpPacketInfoBit::V6_SELF_IP;