Automated g4 rollback of changelist 588486234.

*** Reason for rollback ***

Roll forward with fix.

Fairly simple fix. Had accidentally left out some returns after QUICHE_NOTREACHED(). Causes an issue only when building opt (apparently not done in my initial SQ) when the NOTREACHED noops out of existence.

Confirmed a `--compilation_mode=opt third_party/quic/core/io:all` build/test succeeds with this fix and fails without.

*** Original change description ***

Automated g4 rollback of changelist 588217549.

*** Reason for rollback ***

Broke builds.

*** Original change description ***

Allow creation of Raw IP sockets in QUICHE

***

***

PiperOrigin-RevId: 588769610
diff --git a/quiche/quic/core/io/event_loop_connecting_client_socket_test.cc b/quiche/quic/core/io/event_loop_connecting_client_socket_test.cc
index c7e18ce..f195d9d 100644
--- a/quiche/quic/core/io/event_loop_connecting_client_socket_test.cc
+++ b/quiche/quic/core/io/event_loop_connecting_client_socket_test.cc
@@ -4,16 +4,16 @@
 
 #include "quiche/quic/core/io/event_loop_connecting_client_socket.h"
 
-#include <functional>
 #include <memory>
 #include <optional>
 #include <string>
+#include <tuple>
 #include <utility>
-#include <vector>
 
 #include "absl/functional/bind_front.h"
 #include "absl/status/status.h"
 #include "absl/status/statusor.h"
+#include "absl/strings/str_cat.h"
 #include "absl/strings/string_view.h"
 #include "absl/types/span.h"
 #include "quiche/quic/core/connecting_client_socket.h"
@@ -22,7 +22,7 @@
 #include "quiche/quic/core/io/quic_event_loop.h"
 #include "quiche/quic/core/io/socket.h"
 #include "quiche/quic/core/quic_time.h"
-#include "quiche/quic/platform/api/quic_ip_address_family.h"
+#include "quiche/quic/core/quic_types.h"
 #include "quiche/quic/platform/api/quic_socket_address.h"
 #include "quiche/quic/test_tools/mock_clock.h"
 #include "quiche/quic/test_tools/quic_test_utils.h"
@@ -200,6 +200,10 @@
         return socket_factory_->CreateTcpClientSocket(
             peer_address, /*receive_buffer_size=*/0, /*send_buffer_size=*/0,
             async_visitor);
+      default:
+        // Unexpected protocol.
+        QUICHE_NOTREACHED();
+        return nullptr;
     }
   }
 
@@ -219,6 +223,10 @@
         return socket_factory_->CreateTcpClientSocket(
             peer_address, /*receive_buffer_size=*/0, /*send_buffer_size=*/4,
             async_visitor);
+      default:
+        // Unexpected protocol.
+        QUICHE_NOTREACHED();
+        return nullptr;
     }
   }
 
@@ -275,6 +283,9 @@
         runner = std::make_unique<TestTcpServerSocketRunner>(
             server_socket_descriptor_, std::move(behavior));
         break;
+      default:
+        // Unexpected protocol.
+        QUICHE_NOTREACHED();
     }
 
     // Runner takes responsibility for closing server socket.
@@ -375,6 +386,9 @@
       EXPECT_TRUE(connect_result_.value().ok());
       socket->Disconnect();
       break;
+    default:
+      // Unexpected protocol.
+      FAIL();
   }
 }
 
@@ -411,6 +425,9 @@
       // server.
       EXPECT_TRUE(connect_result_.value().ok());
       break;
+    default:
+      // Unexpected protocol.
+      FAIL();
   }
 }
 
@@ -659,6 +676,9 @@
       socket->SendAsync(data);
       expected = data;
       break;
+    default:
+      // Unexpected protocol.
+      FAIL();
   }
   ASSERT_TRUE(send_result_.has_value());
   EXPECT_TRUE(send_result_.value().ok());
diff --git a/quiche/quic/core/io/socket.cc b/quiche/quic/core/io/socket.cc
index 0118003..d41106f 100644
--- a/quiche/quic/core/io/socket.cc
+++ b/quiche/quic/core/io/socket.cc
@@ -50,10 +50,10 @@
   }
 }
 
-absl::Status SetSockOptInt(SocketFd fd, int option, int value) {
+absl::Status SetSockOptInt(SocketFd fd, int level, int option, int value) {
   QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
 
-  int result = SyscallSetsockopt(fd, SOL_SOCKET, option, &value, sizeof(value));
+  int result = SyscallSetsockopt(fd, level, option, &value, sizeof(value));
 
   if (result >= 0) {
     return absl::OkStatus();
@@ -71,14 +71,21 @@
   QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
   QUICHE_DCHECK_LE(size, QuicByteCount{INT_MAX});
 
-  return SetSockOptInt(fd, SO_RCVBUF, static_cast<int>(size));
+  return SetSockOptInt(fd, SOL_SOCKET, SO_RCVBUF, static_cast<int>(size));
 }
 
 absl::Status SetSendBufferSize(SocketFd fd, QuicByteCount size) {
   QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
   QUICHE_DCHECK_LE(size, QuicByteCount{INT_MAX});
 
-  return SetSockOptInt(fd, SO_SNDBUF, static_cast<int>(size));
+  return SetSockOptInt(fd, SOL_SOCKET, SO_SNDBUF, static_cast<int>(size));
+}
+
+absl::Status SetIpHeaderIncluded(SocketFd fd, bool ip_header_included) {
+  QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
+
+  return SetSockOptInt(fd, IPPROTO_IP, IP_HDRINCL,
+                       static_cast<int>(ip_header_included));
 }
 
 absl::Status Connect(SocketFd fd, const QuicSocketAddress& peer_address) {
diff --git a/quiche/quic/core/io/socket.h b/quiche/quic/core/io/socket.h
index edff4ee..319dff4 100644
--- a/quiche/quic/core/io/socket.h
+++ b/quiche/quic/core/io/socket.h
@@ -5,9 +5,6 @@
 #ifndef QUICHE_QUIC_CORE_IO_SOCKET_H_
 #define QUICHE_QUIC_CORE_IO_SOCKET_H_
 
-#include <functional>
-#include <string>
-
 #include "absl/status/status.h"
 #include "absl/status/statusor.h"
 #include "absl/strings/string_view.h"
@@ -15,7 +12,6 @@
 #include "quiche/quic/core/quic_types.h"
 #include "quiche/quic/platform/api/quic_ip_address_family.h"
 #include "quiche/quic/platform/api/quic_socket_address.h"
-#include "quiche/common/platform/api/quiche_export.h"
 
 #if defined(_WIN32)
 #include <winsock2.h>
@@ -42,6 +38,7 @@
 enum class SocketProtocol {
   kUdp,
   kTcp,
+  kRawIp,
 };
 
 inline absl::string_view GetProtocolName(SocketProtocol protocol) {
@@ -50,6 +47,8 @@
       return "UDP";
     case SocketProtocol::kTcp:
       return "TCP";
+    case SocketProtocol::kRawIp:
+      return "RAW_IP";
   }
 
   return "unknown";
@@ -76,6 +75,11 @@
 absl::Status SetReceiveBufferSize(SocketFd fd, QuicByteCount size);
 absl::Status SetSendBufferSize(SocketFd fd, QuicByteCount size);
 
+// Only allowed for raw IP sockets. If set, sent data buffers include the IP
+// header. If not set, sent data buffers only contain the IP packet payload, and
+// the header will be generated.
+absl::Status SetIpHeaderIncluded(SocketFd fd, bool ip_header_included);
+
 // Connects socket `fd` to `peer_address`.  Returns a status with
 // `absl::StatusCode::kUnavailable` iff the socket is non-blocking and the
 // connection could not be immediately completed.  The socket will then complete
diff --git a/quiche/quic/core/io/socket_internal.h b/quiche/quic/core/io/socket_internal.h
index 3fc9f00..d11c0ef 100644
--- a/quiche/quic/core/io/socket_internal.h
+++ b/quiche/quic/core/io/socket_internal.h
@@ -21,6 +21,8 @@
       return SOCK_DGRAM;
     case SocketProtocol::kTcp:
       return SOCK_STREAM;
+    case SocketProtocol::kRawIp:
+      return SOCK_RAW;
   }
 
   QUICHE_NOTREACHED();
@@ -33,6 +35,8 @@
       return IPPROTO_UDP;
     case SocketProtocol::kTcp:
       return IPPROTO_TCP;
+    case SocketProtocol::kRawIp:
+      return IPPROTO_RAW;
   }
 
   QUICHE_NOTREACHED();
diff --git a/quiche/quic/core/io/socket_test.cc b/quiche/quic/core/io/socket_test.cc
index da1d24a..9e18cc1 100644
--- a/quiche/quic/core/io/socket_test.cc
+++ b/quiche/quic/core/io/socket_test.cc
@@ -5,13 +5,12 @@
 #include "quiche/quic/core/io/socket.h"
 
 #include <string>
-#include <utility>
 
 #include "absl/status/status.h"
 #include "absl/status/statusor.h"
 #include "absl/strings/string_view.h"
 #include "absl/types/span.h"
-#include "quiche/quic/platform/api/quic_ip_address_family.h"
+#include "quiche/quic/platform/api/quic_ip_address.h"
 #include "quiche/quic/platform/api/quic_socket_address.h"
 #include "quiche/common/platform/api/quiche_logging.h"
 #include "quiche/common/platform/api/quiche_test.h"
@@ -39,6 +38,20 @@
   }
 }
 
+SocketFd CreateTestRawSocket(bool blocking = true) {
+  absl::StatusOr<SocketFd> socket =
+      socket_api::CreateSocket(quiche::TestLoopback().address_family(),
+                               socket_api::SocketProtocol::kRawIp, blocking);
+
+  if (socket.ok()) {
+    return socket.value();
+  } else {
+    // This is expected if test not run with relevant admin privileges.
+    QUICHE_CHECK(absl::IsPermissionDenied(socket.status()));
+    return kInvalidSocketFd;
+  }
+}
+
 TEST(SocketTest, CreateAndCloseSocket) {
   QuicIpAddress localhost_address = quiche::TestLoopback();
   absl::StatusOr<SocketFd> created_socket = socket_api::CreateSocket(
@@ -49,6 +62,22 @@
   QUICHE_EXPECT_OK(socket_api::Close(created_socket.value()));
 }
 
+TEST(SocketTest, CreateAndCloseRawSocket) {
+  QuicIpAddress localhost_address = quiche::TestLoopback();
+  absl::StatusOr<SocketFd> created_socket = socket_api::CreateSocket(
+      localhost_address.address_family(), socket_api::SocketProtocol::kRawIp);
+
+  // Raw IP socket creation will typically fail if not run with relevant admin
+  // privileges.
+  if (!created_socket.ok()) {
+    EXPECT_THAT(created_socket.status(),
+                StatusIs(absl::StatusCode::kPermissionDenied));
+    return;
+  }
+
+  QUICHE_EXPECT_OK(socket_api::Close(created_socket.value()));
+}
+
 TEST(SocketTest, SetSocketBlocking) {
   SocketFd socket = CreateTestSocket(socket_api::SocketProtocol::kUdp,
                                      /*blocking=*/true);
@@ -76,6 +105,30 @@
   QUICHE_EXPECT_OK(socket_api::Close(socket));
 }
 
+TEST(SocketTest, SetIpHeaderIncludedForRaw) {
+  SocketFd socket = CreateTestRawSocket(/*blocking=*/true);
+  if (socket == kInvalidSocketFd) {
+    return;
+  }
+
+  QUICHE_EXPECT_OK(
+      socket_api::SetIpHeaderIncluded(socket, /*ip_header_included=*/true));
+
+  QUICHE_EXPECT_OK(socket_api::Close(socket));
+}
+
+TEST(SocketTest, SetIpHeaderIncludedForUdp) {
+  SocketFd socket = CreateTestSocket(socket_api::SocketProtocol::kUdp,
+                                     /*blocking=*/true);
+
+  // Expect option only allowed for raw IP sockets.
+  EXPECT_THAT(
+      socket_api::SetIpHeaderIncluded(socket, /*ip_header_included=*/true),
+      StatusIs(absl::StatusCode::kInvalidArgument));
+
+  QUICHE_EXPECT_OK(socket_api::Close(socket));
+}
+
 TEST(SocketTest, Connect) {
   SocketFd socket = CreateTestSocket(socket_api::SocketProtocol::kUdp);