Add a Windows implementation of socket.h

PiperOrigin-RevId: 527328777
diff --git a/build/source_list.bzl b/build/source_list.bzl
index 3ddc596..50d3f48 100644
--- a/build/source_list.bzl
+++ b/build/source_list.bzl
@@ -956,6 +956,7 @@
     "quic/core/io/quic_event_loop.h",
     "quic/core/io/quic_poll_event_loop.h",
     "quic/core/io/socket.h",
+    "quic/core/io/socket_internal.h",
     "quic/core/quic_default_packet_writer.h",
     "quic/core/quic_packet_reader.h",
     "quic/core/quic_syscall_wrapper.h",
@@ -982,7 +983,9 @@
     "quic/core/io/event_loop_socket_factory.cc",
     "quic/core/io/quic_default_event_loop.cc",
     "quic/core/io/quic_poll_event_loop.cc",
-    "quic/core/io/socket_posix.cc",
+    "quic/core/io/socket.cc",
+    "quic/core/io/socket_posix.inc",
+    "quic/core/io/socket_win.inc",
     "quic/core/quic_default_packet_writer.cc",
     "quic/core/quic_packet_reader.cc",
     "quic/core/quic_syscall_wrapper.cc",
diff --git a/build/source_list.gni b/build/source_list.gni
index 3950cd3..c1baf44 100644
--- a/build/source_list.gni
+++ b/build/source_list.gni
@@ -956,6 +956,7 @@
     "src/quiche/quic/core/io/quic_event_loop.h",
     "src/quiche/quic/core/io/quic_poll_event_loop.h",
     "src/quiche/quic/core/io/socket.h",
+    "src/quiche/quic/core/io/socket_internal.h",
     "src/quiche/quic/core/quic_default_packet_writer.h",
     "src/quiche/quic/core/quic_packet_reader.h",
     "src/quiche/quic/core/quic_syscall_wrapper.h",
@@ -982,7 +983,9 @@
     "src/quiche/quic/core/io/event_loop_socket_factory.cc",
     "src/quiche/quic/core/io/quic_default_event_loop.cc",
     "src/quiche/quic/core/io/quic_poll_event_loop.cc",
-    "src/quiche/quic/core/io/socket_posix.cc",
+    "src/quiche/quic/core/io/socket.cc",
+    "src/quiche/quic/core/io/socket_posix.inc",
+    "src/quiche/quic/core/io/socket_win.inc",
     "src/quiche/quic/core/quic_default_packet_writer.cc",
     "src/quiche/quic/core/quic_packet_reader.cc",
     "src/quiche/quic/core/quic_syscall_wrapper.cc",
diff --git a/build/source_list.json b/build/source_list.json
index 3e8c573..e51e004 100644
--- a/build/source_list.json
+++ b/build/source_list.json
@@ -955,6 +955,7 @@
     "quiche/quic/core/io/quic_event_loop.h",
     "quiche/quic/core/io/quic_poll_event_loop.h",
     "quiche/quic/core/io/socket.h",
+    "quiche/quic/core/io/socket_internal.h",
     "quiche/quic/core/quic_default_packet_writer.h",
     "quiche/quic/core/quic_packet_reader.h",
     "quiche/quic/core/quic_syscall_wrapper.h",
@@ -981,7 +982,9 @@
     "quiche/quic/core/io/event_loop_socket_factory.cc",
     "quiche/quic/core/io/quic_default_event_loop.cc",
     "quiche/quic/core/io/quic_poll_event_loop.cc",
-    "quiche/quic/core/io/socket_posix.cc",
+    "quiche/quic/core/io/socket.cc",
+    "quiche/quic/core/io/socket_posix.inc",
+    "quiche/quic/core/io/socket_win.inc",
     "quiche/quic/core/quic_default_packet_writer.cc",
     "quiche/quic/core/quic_packet_reader.cc",
     "quiche/quic/core/quic_syscall_wrapper.cc",
diff --git a/quiche/quic/core/io/socket.cc b/quiche/quic/core/io/socket.cc
new file mode 100644
index 0000000..d914ffd
--- /dev/null
+++ b/quiche/quic/core/io/socket.cc
@@ -0,0 +1,266 @@
+// Copyright 2022 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 "quiche/quic/core/io/socket.h"
+
+#include "absl/base/attributes.h"
+#include "absl/container/flat_hash_set.h"
+#include "absl/status/status.h"
+#include "absl/status/statusor.h"
+#include "absl/strings/string_view.h"
+#include "quiche/quic/core/io/socket_internal.h"
+#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_logging.h"
+
+#if defined(_WIN32)
+#include "quiche/quic/core/io/socket_win.inc"
+#else
+#include "quiche/quic/core/io/socket_posix.inc"
+#endif
+
+namespace quic::socket_api {
+
+namespace {
+
+absl::StatusOr<AcceptResult> AcceptInternal(SocketFd fd) {
+  QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
+
+  sockaddr_storage peer_addr;
+  PlatformSocklen peer_addr_len = sizeof(peer_addr);
+  SocketFd connection_socket = SyscallAccept(
+      fd, reinterpret_cast<struct sockaddr*>(&peer_addr), &peer_addr_len);
+
+  if (connection_socket == kInvalidSocketFd) {
+    absl::Status status = LastSocketOperationError("::accept()");
+    QUICHE_DVLOG(1) << "Failed to accept connection from socket " << fd
+                    << " with error: " << status;
+    return status;
+  }
+
+  absl::StatusOr<QuicSocketAddress> peer_address =
+      ValidateAndConvertAddress(peer_addr, peer_addr_len);
+
+  if (peer_address.ok()) {
+    return AcceptResult{connection_socket, peer_address.value()};
+  } else {
+    return peer_address.status();
+  }
+}
+
+absl::Status SetSockOptInt(SocketFd fd, int option, int value) {
+  QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
+
+  int result = SyscallSetsockopt(fd, SOL_SOCKET, option, &value, sizeof(value));
+
+  if (result >= 0) {
+    return absl::OkStatus();
+  } else {
+    absl::Status status = LastSocketOperationError("::setsockopt()");
+    QUICHE_DVLOG(1) << "Failed to set socket " << fd << " option " << option
+                    << " to " << value << " with error: " << status;
+    return status;
+  }
+}
+
+}  // namespace
+
+absl::Status SetReceiveBufferSize(SocketFd fd, QuicByteCount size) {
+  QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
+  QUICHE_DCHECK_LE(size, QuicByteCount{INT_MAX});
+
+  return SetSockOptInt(fd, 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));
+}
+
+absl::Status Connect(SocketFd fd, const QuicSocketAddress& peer_address) {
+  QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
+  QUICHE_DCHECK(peer_address.IsInitialized());
+
+  sockaddr_storage addr = peer_address.generic_address();
+  PlatformSocklen addrlen = GetAddrlen(peer_address.host().address_family());
+
+  int connect_result =
+      SyscallConnect(fd, reinterpret_cast<sockaddr*>(&addr), addrlen);
+
+  if (connect_result >= 0) {
+    return absl::OkStatus();
+  } else {
+    // For ::connect(), only `EINPROGRESS` indicates unavailable.
+    absl::Status status =
+        LastSocketOperationError("::connect()", /*unavailable_error_numbers=*/
+                                 {EINPROGRESS});
+    QUICHE_DVLOG(1) << "Failed to connect socket " << fd
+                    << " to address: " << peer_address.ToString()
+                    << " with error: " << status;
+    return status;
+  }
+}
+
+absl::Status GetSocketError(SocketFd fd) {
+  QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
+
+  int socket_error = 0;
+  PlatformSocklen len = sizeof(socket_error);
+  int sockopt_result =
+      SyscallGetsockopt(fd, SOL_SOCKET, SO_ERROR, &socket_error, &len);
+
+  if (sockopt_result >= 0) {
+    if (socket_error == 0) {
+      return absl::OkStatus();
+    } else {
+      return ToStatus(socket_error, "SO_ERROR");
+    }
+  } else {
+    absl::Status status = LastSocketOperationError("::getsockopt()");
+    QUICHE_LOG_FIRST_N(ERROR, 100)
+        << "Failed to get socket error information from socket " << fd
+        << " with error: " << status;
+    return status;
+  }
+}
+
+absl::Status Bind(SocketFd fd, const QuicSocketAddress& address) {
+  QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
+  QUICHE_DCHECK(address.IsInitialized());
+
+  sockaddr_storage addr = address.generic_address();
+  PlatformSocklen addr_len = GetAddrlen(address.host().address_family());
+
+  int result = SyscallBind(fd, reinterpret_cast<sockaddr*>(&addr), addr_len);
+
+  if (result >= 0) {
+    return absl::OkStatus();
+  } else {
+    absl::Status status = LastSocketOperationError("::bind()");
+    QUICHE_DVLOG(1) << "Failed to bind socket " << fd
+                    << " to address: " << address.ToString()
+                    << " with error: " << status;
+    return status;
+  }
+}
+
+absl::StatusOr<QuicSocketAddress> GetSocketAddress(SocketFd fd) {
+  QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
+
+  sockaddr_storage addr;
+  PlatformSocklen addr_len = sizeof(addr);
+
+  int result =
+      SyscallGetsockname(fd, reinterpret_cast<sockaddr*>(&addr), &addr_len);
+
+  if (result >= 0) {
+    return ValidateAndConvertAddress(addr, addr_len);
+  } else {
+    absl::Status status = LastSocketOperationError("::getsockname()");
+    QUICHE_DVLOG(1) << "Failed to get socket " << fd
+                    << " name with error: " << status;
+    return status;
+  }
+}
+
+absl::Status Listen(SocketFd fd, int backlog) {
+  QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
+  QUICHE_DCHECK_GT(backlog, 0);
+
+  int result = SyscallListen(fd, backlog);
+
+  if (result >= 0) {
+    return absl::OkStatus();
+  } else {
+    absl::Status status = LastSocketOperationError("::listen()");
+    QUICHE_DVLOG(1) << "Failed to mark socket: " << fd
+                    << " to listen with error :" << status;
+    return status;
+  }
+}
+
+absl::StatusOr<AcceptResult> Accept(SocketFd fd, bool blocking) {
+  QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
+
+#if defined(HAS_ACCEPT4)
+  if (!blocking) {
+    return AcceptWithFlags(fd, SOCK_NONBLOCK);
+  }
+#endif
+
+  absl::StatusOr<AcceptResult> accept_result = AcceptInternal(fd);
+  if (!accept_result.ok() || blocking) {
+    return accept_result;
+  }
+
+#if !defined(__linux__) || !defined(SOCK_NONBLOCK)
+  // If non-blocking could not be set directly on socket acceptance, need to
+  // do it now.
+  absl::Status set_non_blocking_result =
+      SetSocketBlocking(accept_result.value().fd, /*blocking=*/false);
+  if (!set_non_blocking_result.ok()) {
+    QUICHE_LOG_FIRST_N(ERROR, 100)
+        << "Failed to set socket " << fd << " as non-blocking on acceptance.";
+    if (!Close(accept_result.value().fd).ok()) {
+      QUICHE_LOG_FIRST_N(ERROR, 100)
+          << "Failed to close socket " << accept_result.value().fd
+          << " after error setting non-blocking on acceptance.";
+    }
+    return set_non_blocking_result;
+  }
+#endif
+
+  return accept_result;
+}
+
+absl::StatusOr<absl::Span<char>> Receive(SocketFd fd, absl::Span<char> buffer,
+                                         bool peek) {
+  QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
+  QUICHE_DCHECK(!buffer.empty());
+
+  PlatformSsizeT num_read = SyscallRecv(fd, buffer.data(), buffer.size(),
+                                        /*flags=*/peek ? MSG_PEEK : 0);
+
+  if (num_read > 0 && static_cast<size_t>(num_read) > buffer.size()) {
+    QUICHE_LOG_FIRST_N(WARNING, 100)
+        << "Received more bytes (" << num_read << ") from socket " << fd
+        << " than buffer size (" << buffer.size() << ").";
+    return absl::OutOfRangeError(
+        "::recv(): Received more bytes than buffer size.");
+  } else if (num_read >= 0) {
+    return buffer.subspan(0, num_read);
+  } else {
+    absl::Status status = LastSocketOperationError("::recv()");
+    QUICHE_DVLOG(1) << "Failed to receive from socket: " << fd
+                    << " with error: " << status;
+    return status;
+  }
+}
+
+absl::StatusOr<absl::string_view> Send(SocketFd fd, absl::string_view buffer) {
+  QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
+  QUICHE_DCHECK(!buffer.empty());
+
+  PlatformSsizeT num_sent =
+      SyscallSend(fd, buffer.data(), buffer.size(), /*flags=*/0);
+
+  if (num_sent > 0 && static_cast<size_t>(num_sent) > buffer.size()) {
+    QUICHE_LOG_FIRST_N(WARNING, 100)
+        << "Sent more bytes (" << num_sent << ") to socket " << fd
+        << " than buffer size (" << buffer.size() << ").";
+    return absl::OutOfRangeError("::send(): Sent more bytes than buffer size.");
+  } else if (num_sent >= 0) {
+    return buffer.substr(num_sent);
+  } else {
+    absl::Status status = LastSocketOperationError("::send()");
+    QUICHE_DVLOG(1) << "Failed to send to socket: " << fd
+                    << " with error: " << status;
+    return status;
+  }
+}
+
+}  // namespace quic::socket_api
diff --git a/quiche/quic/core/io/socket.h b/quiche/quic/core/io/socket.h
index 7298f7e..d428f8c 100644
--- a/quiche/quic/core/io/socket.h
+++ b/quiche/quic/core/io/socket.h
@@ -19,6 +19,8 @@
 
 #if defined(_WIN32)
 #include <winsock2.h>
+#else
+#include <sys/socket.h>
 #endif  // defined(_WIN32)
 
 namespace quic {
diff --git a/quiche/quic/core/io/socket_internal.h b/quiche/quic/core/io/socket_internal.h
new file mode 100644
index 0000000..3fc9f00
--- /dev/null
+++ b/quiche/quic/core/io/socket_internal.h
@@ -0,0 +1,78 @@
+// Copyright 2022 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.
+
+// Internal socket tools shared between Windows and POSIX implementations.
+
+#ifndef QUICHE_QUIC_CORE_IO_SOCKET_INTERNAL_H_
+#define QUICHE_QUIC_CORE_IO_SOCKET_INTERNAL_H_
+
+#include "absl/status/status.h"
+#include "absl/status/statusor.h"
+#include "quiche/quic/core/io/socket.h"
+#include "quiche/quic/platform/api/quic_socket_address.h"
+#include "quiche/common/platform/api/quiche_logging.h"
+
+namespace quic::socket_api {
+
+inline int ToPlatformSocketType(SocketProtocol protocol) {
+  switch (protocol) {
+    case SocketProtocol::kUdp:
+      return SOCK_DGRAM;
+    case SocketProtocol::kTcp:
+      return SOCK_STREAM;
+  }
+
+  QUICHE_NOTREACHED();
+  return -1;
+}
+
+inline int ToPlatformProtocol(SocketProtocol protocol) {
+  switch (protocol) {
+    case SocketProtocol::kUdp:
+      return IPPROTO_UDP;
+    case SocketProtocol::kTcp:
+      return IPPROTO_TCP;
+  }
+
+  QUICHE_NOTREACHED();
+  return -1;
+}
+
+// A wrapper around QuicSocketAddress(sockaddr_storage) constructor that
+// validates the supplied address.
+inline absl::StatusOr<QuicSocketAddress> ValidateAndConvertAddress(
+    const sockaddr_storage& addr, socklen_t addr_len) {
+  if (addr.ss_family != AF_INET && addr.ss_family != AF_INET6) {
+    QUICHE_DVLOG(1) << "Socket did not have recognized address family: "
+                    << addr.ss_family;
+    return absl::UnimplementedError("Unrecognized address family.");
+  }
+
+  if ((addr.ss_family == AF_INET && addr_len != sizeof(sockaddr_in)) ||
+      (addr.ss_family == AF_INET6 && addr_len != sizeof(sockaddr_in6))) {
+    QUICHE_DVLOG(1) << "Socket did not have expected address size ("
+                    << (addr.ss_family == AF_INET ? sizeof(sockaddr_in)
+                                                  : sizeof(sockaddr_in6))
+                    << "), had: " << addr_len;
+    return absl::UnimplementedError("Unhandled address size.");
+  }
+
+  return QuicSocketAddress(addr);
+}
+
+inline socklen_t GetAddrlen(IpAddressFamily family) {
+  switch (family) {
+    case IpAddressFamily::IP_V4:
+      return sizeof(sockaddr_in);
+    case IpAddressFamily::IP_V6:
+      return sizeof(sockaddr_in6);
+    default:
+      QUICHE_NOTREACHED();
+      return 0;
+  }
+}
+
+}  // namespace quic::socket_api
+
+#endif  // QUICHE_QUIC_CORE_IO_SOCKET_INTERNAL_H_
diff --git a/quiche/quic/core/io/socket_posix.cc b/quiche/quic/core/io/socket_posix.cc
deleted file mode 100644
index a15140b..0000000
--- a/quiche/quic/core/io/socket_posix.cc
+++ /dev/null
@@ -1,522 +0,0 @@
-// Copyright 2022 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 <fcntl.h>
-#include <sys/socket.h>
-
-#include <climits>
-
-#include "absl/base/attributes.h"
-#include "absl/container/flat_hash_set.h"
-#include "absl/status/status.h"
-#include "absl/status/statusor.h"
-#include "absl/strings/string_view.h"
-#include "quiche/quic/core/io/socket.h"
-#include "quiche/quic/platform/api/quic_ip_address_family.h"
-#include "quiche/common/platform/api/quiche_logging.h"
-
-// accept4() is a Linux-specific extension that is available in glibc 2.10+.
-#if defined(__linux__) && defined(_GNU_SOURCE) && defined(__GLIBC_PREREQ)
-#if __GLIBC_PREREQ(2, 10)
-#define HAS_ACCEPT4
-#endif
-#endif
-
-namespace quic::socket_api {
-
-namespace {
-
-int ToPlatformSocketType(SocketProtocol protocol) {
-  switch (protocol) {
-    case SocketProtocol::kUdp:
-      return SOCK_DGRAM;
-    case SocketProtocol::kTcp:
-      return SOCK_STREAM;
-  }
-
-  QUICHE_NOTREACHED();
-  return -1;
-}
-
-int ToPlatformProtocol(SocketProtocol protocol) {
-  switch (protocol) {
-    case SocketProtocol::kUdp:
-      return IPPROTO_UDP;
-    case SocketProtocol::kTcp:
-      return IPPROTO_TCP;
-  }
-
-  QUICHE_NOTREACHED();
-  return -1;
-}
-
-// Wrapper of absl::ErrnoToStatus that ensures the `unavailable_error_numbers`
-// and only those numbers result in `absl::StatusCode::kUnavailable`, converting
-// any other would-be-unavailable Statuses to `absl::StatusCode::kNotFound`.
-absl::Status ToStatus(int error_number, absl::string_view method_name,
-                      absl::flat_hash_set<int> unavailable_error_numbers = {
-                          EAGAIN, EWOULDBLOCK}) {
-  QUICHE_DCHECK_NE(error_number, 0);
-  QUICHE_DCHECK_NE(error_number, EINTR);
-
-  absl::Status status = absl::ErrnoToStatus(error_number, method_name);
-  QUICHE_DCHECK(!status.ok());
-
-  if (!absl::IsUnavailable(status) &&
-      unavailable_error_numbers.contains(error_number)) {
-    status = absl::UnavailableError(status.message());
-  } else if (absl::IsUnavailable(status) &&
-             !unavailable_error_numbers.contains(error_number)) {
-    status = absl::NotFoundError(status.message());
-  }
-
-  return status;
-}
-
-absl::Status SetSocketFlags(SocketFd fd, int to_add, int to_remove) {
-  QUICHE_DCHECK_GE(fd, 0);
-  QUICHE_DCHECK(to_add || to_remove);
-  QUICHE_DCHECK(!(to_add & to_remove));
-
-  int flags;
-  do {
-    flags = ::fcntl(fd, F_GETFL);
-  } while (flags < 0 && errno == EINTR);
-  if (flags < 0) {
-    absl::Status status = ToStatus(errno, "::fcntl()");
-    QUICHE_LOG_FIRST_N(ERROR, 100)
-        << "Could not get flags for socket " << fd << " with error: " << status;
-    return status;
-  }
-
-  QUICHE_DCHECK(!(flags & to_add) || (flags & to_remove));
-
-  int fcntl_result;
-  do {
-    fcntl_result = ::fcntl(fd, F_SETFL, (flags | to_add) & ~to_remove);
-  } while (fcntl_result < 0 && errno == EINTR);
-  if (fcntl_result < 0) {
-    absl::Status status = ToStatus(errno, "::fcntl()");
-    QUICHE_LOG_FIRST_N(ERROR, 100)
-        << "Could not set flags for socket " << fd << " with error: " << status;
-    return status;
-  }
-
-  return absl::OkStatus();
-}
-
-absl::StatusOr<QuicSocketAddress> ValidateAndConvertAddress(
-    const sockaddr_storage& addr, socklen_t addr_len) {
-  if (addr.ss_family != AF_INET && addr.ss_family != AF_INET6) {
-    QUICHE_DVLOG(1) << "Socket did not have recognized address family: "
-                    << addr.ss_family;
-    return absl::UnimplementedError("Unrecognized address family.");
-  }
-
-  if ((addr.ss_family == AF_INET && addr_len != sizeof(sockaddr_in)) ||
-      (addr.ss_family == AF_INET6 && addr_len != sizeof(sockaddr_in6))) {
-    QUICHE_DVLOG(1) << "Socket did not have expected address size ("
-                    << (addr.ss_family == AF_INET ? sizeof(sockaddr_in)
-                                                  : sizeof(sockaddr_in6))
-                    << "), had: " << addr_len;
-    return absl::UnimplementedError("Unhandled address size.");
-  }
-
-  return QuicSocketAddress(addr);
-}
-
-absl::StatusOr<SocketFd> CreateSocketWithFlags(IpAddressFamily address_family,
-                                               SocketProtocol protocol,
-                                               int flags) {
-  int address_family_int = quiche::ToPlatformAddressFamily(address_family);
-
-  int type_int = ToPlatformSocketType(protocol);
-  type_int |= flags;
-
-  int protocol_int = ToPlatformProtocol(protocol);
-
-  SocketFd fd;
-  do {
-    fd = ::socket(address_family_int, type_int, protocol_int);
-  } while (fd < 0 && errno == EINTR);
-
-  if (fd >= 0) {
-    return fd;
-  } else {
-    absl::Status status = ToStatus(errno, "::socket()");
-    QUICHE_LOG_FIRST_N(ERROR, 100)
-        << "Failed to create socket with error: " << status;
-    return status;
-  }
-}
-
-absl::StatusOr<AcceptResult> AcceptInternal(SocketFd fd) {
-  QUICHE_DCHECK_GE(fd, 0);
-
-  sockaddr_storage peer_addr;
-  socklen_t peer_addr_len = sizeof(peer_addr);
-  SocketFd connection_socket;
-  do {
-    connection_socket = ::accept(
-        fd, reinterpret_cast<struct sockaddr*>(&peer_addr), &peer_addr_len);
-  } while (connection_socket < 0 && errno == EINTR);
-
-  if (connection_socket < 0) {
-    absl::Status status = ToStatus(errno, "::accept()");
-    QUICHE_DVLOG(1) << "Failed to accept connection from socket " << fd
-                    << " with error: " << status;
-    return status;
-  }
-
-  absl::StatusOr<QuicSocketAddress> peer_address =
-      ValidateAndConvertAddress(peer_addr, peer_addr_len);
-
-  if (peer_address.ok()) {
-    return AcceptResult{connection_socket, peer_address.value()};
-  } else {
-    return peer_address.status();
-  }
-}
-
-#if defined(HAS_ACCEPT4)
-absl::StatusOr<AcceptResult> AcceptWithFlags(SocketFd fd, int flags) {
-  QUICHE_DCHECK_GE(fd, 0);
-
-  sockaddr_storage peer_addr;
-  socklen_t peer_addr_len = sizeof(peer_addr);
-  SocketFd connection_socket;
-  do {
-    connection_socket =
-        ::accept4(fd, reinterpret_cast<struct sockaddr*>(&peer_addr),
-                  &peer_addr_len, flags);
-  } while (connection_socket < 0 && errno == EINTR);
-
-  if (connection_socket < 0) {
-    absl::Status status = ToStatus(errno, "::accept4()");
-    QUICHE_DVLOG(1) << "Failed to accept connection from socket " << fd
-                    << " with error: " << status;
-    return status;
-  }
-
-  absl::StatusOr<QuicSocketAddress> peer_address =
-      ValidateAndConvertAddress(peer_addr, peer_addr_len);
-
-  if (peer_address.ok()) {
-    return AcceptResult{connection_socket, peer_address.value()};
-  } else {
-    return peer_address.status();
-  }
-}
-#endif  // defined(HAS_ACCEPT4)
-
-socklen_t GetAddrlen(IpAddressFamily family) {
-  switch (family) {
-    case IpAddressFamily::IP_V4:
-      return sizeof(sockaddr_in);
-    case IpAddressFamily::IP_V6:
-      return sizeof(sockaddr_in6);
-    default:
-      QUICHE_NOTREACHED();
-      return 0;
-  }
-}
-
-absl::Status SetSockOptInt(SocketFd fd, int option, int value) {
-  QUICHE_DCHECK_GE(fd, 0);
-
-  int result;
-  do {
-    result = ::setsockopt(fd, SOL_SOCKET, option, &value, sizeof(value));
-  } while (result < 0 && errno == EINTR);
-
-  if (result >= 0) {
-    return absl::OkStatus();
-  } else {
-    absl::Status status = ToStatus(errno, "::setsockopt()");
-    QUICHE_DVLOG(1) << "Failed to set socket " << fd << " option " << option
-                    << " to " << value << " with error: " << status;
-    return status;
-  }
-}
-
-}  // namespace
-
-absl::StatusOr<SocketFd> CreateSocket(IpAddressFamily address_family,
-                                      SocketProtocol protocol, bool blocking) {
-  int flags = 0;
-#if defined(__linux__) && defined(SOCK_NONBLOCK)
-  if (!blocking) {
-    flags = SOCK_NONBLOCK;
-  }
-#endif
-
-  absl::StatusOr<SocketFd> socket =
-      CreateSocketWithFlags(address_family, protocol, flags);
-  if (!socket.ok() || blocking) {
-    return socket;
-  }
-
-#if !defined(__linux__) || !defined(SOCK_NONBLOCK)
-  // If non-blocking could not be set directly on socket creation, need to do
-  // it now.
-  absl::Status set_non_blocking_result =
-      SetSocketBlocking(socket.value(), /*blocking=*/false);
-  if (!set_non_blocking_result.ok()) {
-    QUICHE_LOG_FIRST_N(ERROR, 100) << "Failed to set socket " << socket.value()
-                                   << " as non-blocking on creation.";
-    if (!Close(socket.value()).ok()) {
-      QUICHE_LOG_FIRST_N(ERROR, 100)
-          << "Failed to close socket " << socket.value()
-          << " after set-non-blocking error on creation.";
-    }
-    return set_non_blocking_result;
-  }
-#endif
-
-  return socket;
-}
-
-absl::Status SetSocketBlocking(SocketFd fd, bool blocking) {
-  if (blocking) {
-    return SetSocketFlags(fd, /*to_add=*/0, /*to_remove=*/O_NONBLOCK);
-  } else {
-    return SetSocketFlags(fd, /*to_add=*/O_NONBLOCK, /*to_remove=*/0);
-  }
-}
-
-absl::Status SetReceiveBufferSize(SocketFd fd, QuicByteCount size) {
-  QUICHE_DCHECK_GE(fd, 0);
-  QUICHE_DCHECK_LE(size, QuicByteCount{INT_MAX});
-
-  return SetSockOptInt(fd, SO_RCVBUF, static_cast<int>(size));
-}
-
-absl::Status SetSendBufferSize(SocketFd fd, QuicByteCount size) {
-  QUICHE_DCHECK_GE(fd, 0);
-  QUICHE_DCHECK_LE(size, QuicByteCount{INT_MAX});
-
-  return SetSockOptInt(fd, SO_SNDBUF, static_cast<int>(size));
-}
-
-absl::Status Connect(SocketFd fd, const QuicSocketAddress& peer_address) {
-  QUICHE_DCHECK_GE(fd, 0);
-  QUICHE_DCHECK(peer_address.IsInitialized());
-
-  sockaddr_storage addr = peer_address.generic_address();
-  socklen_t addrlen = GetAddrlen(peer_address.host().address_family());
-
-  int connect_result;
-  do {
-    connect_result = ::connect(fd, reinterpret_cast<sockaddr*>(&addr), addrlen);
-  } while (connect_result < 0 && errno == EINTR);
-
-  if (connect_result >= 0) {
-    return absl::OkStatus();
-  } else {
-    // For ::connect(), only `EINPROGRESS` indicates unavailable.
-    absl::Status status =
-        ToStatus(errno, "::connect()", /*unavailable_error_numbers=*/
-                 {EINPROGRESS});
-    QUICHE_DVLOG(1) << "Failed to connect socket " << fd
-                    << " to address: " << peer_address.ToString()
-                    << " with error: " << status;
-    return status;
-  }
-}
-
-absl::Status GetSocketError(SocketFd fd) {
-  QUICHE_DCHECK_GE(fd, 0);
-
-  int socket_error = 0;
-  socklen_t len = sizeof(socket_error);
-  int sockopt_result;
-  do {
-    sockopt_result =
-        ::getsockopt(fd, SOL_SOCKET, SO_ERROR, &socket_error, &len);
-  } while (sockopt_result < 0 && errno == EINTR);
-
-  if (sockopt_result >= 0) {
-    if (socket_error == 0) {
-      return absl::OkStatus();
-    } else {
-      return ToStatus(socket_error, "SO_ERROR");
-    }
-  } else {
-    absl::Status status = ToStatus(errno, "::getsockopt()");
-    QUICHE_LOG_FIRST_N(ERROR, 100)
-        << "Failed to get socket error information from socket " << fd
-        << " with error: " << status;
-    return status;
-  }
-}
-
-absl::Status Bind(SocketFd fd, const QuicSocketAddress& address) {
-  QUICHE_DCHECK_GE(fd, 0);
-  QUICHE_DCHECK(address.IsInitialized());
-
-  sockaddr_storage addr = address.generic_address();
-  socklen_t addr_len = GetAddrlen(address.host().address_family());
-
-  int result;
-  do {
-    result = ::bind(fd, reinterpret_cast<sockaddr*>(&addr), addr_len);
-  } while (result < 0 && errno == EINTR);
-
-  if (result >= 0) {
-    return absl::OkStatus();
-  } else {
-    absl::Status status = ToStatus(errno, "::bind()");
-    QUICHE_DVLOG(1) << "Failed to bind socket " << fd
-                    << " to address: " << address.ToString()
-                    << " with error: " << status;
-    return status;
-  }
-}
-
-absl::StatusOr<QuicSocketAddress> GetSocketAddress(SocketFd fd) {
-  QUICHE_DCHECK_GE(fd, 0);
-
-  sockaddr_storage addr;
-  socklen_t addr_len = sizeof(addr);
-
-  int result;
-  do {
-    result = ::getsockname(fd, reinterpret_cast<sockaddr*>(&addr), &addr_len);
-  } while (result < 0 && errno == EINTR);
-
-  if (result >= 0) {
-    return ValidateAndConvertAddress(addr, addr_len);
-  } else {
-    absl::Status status = ToStatus(errno, "::getsockname()");
-    QUICHE_DVLOG(1) << "Failed to get socket " << fd
-                    << " name with error: " << status;
-    return status;
-  }
-}
-
-absl::Status Listen(SocketFd fd, int backlog) {
-  QUICHE_DCHECK_GE(fd, 0);
-  QUICHE_DCHECK_GT(backlog, 0);
-
-  int result;
-  do {
-    result = ::listen(fd, backlog);
-  } while (result < 0 && errno == EINTR);
-
-  if (result >= 0) {
-    return absl::OkStatus();
-  } else {
-    absl::Status status = ToStatus(errno, "::listen()");
-    QUICHE_DVLOG(1) << "Failed to mark socket: " << fd
-                    << " to listen with error :" << status;
-    return status;
-  }
-}
-
-absl::StatusOr<AcceptResult> Accept(SocketFd fd, bool blocking) {
-  QUICHE_DCHECK_GE(fd, 0);
-
-#if defined(HAS_ACCEPT4)
-  if (!blocking) {
-    return AcceptWithFlags(fd, SOCK_NONBLOCK);
-  }
-#endif
-
-  absl::StatusOr<AcceptResult> accept_result = AcceptInternal(fd);
-  if (!accept_result.ok() || blocking) {
-    return accept_result;
-  }
-
-#if !defined(__linux__) || !defined(SOCK_NONBLOCK)
-  // If non-blocking could not be set directly on socket acceptance, need to
-  // do it now.
-  absl::Status set_non_blocking_result =
-      SetSocketBlocking(accept_result.value().fd, /*blocking=*/false);
-  if (!set_non_blocking_result.ok()) {
-    QUICHE_LOG_FIRST_N(ERROR, 100)
-        << "Failed to set socket " << fd << " as non-blocking on acceptance.";
-    if (!Close(accept_result.value().fd).ok()) {
-      QUICHE_LOG_FIRST_N(ERROR, 100)
-          << "Failed to close socket " << accept_result.value().fd
-          << " after error setting non-blocking on acceptance.";
-    }
-    return set_non_blocking_result;
-  }
-#endif
-
-  return accept_result;
-}
-
-absl::StatusOr<absl::Span<char>> Receive(SocketFd fd, absl::Span<char> buffer,
-                                         bool peek) {
-  QUICHE_DCHECK_GE(fd, 0);
-  QUICHE_DCHECK(!buffer.empty());
-
-  ssize_t num_read;
-  do {
-    num_read =
-        ::recv(fd, buffer.data(), buffer.size(), /*flags=*/peek ? MSG_PEEK : 0);
-  } while (num_read < 0 && errno == EINTR);
-
-  if (num_read > 0 && static_cast<size_t>(num_read) > buffer.size()) {
-    QUICHE_LOG_FIRST_N(WARNING, 100)
-        << "Received more bytes (" << num_read << ") from socket " << fd
-        << " than buffer size (" << buffer.size() << ").";
-    return absl::OutOfRangeError(
-        "::recv(): Received more bytes than buffer size.");
-  } else if (num_read >= 0) {
-    return buffer.subspan(0, num_read);
-  } else {
-    absl::Status status = ToStatus(errno, "::recv()");
-    QUICHE_DVLOG(1) << "Failed to receive from socket: " << fd
-                    << " with error: " << status;
-    return status;
-  }
-}
-
-absl::StatusOr<absl::string_view> Send(SocketFd fd, absl::string_view buffer) {
-  QUICHE_DCHECK_GE(fd, 0);
-  QUICHE_DCHECK(!buffer.empty());
-
-  ssize_t num_sent;
-  do {
-    num_sent = ::send(fd, buffer.data(), buffer.size(), /*flags=*/0);
-  } while (num_sent < 0 && errno == EINTR);
-
-  if (num_sent > 0 && static_cast<size_t>(num_sent) > buffer.size()) {
-    QUICHE_LOG_FIRST_N(WARNING, 100)
-        << "Sent more bytes (" << num_sent << ") to socket " << fd
-        << " than buffer size (" << buffer.size() << ").";
-    return absl::OutOfRangeError("::send(): Sent more bytes than buffer size.");
-  } else if (num_sent >= 0) {
-    return buffer.substr(num_sent);
-  } else {
-    absl::Status status = ToStatus(errno, "::send()");
-    QUICHE_DVLOG(1) << "Failed to send to socket: " << fd
-                    << " with error: " << status;
-    return status;
-  }
-}
-
-absl::Status Close(SocketFd fd) {
-  QUICHE_DCHECK_GE(fd, 0);
-
-  int close_result = ::close(fd);
-
-  if (close_result >= 0) {
-    return absl::OkStatus();
-  } else if (errno == EINTR) {
-    // Ignore EINTR on close because the socket is left in an undefined state
-    // and can't be acted on again.
-    QUICHE_DVLOG(1) << "Socket " << fd << " close unspecified due to EINTR.";
-    return absl::OkStatus();
-  } else {
-    absl::Status status = ToStatus(errno, "::close()");
-    QUICHE_DVLOG(1) << "Failed to close socket: " << fd
-                    << " with error: " << status;
-    return status;
-  }
-}
-
-}  // namespace quic::socket_api
diff --git a/quiche/quic/core/io/socket_posix.inc b/quiche/quic/core/io/socket_posix.inc
new file mode 100644
index 0000000..c646784
--- /dev/null
+++ b/quiche/quic/core/io/socket_posix.inc
@@ -0,0 +1,262 @@
+// Copyright 2022 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 <fcntl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <cerrno>
+#include <climits>
+
+#include "absl/base/attributes.h"
+#include "absl/container/flat_hash_set.h"
+#include "absl/status/status.h"
+#include "absl/status/statusor.h"
+#include "absl/strings/string_view.h"
+#include "quiche/quic/core/io/socket.h"
+#include "quiche/quic/core/io/socket_internal.h"
+#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_logging.h"
+
+// accept4() is a Linux-specific extension that is available in glibc 2.10+.
+#if defined(__linux__) && defined(_GNU_SOURCE) && defined(__GLIBC_PREREQ)
+#if __GLIBC_PREREQ(2, 10)
+#define HAS_ACCEPT4
+#endif
+#endif
+
+namespace quic::socket_api {
+
+namespace {
+
+using PlatformSocklen = socklen_t;
+using PlatformSsizeT = ssize_t;
+
+template <typename Result, typename... Args>
+Result SyscallWrapper(Result (*syscall)(Args...), Args... args) {
+  while (true) {
+    auto result = syscall(args...);
+    if (result < 0 && errno == EINTR) {
+      continue;
+    }
+    return result;
+  }
+}
+
+int SyscallGetsockopt(int sockfd, int level, int optname, void* optval,
+                      socklen_t* optlen) {
+  return SyscallWrapper(&::getsockopt, sockfd, level, optname, optval, optlen);
+}
+int SyscallSetsockopt(int sockfd, int level, int optname, const void* optval,
+                      socklen_t optlen) {
+  return SyscallWrapper(&::setsockopt, sockfd, level, optname, optval, optlen);
+}
+int SyscallGetsockname(int sockfd, sockaddr* addr, socklen_t* addrlen) {
+  return SyscallWrapper(&::getsockname, sockfd, addr, addrlen);
+}
+int SyscallAccept(int sockfd, sockaddr* addr, socklen_t* addrlen) {
+  return SyscallWrapper(&::accept, sockfd, addr, addrlen);
+}
+int SyscallConnect(int sockfd, const sockaddr* addr, socklen_t addrlen) {
+  return SyscallWrapper(&::connect, sockfd, addr, addrlen);
+}
+int SyscallBind(int sockfd, const sockaddr* addr, socklen_t addrlen) {
+  return SyscallWrapper(&::bind, sockfd, addr, addrlen);
+}
+int SyscallListen(int sockfd, int backlog) {
+  return SyscallWrapper(&::listen, sockfd, backlog);
+}
+ssize_t SyscallRecv(int sockfd, void* buf, size_t len, int flags) {
+  return SyscallWrapper(&::recv, sockfd, buf, len, flags);
+}
+ssize_t SyscallSend(int sockfd, const void* buf, size_t len, int flags) {
+  return SyscallWrapper(&::send, sockfd, buf, len, flags);
+}
+
+// Wrapper of absl::ErrnoToStatus that ensures the `unavailable_error_numbers`
+// and only those numbers result in `absl::StatusCode::kUnavailable`, converting
+// any other would-be-unavailable Statuses to `absl::StatusCode::kNotFound`.
+absl::Status ToStatus(int error_number, absl::string_view method_name,
+                      absl::flat_hash_set<int> unavailable_error_numbers = {
+                          EAGAIN, EWOULDBLOCK}) {
+  QUICHE_DCHECK_NE(error_number, 0);
+  QUICHE_DCHECK_NE(error_number, EINTR);
+
+  absl::Status status = absl::ErrnoToStatus(error_number, method_name);
+  QUICHE_DCHECK(!status.ok());
+
+  if (!absl::IsUnavailable(status) &&
+      unavailable_error_numbers.contains(error_number)) {
+    status = absl::UnavailableError(status.message());
+  } else if (absl::IsUnavailable(status) &&
+             !unavailable_error_numbers.contains(error_number)) {
+    status = absl::NotFoundError(status.message());
+  }
+
+  return status;
+}
+
+absl::Status LastSocketOperationError(
+    absl::string_view method_name,
+    absl::flat_hash_set<int> unavailable_error_numbers = {EAGAIN,
+                                                          EWOULDBLOCK}) {
+  return ToStatus(errno, method_name, unavailable_error_numbers);
+}
+
+absl::Status SetSocketFlags(SocketFd fd, int to_add, int to_remove) {
+  QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
+  QUICHE_DCHECK(to_add || to_remove);
+  QUICHE_DCHECK(!(to_add & to_remove));
+
+  int flags;
+  do {
+    flags = ::fcntl(fd, F_GETFL);
+  } while (flags < 0 && errno == EINTR);
+  if (flags < 0) {
+    absl::Status status = LastSocketOperationError("::fcntl()");
+    QUICHE_LOG_FIRST_N(ERROR, 100)
+        << "Could not get flags for socket " << fd << " with error: " << status;
+    return status;
+  }
+
+  QUICHE_DCHECK(!(flags & to_add) || (flags & to_remove));
+
+  int fcntl_result;
+  do {
+    fcntl_result = ::fcntl(fd, F_SETFL, (flags | to_add) & ~to_remove);
+  } while (fcntl_result < 0 && errno == EINTR);
+  if (fcntl_result < 0) {
+    absl::Status status = LastSocketOperationError("::fcntl()");
+    QUICHE_LOG_FIRST_N(ERROR, 100)
+        << "Could not set flags for socket " << fd << " with error: " << status;
+    return status;
+  }
+
+  return absl::OkStatus();
+}
+
+absl::StatusOr<SocketFd> CreateSocketWithFlags(IpAddressFamily address_family,
+                                               SocketProtocol protocol,
+                                               int flags) {
+  int address_family_int = quiche::ToPlatformAddressFamily(address_family);
+
+  int type_int = ToPlatformSocketType(protocol);
+  type_int |= flags;
+
+  int protocol_int = ToPlatformProtocol(protocol);
+
+  SocketFd fd;
+  do {
+    fd = SyscallWrapper(&::socket, address_family_int, type_int, protocol_int);
+  } while (fd < 0 && errno == EINTR);
+
+  if (fd >= 0) {
+    return fd;
+  } else {
+    absl::Status status = LastSocketOperationError("::socket()");
+    QUICHE_LOG_FIRST_N(ERROR, 100)
+        << "Failed to create socket with error: " << status;
+    return status;
+  }
+}
+
+#if defined(HAS_ACCEPT4)
+absl::StatusOr<AcceptResult> AcceptWithFlags(SocketFd fd, int flags) {
+  QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
+
+  sockaddr_storage peer_addr;
+  socklen_t peer_addr_len = sizeof(peer_addr);
+  SocketFd connection_socket;
+  do {
+    connection_socket = SyscallWrapper(
+        &::accept4, fd, reinterpret_cast<struct sockaddr*>(&peer_addr),
+        &peer_addr_len, flags);
+  } while (connection_socket < 0 && errno == EINTR);
+
+  if (connection_socket < 0) {
+    absl::Status status = LastSocketOperationError("::accept4()");
+    QUICHE_DVLOG(1) << "Failed to accept connection from socket " << fd
+                    << " with error: " << status;
+    return status;
+  }
+
+  absl::StatusOr<QuicSocketAddress> peer_address =
+      ValidateAndConvertAddress(peer_addr, peer_addr_len);
+
+  if (peer_address.ok()) {
+    return AcceptResult{connection_socket, peer_address.value()};
+  } else {
+    return peer_address.status();
+  }
+}
+#endif  // defined(HAS_ACCEPT4)
+
+}  // namespace
+
+absl::Status SetSocketBlocking(SocketFd fd, bool blocking) {
+  if (blocking) {
+    return SetSocketFlags(fd, /*to_add=*/0, /*to_remove=*/O_NONBLOCK);
+  } else {
+    return SetSocketFlags(fd, /*to_add=*/O_NONBLOCK, /*to_remove=*/0);
+  }
+}
+
+absl::StatusOr<SocketFd> CreateSocket(IpAddressFamily address_family,
+                                      SocketProtocol protocol, bool blocking) {
+  int flags = 0;
+#if defined(__linux__) && defined(SOCK_NONBLOCK)
+  if (!blocking) {
+    flags = SOCK_NONBLOCK;
+  }
+#endif
+
+  absl::StatusOr<SocketFd> socket =
+      CreateSocketWithFlags(address_family, protocol, flags);
+  if (!socket.ok() || blocking) {
+    return socket;
+  }
+
+#if !defined(__linux__) || !defined(SOCK_NONBLOCK)
+  // If non-blocking could not be set directly on socket creation, need to do
+  // it now.
+  absl::Status set_non_blocking_result =
+      SetSocketBlocking(socket.value(), /*blocking=*/false);
+  if (!set_non_blocking_result.ok()) {
+    QUICHE_LOG_FIRST_N(ERROR, 100) << "Failed to set socket " << socket.value()
+                                   << " as non-blocking on creation.";
+    if (!Close(socket.value()).ok()) {
+      QUICHE_LOG_FIRST_N(ERROR, 100)
+          << "Failed to close socket " << socket.value()
+          << " after set-non-blocking error on creation.";
+    }
+    return set_non_blocking_result;
+  }
+#endif
+
+  return socket;
+}
+
+absl::Status Close(SocketFd fd) {
+  QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
+
+  int close_result = ::close(fd);
+
+  if (close_result >= 0) {
+    return absl::OkStatus();
+  } else if (errno == EINTR) {
+    // Ignore EINTR on close because the socket is left in an undefined state
+    // and can't be acted on again.
+    QUICHE_DVLOG(1) << "Socket " << fd << " close unspecified due to EINTR.";
+    return absl::OkStatus();
+  } else {
+    absl::Status status = LastSocketOperationError("::close()");
+    QUICHE_DVLOG(1) << "Failed to close socket: " << fd
+                    << " with error: " << status;
+    return status;
+  }
+}
+
+}  // namespace quic::socket_api
diff --git a/quiche/quic/core/io/socket_test.cc b/quiche/quic/core/io/socket_test.cc
index 9afe0f6..da1d24a 100644
--- a/quiche/quic/core/io/socket_test.cc
+++ b/quiche/quic/core/io/socket_test.cc
@@ -16,11 +16,13 @@
 #include "quiche/common/platform/api/quiche_logging.h"
 #include "quiche/common/platform/api/quiche_test.h"
 #include "quiche/common/platform/api/quiche_test_loopback.h"
+#include "quiche/common/test_tools/quiche_test_utils.h"
 
 namespace quic {
 namespace {
 
 using quiche::test::QuicheTest;
+using quiche::test::StatusIs;
 using testing::Lt;
 using testing::SizeIs;
 
@@ -42,47 +44,46 @@
   absl::StatusOr<SocketFd> created_socket = socket_api::CreateSocket(
       localhost_address.address_family(), socket_api::SocketProtocol::kUdp);
 
-  EXPECT_TRUE(created_socket.ok());
+  QUICHE_EXPECT_OK(created_socket.status());
 
-  EXPECT_TRUE(socket_api::Close(created_socket.value()).ok());
+  QUICHE_EXPECT_OK(socket_api::Close(created_socket.value()));
 }
 
 TEST(SocketTest, SetSocketBlocking) {
   SocketFd socket = CreateTestSocket(socket_api::SocketProtocol::kUdp,
                                      /*blocking=*/true);
 
-  EXPECT_TRUE(socket_api::SetSocketBlocking(socket, /*blocking=*/false).ok());
+  QUICHE_EXPECT_OK(socket_api::SetSocketBlocking(socket, /*blocking=*/false));
 
-  EXPECT_TRUE(socket_api::Close(socket).ok());
+  QUICHE_EXPECT_OK(socket_api::Close(socket));
 }
 
 TEST(SocketTest, SetReceiveBufferSize) {
   SocketFd socket = CreateTestSocket(socket_api::SocketProtocol::kUdp,
                                      /*blocking=*/true);
 
-  EXPECT_TRUE(socket_api::SetReceiveBufferSize(socket, /*size=*/100).ok());
+  QUICHE_EXPECT_OK(socket_api::SetReceiveBufferSize(socket, /*size=*/100));
 
-  EXPECT_TRUE(socket_api::Close(socket).ok());
+  QUICHE_EXPECT_OK(socket_api::Close(socket));
 }
 
 TEST(SocketTest, SetSendBufferSize) {
   SocketFd socket = CreateTestSocket(socket_api::SocketProtocol::kUdp,
                                      /*blocking=*/true);
 
-  EXPECT_TRUE(socket_api::SetSendBufferSize(socket, /*size=*/100).ok());
+  QUICHE_EXPECT_OK(socket_api::SetSendBufferSize(socket, /*size=*/100));
 
-  EXPECT_TRUE(socket_api::Close(socket).ok());
+  QUICHE_EXPECT_OK(socket_api::Close(socket));
 }
 
 TEST(SocketTest, Connect) {
   SocketFd socket = CreateTestSocket(socket_api::SocketProtocol::kUdp);
 
   // UDP, so "connecting" should succeed without any listening sockets.
-  EXPECT_TRUE(socket_api::Connect(
-                  socket, QuicSocketAddress(quiche::TestLoopback(), /*port=*/0))
-                  .ok());
+  QUICHE_EXPECT_OK(socket_api::Connect(
+      socket, QuicSocketAddress(quiche::TestLoopback(), /*port=*/0)));
 
-  EXPECT_TRUE(socket_api::Close(socket).ok());
+  QUICHE_EXPECT_OK(socket_api::Close(socket));
 }
 
 TEST(SocketTest, GetSocketError) {
@@ -90,62 +91,57 @@
                                      /*blocking=*/true);
 
   absl::Status error = socket_api::GetSocketError(socket);
-  EXPECT_TRUE(error.ok());
+  QUICHE_EXPECT_OK(error);
 
-  EXPECT_TRUE(socket_api::Close(socket).ok());
+  QUICHE_EXPECT_OK(socket_api::Close(socket));
 }
 
 TEST(SocketTest, Bind) {
   SocketFd socket = CreateTestSocket(socket_api::SocketProtocol::kUdp);
 
-  EXPECT_TRUE(socket_api::Bind(
-                  socket, QuicSocketAddress(quiche::TestLoopback(), /*port=*/0))
-                  .ok());
+  QUICHE_EXPECT_OK(socket_api::Bind(
+      socket, QuicSocketAddress(quiche::TestLoopback(), /*port=*/0)));
 
-  EXPECT_TRUE(socket_api::Close(socket).ok());
+  QUICHE_EXPECT_OK(socket_api::Close(socket));
 }
 
 TEST(SocketTest, GetSocketAddress) {
   SocketFd socket = CreateTestSocket(socket_api::SocketProtocol::kUdp);
-  ASSERT_TRUE(socket_api::Bind(
-                  socket, QuicSocketAddress(quiche::TestLoopback(), /*port=*/0))
-                  .ok());
+  QUICHE_ASSERT_OK(socket_api::Bind(
+      socket, QuicSocketAddress(quiche::TestLoopback(), /*port=*/0)));
 
   absl::StatusOr<QuicSocketAddress> address =
       socket_api::GetSocketAddress(socket);
-  EXPECT_TRUE(address.ok());
+  QUICHE_EXPECT_OK(address);
   EXPECT_TRUE(address.value().IsInitialized());
   EXPECT_EQ(address.value().host(), quiche::TestLoopback());
 
-  EXPECT_TRUE(socket_api::Close(socket).ok());
+  QUICHE_EXPECT_OK(socket_api::Close(socket));
 }
 
 TEST(SocketTest, Listen) {
   SocketFd socket = CreateTestSocket(socket_api::SocketProtocol::kTcp);
-  ASSERT_TRUE(socket_api::Bind(
-                  socket, QuicSocketAddress(quiche::TestLoopback(), /*port=*/0))
-                  .ok());
+  QUICHE_ASSERT_OK(socket_api::Bind(
+      socket, QuicSocketAddress(quiche::TestLoopback(), /*port=*/0)));
 
-  EXPECT_TRUE(socket_api::Listen(socket, /*backlog=*/5).ok());
+  QUICHE_EXPECT_OK(socket_api::Listen(socket, /*backlog=*/5));
 
-  EXPECT_TRUE(socket_api::Close(socket).ok());
+  QUICHE_EXPECT_OK(socket_api::Close(socket));
 }
 
 TEST(SocketTest, Accept) {
   // Need a non-blocking socket to avoid waiting when no connection comes.
   SocketFd socket =
       CreateTestSocket(socket_api::SocketProtocol::kTcp, /*blocking=*/false);
-  ASSERT_TRUE(socket_api::Bind(
-                  socket, QuicSocketAddress(quiche::TestLoopback(), /*port=*/0))
-                  .ok());
-  ASSERT_TRUE(socket_api::Listen(socket, /*backlog=*/5).ok());
+  QUICHE_ASSERT_OK(socket_api::Bind(
+      socket, QuicSocketAddress(quiche::TestLoopback(), /*port=*/0)));
+  QUICHE_ASSERT_OK(socket_api::Listen(socket, /*backlog=*/5));
 
   // Nothing set up to connect, so expect kUnavailable.
   absl::StatusOr<socket_api::AcceptResult> result = socket_api::Accept(socket);
-  ASSERT_FALSE(result.ok());
-  EXPECT_TRUE(absl::IsUnavailable(result.status()));
+  EXPECT_THAT(result, StatusIs(absl::StatusCode::kUnavailable));
 
-  EXPECT_TRUE(socket_api::Close(socket).ok());
+  QUICHE_EXPECT_OK(socket_api::Close(socket));
 }
 
 TEST(SocketTest, Receive) {
@@ -153,13 +149,16 @@
   SocketFd socket = CreateTestSocket(socket_api::SocketProtocol::kUdp,
                                      /*blocking=*/false);
 
+  // On Windows, recv() fails on a socket that is connectionless and not bound.
+  QUICHE_ASSERT_OK(socket_api::Bind(
+      socket, QuicSocketAddress(quiche::TestLoopback(), /*port=*/0)));
+
   std::string buffer(100, 0);
   absl::StatusOr<absl::Span<char>> result =
       socket_api::Receive(socket, absl::MakeSpan(buffer));
-  ASSERT_FALSE(result.ok());
-  EXPECT_TRUE(absl::IsUnavailable(result.status()));
+  EXPECT_THAT(result, StatusIs(absl::StatusCode::kUnavailable));
 
-  EXPECT_TRUE(socket_api::Close(socket).ok());
+  QUICHE_EXPECT_OK(socket_api::Close(socket));
 }
 
 TEST(SocketTest, Peek) {
@@ -167,30 +166,32 @@
   SocketFd socket = CreateTestSocket(socket_api::SocketProtocol::kUdp,
                                      /*blocking=*/false);
 
+  // On Windows, recv() fails on a socket that is connectionless and not bound.
+  QUICHE_ASSERT_OK(socket_api::Bind(
+      socket, QuicSocketAddress(quiche::TestLoopback(), /*port=*/0)));
+
   std::string buffer(100, 0);
   absl::StatusOr<absl::Span<char>> result =
       socket_api::Receive(socket, absl::MakeSpan(buffer), /*peek=*/true);
-  ASSERT_FALSE(result.ok());
-  EXPECT_TRUE(absl::IsUnavailable(result.status()));
+  EXPECT_THAT(result, StatusIs(absl::StatusCode::kUnavailable));
 
-  EXPECT_TRUE(socket_api::Close(socket).ok());
+  QUICHE_EXPECT_OK(socket_api::Close(socket));
 }
 
 TEST(SocketTest, Send) {
   SocketFd socket = CreateTestSocket(socket_api::SocketProtocol::kUdp);
   // UDP, so "connecting" should succeed without any listening sockets.
-  ASSERT_TRUE(socket_api::Connect(
-                  socket, QuicSocketAddress(quiche::TestLoopback(), /*port=*/0))
-                  .ok());
+  QUICHE_ASSERT_OK(socket_api::Connect(
+      socket, QuicSocketAddress(quiche::TestLoopback(), /*port=*/0)));
 
   char buffer[] = {12, 34, 56, 78};
   // Expect at least some data to be sent successfully.
   absl::StatusOr<absl::string_view> result =
       socket_api::Send(socket, absl::string_view(buffer, sizeof(buffer)));
-  ASSERT_TRUE(result.ok());
+  QUICHE_ASSERT_OK(result.status());
   EXPECT_THAT(result.value(), SizeIs(Lt(4)));
 
-  EXPECT_TRUE(socket_api::Close(socket).ok());
+  QUICHE_EXPECT_OK(socket_api::Close(socket));
 }
 
 }  // namespace
diff --git a/quiche/quic/core/io/socket_win.inc b/quiche/quic/core/io/socket_win.inc
new file mode 100644
index 0000000..5fce989
--- /dev/null
+++ b/quiche/quic/core/io/socket_win.inc
@@ -0,0 +1,164 @@
+// Copyright 2023 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 <winsock2.h>
+
+#include "absl/status/status.h"
+#include "absl/strings/string_view.h"
+#include "quiche/quic/core/io/socket.h"
+#include "quiche/quic/core/io/socket_internal.h"
+#include "quiche/common/quiche_status_utils.h"
+
+namespace quic::socket_api {
+
+namespace {
+
+using PlatformSocklen = int;
+using PlatformSsizeT = int;
+
+int SyscallGetsockopt(int sockfd, int level, int optname, void* optval,
+                      int* optlen) {
+  return ::getsockopt(sockfd, level, optname, reinterpret_cast<char*>(optval),
+                      optlen);
+}
+int SyscallSetsockopt(int sockfd, int level, int optname, const void* optval,
+                      int optlen) {
+  return ::setsockopt(sockfd, level, optname,
+                      reinterpret_cast<const char*>(optval), optlen);
+}
+int SyscallGetsockname(int sockfd, sockaddr* addr, int* addrlen) {
+  return ::getsockname(sockfd, addr, addrlen);
+}
+int SyscallAccept(int sockfd, sockaddr* addr, int* addrlen) {
+  return ::accept(sockfd, addr, addrlen);
+}
+int SyscallConnect(int sockfd, const sockaddr* addr, socklen_t addrlen) {
+  return ::connect(sockfd, addr, addrlen);
+}
+int SyscallBind(int sockfd, const sockaddr* addr, socklen_t addrlen) {
+  return ::bind(sockfd, addr, addrlen);
+}
+int SyscallListen(int sockfd, int backlog) { return ::listen(sockfd, backlog); }
+int SyscallRecv(int sockfd, void* buf, size_t len, int flags) {
+  return ::recv(sockfd, reinterpret_cast<char*>(buf), len, flags);
+}
+int SyscallSend(int sockfd, const void* buf, size_t len, int flags) {
+  return ::send(sockfd, reinterpret_cast<const char*>(buf), len, flags);
+}
+
+absl::StatusCode RemapErrorCode(int code) {
+  switch (code) {
+    // Note that kUnavailable is the special status that always has to map to
+    // EWOULDBLOCK (see the API documentation).
+    case WSAEWOULDBLOCK:
+      return absl::StatusCode::kUnavailable;
+
+    case WSANOTINITIALISED:
+    case WSAENETDOWN:
+    case WSAEAFNOSUPPORT:
+    case WSAEPROTONOSUPPORT:
+    case WSAESHUTDOWN:
+      return absl::StatusCode::kFailedPrecondition;
+
+    case WSAEFAULT:
+    case WSAEINVAL:
+    case WSAEPROTOTYPE:
+    case WSAESOCKTNOSUPPORT:
+    case WSAEADDRNOTAVAIL:
+    case WSAENOTSOCK:
+    case WSAEOPNOTSUPP:
+      return absl::StatusCode::kInvalidArgument;
+
+    case WSAEADDRINUSE:
+    case WSAEISCONN:
+      return absl::StatusCode::kAlreadyExists;
+
+    case WSAEMFILE:
+    case WSAENOBUFS:
+      return absl::StatusCode::kResourceExhausted;
+
+    case WSAECONNREFUSED:
+    case WSAENETUNREACH:
+    case WSAEHOSTUNREACH:
+      return absl::StatusCode::kNotFound;
+
+    case WSAETIMEDOUT:
+      return absl::StatusCode::kDeadlineExceeded;
+
+    case WSAEACCES:
+      return absl::StatusCode::kPermissionDenied;
+
+    case WSAENETRESET:
+    case WSAECONNABORTED:
+    case WSAECONNRESET:
+      return absl::StatusCode::kAborted;
+
+    case WSAEMSGSIZE:
+      return absl::StatusCode::kOutOfRange;
+
+    default:
+      return absl::StatusCode::kInternal;
+  }
+}
+
+std::string SystemErrorCodeToString(int code) {
+  LPSTR message = nullptr;
+  FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+                 nullptr, code, 0, reinterpret_cast<LPSTR>(&message), 0,
+                 nullptr);
+  std::string owned_message(absl::StripAsciiWhitespace(message));
+  LocalFree(message);
+  return owned_message;
+}
+
+absl::Status ToStatus(int error_number, absl::string_view method_name,
+                      absl::flat_hash_set<int> unavailable_error_numbers = {}) {
+  (void)unavailable_error_numbers;  // Suppress "unused variable" error.
+  return absl::Status(
+      RemapErrorCode(error_number),
+      absl::StrCat(method_name, ": Winsock error ", error_number, ": ",
+                   SystemErrorCodeToString(error_number)));
+}
+
+absl::Status LastSocketOperationError(
+    absl::string_view method_name,
+    absl::flat_hash_set<int> unavailable_error_numbers = {}) {
+  return ToStatus(WSAGetLastError(), method_name, unavailable_error_numbers);
+}
+
+absl::Status StatusForLastCall(int result, absl::string_view method_name) {
+  return result == 0 ? absl::OkStatus() : LastSocketOperationError(method_name);
+}
+
+}  // namespace
+
+absl::StatusOr<SocketFd> CreateSocket(IpAddressFamily address_family,
+                                      SocketProtocol protocol, bool blocking) {
+  int family_int = ToPlatformAddressFamily(address_family);
+  int type_int = ToPlatformSocketType(protocol);
+  int protocol_int = ToPlatformProtocol(protocol);
+  SocketFd result = ::WSASocket(family_int, type_int, protocol_int, nullptr, 0,
+                                WSA_FLAG_OVERLAPPED);
+  if (result == INVALID_SOCKET) {
+    return LastSocketOperationError("socket()");
+  }
+  if (!blocking) {
+    // Windows sockets are blocking by default.
+    QUICHE_RETURN_IF_ERROR(SetSocketBlocking(result, blocking));
+  }
+  return result;
+}
+
+absl::Status SetSocketBlocking(SocketFd fd, bool blocking) {
+  u_long mode = !blocking;
+  int result = ::ioctlsocket(fd, FIONBIO, &mode);
+  return StatusForLastCall(result, "SetSocketBlocking()");
+}
+
+absl::Status Close(SocketFd fd) {
+  int result = ::closesocket(fd);
+  return StatusForLastCall(result, "close()");
+}
+
+}  // namespace quic::socket_api