Support enough of Windows to make EndToEndTest.SimpleRequestResponse pass. PiperOrigin-RevId: 529755002
diff --git a/build/source_list.bzl b/build/source_list.bzl index fd20c48..de04f82 100644 --- a/build/source_list.bzl +++ b/build/source_list.bzl
@@ -665,6 +665,7 @@ "quic/core/quic_trace_visitor.cc", "quic/core/quic_transmission_info.cc", "quic/core/quic_types.cc", + "quic/core/quic_udp_socket.cc", "quic/core/quic_unacked_packet_map.cc", "quic/core/quic_utils.cc", "quic/core/quic_version_manager.cc", @@ -991,7 +992,6 @@ "quic/core/quic_default_packet_writer.cc", "quic/core/quic_packet_reader.cc", "quic/core/quic_syscall_wrapper.cc", - "quic/core/quic_udp_socket_posix.cc", "quic/masque/masque_client.cc", "quic/masque/masque_client_session.cc", "quic/masque/masque_client_tools.cc",
diff --git a/build/source_list.gni b/build/source_list.gni index 4d34746..ac54fca 100644 --- a/build/source_list.gni +++ b/build/source_list.gni
@@ -665,6 +665,7 @@ "src/quiche/quic/core/quic_trace_visitor.cc", "src/quiche/quic/core/quic_transmission_info.cc", "src/quiche/quic/core/quic_types.cc", + "src/quiche/quic/core/quic_udp_socket.cc", "src/quiche/quic/core/quic_unacked_packet_map.cc", "src/quiche/quic/core/quic_utils.cc", "src/quiche/quic/core/quic_version_manager.cc", @@ -991,7 +992,6 @@ "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", - "src/quiche/quic/core/quic_udp_socket_posix.cc", "src/quiche/quic/masque/masque_client.cc", "src/quiche/quic/masque/masque_client_session.cc", "src/quiche/quic/masque/masque_client_tools.cc",
diff --git a/build/source_list.json b/build/source_list.json index d9867f7..4465eeb 100644 --- a/build/source_list.json +++ b/build/source_list.json
@@ -664,6 +664,7 @@ "quiche/quic/core/quic_trace_visitor.cc", "quiche/quic/core/quic_transmission_info.cc", "quiche/quic/core/quic_types.cc", + "quiche/quic/core/quic_udp_socket.cc", "quiche/quic/core/quic_unacked_packet_map.cc", "quiche/quic/core/quic_utils.cc", "quiche/quic/core/quic_version_manager.cc", @@ -990,7 +991,6 @@ "quiche/quic/core/quic_default_packet_writer.cc", "quiche/quic/core/quic_packet_reader.cc", "quiche/quic/core/quic_syscall_wrapper.cc", - "quiche/quic/core/quic_udp_socket_posix.cc", "quiche/quic/masque/masque_client.cc", "quiche/quic/masque/masque_client_session.cc", "quiche/quic/masque/masque_client_tools.cc",
diff --git a/quiche/quic/core/io/socket.h b/quiche/quic/core/io/socket.h index d428f8c..8fc7732 100644 --- a/quiche/quic/core/io/socket.h +++ b/quiche/quic/core/io/socket.h
@@ -28,9 +28,11 @@ #if defined(_WIN32) using SocketFd = SOCKET; inline constexpr SocketFd kInvalidSocketFd = INVALID_SOCKET; +inline constexpr int kSocketErrorMsgSize = WSAEMSGSIZE; #else using SocketFd = int; inline constexpr SocketFd kInvalidSocketFd = -1; +inline constexpr int kSocketErrorMsgSize = EMSGSIZE; #endif // Low-level platform-agnostic socket operations. Closely follows the behavior
diff --git a/quiche/quic/core/quic_default_packet_writer.cc b/quiche/quic/core/quic_default_packet_writer.cc index 78feee5..7eac827 100644 --- a/quiche/quic/core/quic_default_packet_writer.cc +++ b/quiche/quic/core/quic_default_packet_writer.cc
@@ -8,7 +8,7 @@ namespace quic { -QuicDefaultPacketWriter::QuicDefaultPacketWriter(int fd) +QuicDefaultPacketWriter::QuicDefaultPacketWriter(SocketFd fd) : fd_(fd), write_blocked_(false) {} QuicDefaultPacketWriter::~QuicDefaultPacketWriter() = default; @@ -36,7 +36,7 @@ void QuicDefaultPacketWriter::SetWritable() { write_blocked_ = false; } absl::optional<int> QuicDefaultPacketWriter::MessageTooBigErrorCode() const { - return EMSGSIZE; + return kSocketErrorMsgSize; } QuicByteCount QuicDefaultPacketWriter::GetMaxPacketSize(
diff --git a/quiche/quic/core/quic_default_packet_writer.h b/quiche/quic/core/quic_default_packet_writer.h index b2a0a86..718f8eb 100644 --- a/quiche/quic/core/quic_default_packet_writer.h +++ b/quiche/quic/core/quic_default_packet_writer.h
@@ -7,6 +7,7 @@ #include <cstddef> +#include "quiche/quic/core/io/socket.h" #include "quiche/quic/core/quic_packet_writer.h" #include "quiche/quic/platform/api/quic_export.h" #include "quiche/quic/platform/api/quic_socket_address.h" @@ -18,7 +19,7 @@ // Default packet writer which wraps QuicSocketUtils WritePacket. class QUIC_EXPORT_PRIVATE QuicDefaultPacketWriter : public QuicPacketWriter { public: - explicit QuicDefaultPacketWriter(int fd); + explicit QuicDefaultPacketWriter(SocketFd fd); QuicDefaultPacketWriter(const QuicDefaultPacketWriter&) = delete; QuicDefaultPacketWriter& operator=(const QuicDefaultPacketWriter&) = delete; ~QuicDefaultPacketWriter() override; @@ -40,14 +41,14 @@ const QuicSocketAddress& peer_address) override; WriteResult Flush() override; - void set_fd(int fd) { fd_ = fd; } + void set_fd(SocketFd fd) { fd_ = fd; } protected: void set_write_blocked(bool is_blocked); - int fd() { return fd_; } + SocketFd fd() { return fd_; } private: - int fd_; + SocketFd fd_; bool write_blocked_; };
diff --git a/quiche/quic/core/quic_udp_socket.cc b/quiche/quic/core/quic_udp_socket.cc new file mode 100644 index 0000000..1a35b72 --- /dev/null +++ b/quiche/quic/core/quic_udp_socket.cc
@@ -0,0 +1,205 @@ +// Copyright 2019 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. + +#if defined(__APPLE__) && !defined(__APPLE_USE_RFC_3542) +// This must be defined before including any system headers. +#define __APPLE_USE_RFC_3542 +#endif // defined(__APPLE__) && !defined(__APPLE_USE_RFC_3542) + +#include "absl/base/optimization.h" +#include "quiche/quic/core/io/socket.h" +#include "quiche/quic/core/quic_udp_socket.h" +#include "quiche/quic/platform/api/quic_bug_tracker.h" +#include "quiche/quic/platform/api/quic_flag_utils.h" + +// Common cmsg-related functions are defined below. +// Windows and POSIX cmsg formats are actually fairly similar, except the +// Windows ones have all of the macros prefixed with WSA_ and all the type names +// are different. + +namespace quic { +namespace { + +#if defined(_WIN32) +using PlatformCmsghdr = ::WSACMSGHDR; +#if !defined(CMSG_DATA) +#define CMSG_DATA WSA_CMSG_DATA +#endif // !defined(CMSG_DATA) +#else +using PlatformCmsghdr = ::cmsghdr; +#endif // defined(_WIN32) + +void PopulatePacketInfoFromControlMessageBase( + PlatformCmsghdr* cmsg, QuicUdpPacketInfo* packet_info, + BitMask64 packet_info_interested) { + if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) { + if (packet_info_interested.IsSet(QuicUdpPacketInfoBit::V6_SELF_IP)) { + const in6_pktinfo* info = reinterpret_cast<in6_pktinfo*>(CMSG_DATA(cmsg)); + const char* addr_data = reinterpret_cast<const char*>(&info->ipi6_addr); + int addr_len = sizeof(in6_addr); + QuicIpAddress self_v6_ip; + if (self_v6_ip.FromPackedString(addr_data, addr_len)) { + packet_info->SetSelfV6Ip(self_v6_ip); + } else { + QUIC_BUG(quic_bug_10751_1) << "QuicIpAddress::FromPackedString failed"; + } + } + return; + } + + if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) { + if (packet_info_interested.IsSet(QuicUdpPacketInfoBit::V4_SELF_IP)) { + const in_pktinfo* info = reinterpret_cast<in_pktinfo*>(CMSG_DATA(cmsg)); + const char* addr_data = reinterpret_cast<const char*>(&info->ipi_addr); + int addr_len = sizeof(in_addr); + QuicIpAddress self_v4_ip; + if (self_v4_ip.FromPackedString(addr_data, addr_len)) { + packet_info->SetSelfV4Ip(self_v4_ip); + } else { + QUIC_BUG(quic_bug_10751_2) << "QuicIpAddress::FromPackedString failed"; + } + } + return; + } +} + +} // namespace +} // namespace quic + +#if defined(_WIN32) +#include "quiche/quic/core/quic_udp_socket_win.inc" +#else +#include "quiche/quic/core/quic_udp_socket_posix.inc" +#endif + +namespace quic { + +QuicUdpSocketFd QuicUdpSocketApi::Create(int address_family, + int receive_buffer_size, + int send_buffer_size, bool ipv6_only) { + // QUICHE_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. + QUICHE_DCHECK_GE(kDefaultUdpPacketControlBufferSize, kMinCmsgSpaceForRead); + + absl::StatusOr<SocketFd> socket = socket_api::CreateSocket( + quiche::FromPlatformAddressFamily(address_family), + socket_api::SocketProtocol::kUdp, + /*blocking=*/false); + + if (!socket.ok()) { + QUIC_LOG_FIRST_N(ERROR, 100) + << "UDP non-blocking socket creation for address_family=" + << address_family << " failed: " << socket.status(); + return kQuicInvalidSocketFd; + } + +#if !defined(_WIN32) + SetGoogleSocketOptions(socket.value()); +#endif + + if (!SetupSocket(socket.value(), address_family, receive_buffer_size, + send_buffer_size, ipv6_only)) { + Destroy(socket.value()); + return kQuicInvalidSocketFd; + } + + return socket.value(); +} + +void QuicUdpSocketApi::Destroy(QuicUdpSocketFd fd) { + if (fd != kQuicInvalidSocketFd) { + absl::Status result = socket_api::Close(fd); + if (!result.ok()) { + QUIC_LOG_FIRST_N(WARNING, 100) + << "Failed to close UDP socket with error " << result; + } + } +} + +bool QuicUdpSocketApi::Bind(QuicUdpSocketFd fd, QuicSocketAddress address) { + sockaddr_storage addr = address.generic_address(); + int addr_len = + address.host().IsIPv4() ? sizeof(sockaddr_in) : sizeof(sockaddr_in6); + return 0 == bind(fd, reinterpret_cast<sockaddr*>(&addr), addr_len); +} + +bool QuicUdpSocketApi::BindInterface(QuicUdpSocketFd fd, + const std::string& interface_name) { +#if defined(__linux__) && !defined(__ANDROID_API__) + if (interface_name.empty() || interface_name.size() >= IFNAMSIZ) { + QUIC_BUG(udp_bad_interface_name) + << "interface_name must be nonempty and shorter than " << IFNAMSIZ; + return false; + } + + return 0 == setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, + interface_name.c_str(), interface_name.length()); +#else + (void)fd; + (void)interface_name; + QUIC_BUG(interface_bind_not_implemented) + << "Interface binding is not implemented on this platform"; + return false; +#endif +} + +bool QuicUdpSocketApi::EnableDroppedPacketCount(QuicUdpSocketFd fd) { +#if defined(__linux__) && defined(SO_RXQ_OVFL) + int get_overflow = 1; + return 0 == setsockopt(fd, SOL_SOCKET, SO_RXQ_OVFL, &get_overflow, + sizeof(get_overflow)); +#else + (void)fd; + return false; +#endif +} + +bool QuicUdpSocketApi::EnableReceiveSelfIpAddressForV4(QuicUdpSocketFd fd) { + int get_self_ip = 1; + return 0 == setsockopt(fd, IPPROTO_IP, IP_PKTINFO, + reinterpret_cast<char*>(&get_self_ip), + sizeof(get_self_ip)); +} + +bool QuicUdpSocketApi::EnableReceiveSelfIpAddressForV6(QuicUdpSocketFd fd) { + int get_self_ip = 1; + return 0 == setsockopt(fd, IPPROTO_IPV6, kIpv6RecvPacketInfo, + reinterpret_cast<char*>(&get_self_ip), + sizeof(get_self_ip)); +} + +bool QuicUdpSocketApi::EnableReceiveTimestamp(QuicUdpSocketFd fd) { +#if defined(__linux__) && (!defined(__ANDROID_API__) || __ANDROID_API__ >= 21) + int timestamping = SOF_TIMESTAMPING_RX_SOFTWARE | SOF_TIMESTAMPING_SOFTWARE; + return 0 == setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, ×tamping, + sizeof(timestamping)); +#else + (void)fd; + return false; +#endif +} + +bool QuicUdpSocketApi::EnableReceiveTtlForV4(QuicUdpSocketFd fd) { +#if defined(QUIC_UDP_SOCKET_SUPPORT_TTL) + int get_ttl = 1; + return 0 == setsockopt(fd, IPPROTO_IP, IP_RECVTTL, &get_ttl, sizeof(get_ttl)); +#else + (void)fd; + return false; +#endif +} + +bool QuicUdpSocketApi::EnableReceiveTtlForV6(QuicUdpSocketFd fd) { +#if defined(QUIC_UDP_SOCKET_SUPPORT_TTL) + int get_ttl = 1; + return 0 == setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &get_ttl, + sizeof(get_ttl)); +#else + (void)fd; + return false; +#endif +} + +} // namespace quic
diff --git a/quiche/quic/core/quic_udp_socket_posix.cc b/quiche/quic/core/quic_udp_socket_posix.inc similarity index 77% rename from quiche/quic/core/quic_udp_socket_posix.cc rename to quiche/quic/core/quic_udp_socket_posix.inc index 26d4ef4..deb406c 100644 --- a/quiche/quic/core/quic_udp_socket_posix.cc +++ b/quiche/quic/core/quic_udp_socket_posix.inc
@@ -2,12 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "quiche/quic/core/quic_types.h" -#if defined(__APPLE__) && !defined(__APPLE_USE_RFC_3542) -// This must be defined before including any system headers. -#define __APPLE_USE_RFC_3542 -#endif // defined(__APPLE__) && !defined(__APPLE_USE_RFC_3542) - #include <arpa/inet.h> #include <fcntl.h> #include <net/if.h> @@ -43,6 +37,8 @@ // Explicit Congestion Notification is the last two bits of the TOS byte. constexpr uint8_t kEcnMask = 0x03; +constexpr int kIpv6RecvPacketInfo = IPV6_RECVPKTINFO; + #if defined(__linux__) && (!defined(__ANDROID_API__) || __ANDROID_API__ >= 21) #define QUIC_UDP_SOCKET_SUPPORT_LINUX_TIMESTAMPING 1 // This is the structure that SO_TIMESTAMPING fills into the cmsg header. @@ -125,35 +121,8 @@ } #endif - if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) { - if (packet_info_interested.IsSet(QuicUdpPacketInfoBit::V6_SELF_IP)) { - const in6_pktinfo* info = reinterpret_cast<in6_pktinfo*>(CMSG_DATA(cmsg)); - const char* addr_data = reinterpret_cast<const char*>(&info->ipi6_addr); - int addr_len = sizeof(in6_addr); - QuicIpAddress self_v6_ip; - if (self_v6_ip.FromPackedString(addr_data, addr_len)) { - packet_info->SetSelfV6Ip(self_v6_ip); - } else { - QUIC_BUG(quic_bug_10751_1) << "QuicIpAddress::FromPackedString failed"; - } - } - return; - } - - if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) { - if (packet_info_interested.IsSet(QuicUdpPacketInfoBit::V4_SELF_IP)) { - const in_pktinfo* info = reinterpret_cast<in_pktinfo*>(CMSG_DATA(cmsg)); - const char* addr_data = reinterpret_cast<const char*>(&info->ipi_addr); - int addr_len = sizeof(in_addr); - QuicIpAddress self_v4_ip; - if (self_v4_ip.FromPackedString(addr_data, addr_len)) { - packet_info->SetSelfV4Ip(self_v4_ip); - } else { - QUIC_BUG(quic_bug_10751_2) << "QuicIpAddress::FromPackedString failed"; - } - } - return; - } + PopulatePacketInfoFromControlMessageBase(cmsg, packet_info, + packet_info_interested); if ((cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_TTL) || (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_HOPLIMIT)) { @@ -214,37 +183,6 @@ } } // namespace -QuicUdpSocketFd QuicUdpSocketApi::Create(int address_family, - int receive_buffer_size, - int send_buffer_size, bool ipv6_only) { - // QUICHE_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. - QUICHE_DCHECK_GE(kDefaultUdpPacketControlBufferSize, kMinCmsgSpaceForRead); - - absl::StatusOr<SocketFd> socket = socket_api::CreateSocket( - quiche::FromPlatformAddressFamily(address_family), - socket_api::SocketProtocol::kUdp, - /*blocking=*/false); - - if (!socket.ok()) { - QUIC_LOG_FIRST_N(ERROR, 100) - << "UDP non-blocking socket creation for address_family=" - << address_family << " failed: " << socket.status(); - return kQuicInvalidSocketFd; - } - - SetGoogleSocketOptions(socket.value()); - - if (!SetupSocket(socket.value(), address_family, receive_buffer_size, - send_buffer_size, ipv6_only)) { - Destroy(socket.value()); - return kQuicInvalidSocketFd; - } - - return socket.value(); -} - bool QuicUdpSocketApi::SetupSocket(QuicUdpSocketFd fd, int address_family, int receive_buffer_size, int send_buffer_size, bool ipv6_only) { @@ -298,98 +236,6 @@ return true; } -void QuicUdpSocketApi::Destroy(QuicUdpSocketFd fd) { - if (fd != kQuicInvalidSocketFd) { - absl::Status result = socket_api::Close(fd); - if (!result.ok()) { - QUIC_LOG_FIRST_N(WARNING, 100) - << "Failed to close UDP socket with error " << result; - } - } -} - -bool QuicUdpSocketApi::Bind(QuicUdpSocketFd fd, QuicSocketAddress address) { - sockaddr_storage addr = address.generic_address(); - int addr_len = - address.host().IsIPv4() ? sizeof(sockaddr_in) : sizeof(sockaddr_in6); - return 0 == bind(fd, reinterpret_cast<sockaddr*>(&addr), addr_len); -} - -bool QuicUdpSocketApi::BindInterface(QuicUdpSocketFd fd, - const std::string& interface_name) { -#if defined(__linux__) && !defined(__ANDROID_API__) - if (interface_name.empty() || interface_name.size() >= IFNAMSIZ) { - QUIC_BUG(udp_bad_interface_name) - << "interface_name must be nonempty and shorter than " << IFNAMSIZ; - return false; - } - - return 0 == setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, - interface_name.c_str(), interface_name.length()); -#else - (void)fd; - (void)interface_name; - QUIC_BUG(interface_bind_not_implemented) - << "Interface binding is not implemented on this platform"; - return false; -#endif -} - -bool QuicUdpSocketApi::EnableDroppedPacketCount(QuicUdpSocketFd fd) { -#if defined(__linux__) && defined(SO_RXQ_OVFL) - int get_overflow = 1; - return 0 == setsockopt(fd, SOL_SOCKET, SO_RXQ_OVFL, &get_overflow, - sizeof(get_overflow)); -#else - (void)fd; - return false; -#endif -} - -bool QuicUdpSocketApi::EnableReceiveSelfIpAddressForV4(QuicUdpSocketFd fd) { - int get_self_ip = 1; - return 0 == setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &get_self_ip, - sizeof(get_self_ip)); -} - -bool QuicUdpSocketApi::EnableReceiveSelfIpAddressForV6(QuicUdpSocketFd fd) { - int get_self_ip = 1; - return 0 == setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &get_self_ip, - sizeof(get_self_ip)); -} - -bool QuicUdpSocketApi::EnableReceiveTimestamp(QuicUdpSocketFd fd) { -#if defined(__linux__) && (!defined(__ANDROID_API__) || __ANDROID_API__ >= 21) - int timestamping = SOF_TIMESTAMPING_RX_SOFTWARE | SOF_TIMESTAMPING_SOFTWARE; - return 0 == setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, ×tamping, - sizeof(timestamping)); -#else - (void)fd; - return false; -#endif -} - -bool QuicUdpSocketApi::EnableReceiveTtlForV4(QuicUdpSocketFd fd) { -#if defined(QUIC_UDP_SOCKET_SUPPORT_TTL) - int get_ttl = 1; - return 0 == setsockopt(fd, IPPROTO_IP, IP_RECVTTL, &get_ttl, sizeof(get_ttl)); -#else - (void)fd; - return false; -#endif -} - -bool QuicUdpSocketApi::EnableReceiveTtlForV6(QuicUdpSocketFd fd) { -#if defined(QUIC_UDP_SOCKET_SUPPORT_TTL) - int get_ttl = 1; - return 0 == setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &get_ttl, - sizeof(get_ttl)); -#else - (void)fd; - return false; -#endif -} - bool QuicUdpSocketApi::WaitUntilReadable(QuicUdpSocketFd fd, QuicTime::Delta timeout) { fd_set read_fds;
diff --git a/quiche/quic/core/quic_udp_socket_win.inc b/quiche/quic/core/quic_udp_socket_win.inc new file mode 100644 index 0000000..429b8c7 --- /dev/null +++ b/quiche/quic/core/quic_udp_socket_win.inc
@@ -0,0 +1,281 @@ +// 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. + +// UDP socket implementation for Windows. Feature overview: +// * Supported: setting and getting self IP address. +// * Unsupported but could work on a sufficiently new Windows version: +// - Timestamping +// - Setting and getting TTL. + +#include <mswsock.h> +#include <winsock2.h> + +#include <cstddef> + +#include "quiche/quic/core/quic_utils.h" + +namespace quic { + +namespace { +constexpr size_t kMinCmsgSpaceForRead = + CMSG_SPACE(sizeof(in_pktinfo)) // V4 Self IP + + CMSG_SPACE(sizeof(in6_pktinfo)); // V6 Self IP + +constexpr int kIpv6RecvPacketInfo = IPV6_PKTINFO; + +void SetV4SelfIpInControlMessage(const QuicIpAddress& self_address, + WSACMSGHDR* cmsg) { + QUICHE_DCHECK(self_address.IsIPv4()); + in_pktinfo* pktinfo = reinterpret_cast<in_pktinfo*>(WSA_CMSG_DATA(cmsg)); + memset(pktinfo, 0, sizeof(in_pktinfo)); + pktinfo->ipi_addr = self_address.GetIPv4(); +} + +void SetV6SelfIpInControlMessage(const QuicIpAddress& self_address, + cmsghdr* cmsg) { + QUICHE_DCHECK(self_address.IsIPv6()); + in6_pktinfo* pktinfo = reinterpret_cast<in6_pktinfo*>(WSA_CMSG_DATA(cmsg)); + memset(pktinfo, 0, sizeof(in6_pktinfo)); + pktinfo->ipi6_addr = self_address.GetIPv6(); +} + +bool NextCmsg(WSAMSG* hdr, char* control_buffer, size_t control_buffer_len, + int cmsg_level, int cmsg_type, size_t data_size, + WSACMSGHDR** cmsg /*in, out*/) { + // msg_controllen needs to be increased first, otherwise CMSG_NXTHDR will + // return nullptr. + hdr->Control.len += WSA_CMSG_SPACE(data_size); + if (hdr->Control.len > control_buffer_len) { + return false; + } + + if ((*cmsg) == nullptr) { + QUICHE_DCHECK_EQ(nullptr, hdr->Control.buf); + memset(control_buffer, 0, control_buffer_len); + hdr->Control.buf = control_buffer; + (*cmsg) = WSA_CMSG_FIRSTHDR(hdr); + } else { + QUICHE_DCHECK_NE(nullptr, hdr->Control.buf); + (*cmsg) = WSA_CMSG_NXTHDR(hdr, (*cmsg)); + } + + if (nullptr == (*cmsg)) { + return false; + } + + (*cmsg)->cmsg_len = WSA_CMSG_LEN(data_size); + (*cmsg)->cmsg_level = cmsg_level; + (*cmsg)->cmsg_type = cmsg_type; + + return true; +} +} // namespace + +bool QuicUdpSocketApi::SetupSocket(QuicUdpSocketFd fd, int address_family, + int receive_buffer_size, + int send_buffer_size, bool /*ipv6_only*/) { + // Receive buffer size. + if (absl::Status status = + socket_api::SetReceiveBufferSize(fd, receive_buffer_size); + !status.ok()) { + QUIC_LOG_FIRST_N(ERROR, 100) + << "Failed to set socket recv size: " << status; + return false; + } + + // Send buffer size. + if (absl::Status status = socket_api::SetSendBufferSize(fd, send_buffer_size); + !status.ok()) { + QUIC_LOG_FIRST_N(ERROR, 100) + << "Failed to set socket send size: " << status; + return false; + } + + if (address_family == AF_INET) { + if (!EnableReceiveSelfIpAddressForV4(fd)) { + QUIC_LOG_FIRST_N(ERROR, 100) + << "Failed to enable receiving of self v4 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; +} + +void QuicUdpSocketApi::ReadPacket(QuicUdpSocketFd fd, + BitMask64 packet_info_interested, + ReadPacketResult* result) { + result->ok = false; + + // WSARecvMsg is an extension to Windows Socket API that requires us to fetch + // the function pointer via an ioctl. + DWORD recvmsg_fn_out_bytes; + LPFN_WSARECVMSG recvmsg_fn = nullptr; + GUID recvmsg_guid = WSAID_WSARECVMSG; + int ioctl_result = + WSAIoctl(fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &recvmsg_guid, + sizeof(recvmsg_guid), &recvmsg_fn, sizeof(recvmsg_fn), + &recvmsg_fn_out_bytes, nullptr, nullptr); + if (ioctl_result != 0) { + QUICHE_LOG(ERROR) << "Failed to load WSARecvMsg() function, error code: " + << WSAGetLastError(); + return; + } + + BufferSpan& packet_buffer = result->packet_buffer; + BufferSpan& control_buffer = result->control_buffer; + QuicUdpPacketInfo* packet_info = &result->packet_info; + + QUICHE_DCHECK_GE(control_buffer.buffer_len, kMinCmsgSpaceForRead); + + WSABUF iov; + iov.buf = packet_buffer.buffer; + iov.len = packet_buffer.buffer_len; + sockaddr_storage raw_peer_address; + + if (control_buffer.buffer_len > 0) { + reinterpret_cast<WSACMSGHDR*>(control_buffer.buffer)->cmsg_len = + control_buffer.buffer_len; + } + + WSAMSG hdr; + memset(&hdr, 0, sizeof(hdr)); + hdr.name = reinterpret_cast<sockaddr*>(&raw_peer_address); + hdr.namelen = sizeof(raw_peer_address); + hdr.lpBuffers = &iov; + hdr.dwBufferCount = 1; + hdr.dwFlags = 0; + hdr.Control.buf = control_buffer.buffer; + hdr.Control.len = control_buffer.buffer_len; + + DWORD bytes_read; + int recvmsg_result = recvmsg_fn(fd, &hdr, &bytes_read, nullptr, nullptr); + if (recvmsg_result != 0) { + const int error_num = WSAGetLastError(); + if (error_num != WSAEWOULDBLOCK) { + QUIC_LOG_FIRST_N(ERROR, 100) << "Error reading packet: " << error_num; + } + return; + } + + packet_buffer.buffer_len = bytes_read; + if (packet_info_interested.IsSet(QuicUdpPacketInfoBit::PEER_ADDRESS)) { + packet_info->SetPeerAddress(QuicSocketAddress(raw_peer_address)); + } + + if (hdr.Control.len > 0) { + for (WSACMSGHDR* cmsg = WSA_CMSG_FIRSTHDR(&hdr); cmsg != nullptr; + cmsg = WSA_CMSG_NXTHDR(&hdr, cmsg)) { + BitMask64 prior_bitmask = packet_info->bitmask(); + PopulatePacketInfoFromControlMessageBase(cmsg, packet_info, + packet_info_interested); + if (packet_info->bitmask() == prior_bitmask) { + QUIC_DLOG(INFO) << "Ignored cmsg_level:" << cmsg->cmsg_level + << ", cmsg_type:" << cmsg->cmsg_type; + } + } + } + + result->ok = true; +} + +size_t QuicUdpSocketApi::ReadMultiplePackets(QuicUdpSocketFd fd, + BitMask64 packet_info_interested, + ReadPacketResults* results) { + size_t num_packets = 0; + for (ReadPacketResult& result : *results) { + result.ok = false; + } + for (ReadPacketResult& result : *results) { + ReadPacket(fd, packet_info_interested, &result); + if (!result.ok && WSAGetLastError() == WSAEWOULDBLOCK) { + break; + } + ++num_packets; + } + return num_packets; +} + +WriteResult QuicUdpSocketApi::WritePacket( + QuicUdpSocketFd fd, const char* packet_buffer, size_t packet_buffer_len, + const QuicUdpPacketInfo& packet_info) { + if (!packet_info.HasValue(QuicUdpPacketInfoBit::PEER_ADDRESS)) { + return WriteResult(WRITE_STATUS_ERROR, WSAEINVAL); + } + + char control_buffer[512]; + sockaddr_storage raw_peer_address = + packet_info.peer_address().generic_address(); + WSABUF iov; + iov.buf = const_cast<char*>(packet_buffer); + iov.len = packet_buffer_len; + + WSAMSG hdr; + memset(&hdr, 0, sizeof(hdr)); + hdr.name = reinterpret_cast<sockaddr*>(&raw_peer_address); + hdr.namelen = packet_info.peer_address().host().IsIPv4() + ? sizeof(sockaddr_in) + : sizeof(sockaddr_in6); + hdr.lpBuffers = &iov; + hdr.dwBufferCount = 1; + + WSACMSGHDR* cmsg = nullptr; + + // Set self IP. + if (packet_info.HasValue(QuicUdpPacketInfoBit::V4_SELF_IP) && + packet_info.self_v4_ip().IsInitialized()) { + if (!NextCmsg(&hdr, control_buffer, sizeof(control_buffer), IPPROTO_IP, + IP_PKTINFO, sizeof(in_pktinfo), &cmsg)) { + QUIC_LOG_FIRST_N(ERROR, 100) + << "Not enough buffer to set self v4 ip address."; + return WriteResult(WRITE_STATUS_ERROR, EINVAL); + } + SetV4SelfIpInControlMessage(packet_info.self_v4_ip(), cmsg); + } else if (packet_info.HasValue(QuicUdpPacketInfoBit::V6_SELF_IP) && + packet_info.self_v6_ip().IsInitialized()) { + if (!NextCmsg(&hdr, control_buffer, sizeof(control_buffer), IPPROTO_IPV6, + IPV6_PKTINFO, sizeof(in6_pktinfo), &cmsg)) { + QUIC_LOG_FIRST_N(ERROR, 100) + << "Not enough buffer to set self v6 ip address."; + return WriteResult(WRITE_STATUS_ERROR, EINVAL); + } + SetV6SelfIpInControlMessage(packet_info.self_v6_ip(), cmsg); + } + + DWORD bytes_sent; + int result = + WSASendMsg(fd, &hdr, /*dwFlags=*/0, &bytes_sent, nullptr, nullptr); + if (result == 0) { + return WriteResult(WRITE_STATUS_OK, bytes_sent); + } + int error = WSAGetLastError(); + return WriteResult( + (error == WSAEWOULDBLOCK) ? WRITE_STATUS_BLOCKED : WRITE_STATUS_ERROR, + error); +} + +bool QuicUdpSocketApi::WaitUntilReadable(QuicUdpSocketFd fd, + QuicTime::Delta timeout) { + WSAPOLLFD polled_fd; + polled_fd.fd = fd; + polled_fd.events = POLLIN; + polled_fd.revents = 0; + + int result = ::WSAPoll(&polled_fd, 1, timeout.ToMilliseconds()); + if (result == SOCKET_ERROR) { + QUICHE_LOG(ERROR) << "Error while calling WSAPoll(): " << WSAGetLastError(); + } + + return result > 0; +} + +} // namespace quic
diff --git a/quiche/quic/test_tools/quic_server_peer.cc b/quiche/quic/test_tools/quic_server_peer.cc index 6f6c8f9..4ef81fb 100644 --- a/quiche/quic/test_tools/quic_server_peer.cc +++ b/quiche/quic/test_tools/quic_server_peer.cc
@@ -14,8 +14,8 @@ // static bool QuicServerPeer::SetSmallSocket(QuicServer* server) { int size = 1024 * 10; - return setsockopt(server->fd_, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) != - -1; + return setsockopt(server->fd_, SOL_SOCKET, SO_RCVBUF, + reinterpret_cast<char*>(&size), sizeof(size)) != -1; } // static
diff --git a/quiche/quic/test_tools/quic_test_client.cc b/quiche/quic/test_tools/quic_test_client.cc index a617348..1f17227 100644 --- a/quiche/quic/test_tools/quic_test_client.cc +++ b/quiche/quic/test_tools/quic_test_client.cc
@@ -365,7 +365,7 @@ client_->SetUserAgentID(user_agent_id); } -ssize_t QuicTestClient::SendRequest(const std::string& uri) { +int64_t QuicTestClient::SendRequest(const std::string& uri) { spdy::Http2HeaderBlock headers; if (!PopulateHeaderBlockFromUrl(uri, &headers)) { return 0; @@ -373,7 +373,7 @@ return SendMessage(headers, ""); } -ssize_t QuicTestClient::SendRequestAndRstTogether(const std::string& uri) { +int64_t QuicTestClient::SendRequestAndRstTogether(const std::string& uri) { spdy::Http2HeaderBlock headers; if (!PopulateHeaderBlockFromUrl(uri, &headers)) { return 0; @@ -381,7 +381,7 @@ QuicSpdyClientSession* session = client()->client_session(); QuicConnection::ScopedPacketFlusher flusher(session->connection()); - ssize_t ret = SendMessage(headers, "", /*fin=*/true, /*flush=*/false); + int64_t ret = SendMessage(headers, "", /*fin=*/true, /*flush=*/false); QuicStreamId stream_id = GetNthClientInitiatedBidirectionalStreamId( session->transport_version(), 0); @@ -398,7 +398,7 @@ } } -ssize_t QuicTestClient::GetOrCreateStreamAndSendRequest( +int64_t QuicTestClient::GetOrCreateStreamAndSendRequest( const spdy::Http2HeaderBlock* headers, absl::string_view body, bool fin, quiche::QuicheReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { @@ -426,7 +426,7 @@ } QuicSpdyStreamPeer::set_ack_listener(stream, ack_listener); - ssize_t ret = 0; + int64_t ret = 0; if (headers != nullptr) { spdy::Http2HeaderBlock spdy_headers(headers->Clone()); if (spdy_headers[":authority"].as_string().empty()) { @@ -441,23 +441,23 @@ return ret; } -ssize_t QuicTestClient::SendMessage(const spdy::Http2HeaderBlock& headers, +int64_t QuicTestClient::SendMessage(const spdy::Http2HeaderBlock& headers, absl::string_view body) { return SendMessage(headers, body, /*fin=*/true); } -ssize_t QuicTestClient::SendMessage(const spdy::Http2HeaderBlock& headers, +int64_t QuicTestClient::SendMessage(const spdy::Http2HeaderBlock& headers, absl::string_view body, bool fin) { return SendMessage(headers, body, fin, /*flush=*/true); } -ssize_t QuicTestClient::SendMessage(const spdy::Http2HeaderBlock& headers, +int64_t QuicTestClient::SendMessage(const spdy::Http2HeaderBlock& headers, absl::string_view body, bool fin, bool flush) { // Always force creation of a stream for SendMessage. latest_created_stream_ = nullptr; - ssize_t ret = GetOrCreateStreamAndSendRequest(&headers, body, fin, nullptr); + int64_t ret = GetOrCreateStreamAndSendRequest(&headers, body, fin, nullptr); if (flush) { WaitForWriteToFlush(); @@ -465,11 +465,11 @@ return ret; } -ssize_t QuicTestClient::SendData(const std::string& data, bool last_data) { +int64_t QuicTestClient::SendData(const std::string& data, bool last_data) { return SendData(data, last_data, nullptr); } -ssize_t QuicTestClient::SendData( +int64_t QuicTestClient::SendData( const std::string& data, bool last_data, quiche::QuicheReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { @@ -645,7 +645,7 @@ return true; } -ssize_t QuicTestClient::Send(absl::string_view data) { +int64_t QuicTestClient::Send(absl::string_view data) { return SendData(std::string(data), false); }
diff --git a/quiche/quic/test_tools/quic_test_client.h b/quiche/quic/test_tools/quic_test_client.h index 9abab23..9f2a869 100644 --- a/quiche/quic/test_tools/quic_test_client.h +++ b/quiche/quic/test_tools/quic_test_client.h
@@ -115,18 +115,18 @@ void SetUserAgentID(const std::string& user_agent_id); // Wraps data in a quic packet and sends it. - ssize_t SendData(const std::string& data, bool last_data); + int64_t SendData(const std::string& data, bool last_data); // As above, but |delegate| will be notified when |data| is ACKed. - ssize_t SendData( + int64_t SendData( const std::string& data, bool last_data, quiche::QuicheReferenceCountedPointer<QuicAckListenerInterface> ack_listener); // Clears any outstanding state and sends a simple GET of 'uri' to the // server. Returns 0 if the request failed and no bytes were written. - ssize_t SendRequest(const std::string& uri); + int64_t SendRequest(const std::string& uri); // Send a request R and a RST_FRAME which resets R, in the same packet. - ssize_t SendRequestAndRstTogether(const std::string& uri); + int64_t SendRequestAndRstTogether(const std::string& uri); // Sends requests for all the urls and waits for the responses. To process // the individual responses as they are returned, the caller should use the // set the response_listener on the client(). @@ -134,18 +134,18 @@ const std::vector<std::string>& url_list); // Sends a request containing |headers| and |body| and returns the number of // bytes sent (the size of the serialized request headers and body). - ssize_t SendMessage(const spdy::Http2HeaderBlock& headers, + int64_t SendMessage(const spdy::Http2HeaderBlock& headers, absl::string_view body); // Sends a request containing |headers| and |body| with the fin bit set to // |fin| and returns the number of bytes sent (the size of the serialized // request headers and body). - ssize_t SendMessage(const spdy::Http2HeaderBlock& headers, + int64_t SendMessage(const spdy::Http2HeaderBlock& headers, absl::string_view body, bool fin); // Sends a request containing |headers| and |body| with the fin bit set to // |fin| and returns the number of bytes sent (the size of the serialized // request headers and body). If |flush| is true, will wait for the message to // be flushed before returning. - ssize_t SendMessage(const spdy::Http2HeaderBlock& headers, + int64_t SendMessage(const spdy::Http2HeaderBlock& headers, absl::string_view body, bool fin, bool flush); // Sends a request containing |headers| and |body|, waits for the response, // and returns the response body. @@ -161,7 +161,7 @@ QuicSocketAddress local_address() const; void ClearPerRequestState(); bool WaitUntil(int timeout_ms, std::function<bool()> trigger); - ssize_t Send(absl::string_view data); + int64_t Send(absl::string_view data); bool connected() const; bool buffer_body() const; void set_buffer_body(bool buffer_body); @@ -259,7 +259,7 @@ // Calls GetOrCreateStream(), sends the request on the stream, and // stores the request in case it needs to be resent. If |headers| is // null, only the body will be sent on the stream. - ssize_t GetOrCreateStreamAndSendRequest( + int64_t GetOrCreateStreamAndSendRequest( const spdy::Http2HeaderBlock* headers, absl::string_view body, bool fin, quiche::QuicheReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
diff --git a/quiche/quic/tools/quic_client_default_network_helper.cc b/quiche/quic/tools/quic_client_default_network_helper.cc index ab9e1b1..424b8b9 100644 --- a/quiche/quic/tools/quic_client_default_network_helper.cc +++ b/quiche/quic/tools/quic_client_default_network_helper.cc
@@ -22,7 +22,7 @@ // listener whenever the socket gets blocked. class LevelTriggeredPacketWriter : public QuicDefaultPacketWriter { public: - explicit LevelTriggeredPacketWriter(int fd, QuicEventLoop* event_loop) + explicit LevelTriggeredPacketWriter(SocketFd fd, QuicEventLoop* event_loop) : QuicDefaultPacketWriter(fd), event_loop_(event_loop) { QUICHE_DCHECK(!event_loop->SupportsEdgeTriggered()); } @@ -68,11 +68,11 @@ bool QuicClientDefaultNetworkHelper::CreateUDPSocketAndBind( QuicSocketAddress server_address, QuicIpAddress bind_to_address, int bind_to_port) { - int fd = CreateUDPSocket(server_address, &overflow_supported_); - if (fd < 0) { + SocketFd fd = CreateUDPSocket(server_address, &overflow_supported_); + if (fd == kInvalidSocketFd) { return false; } - auto closer = absl::MakeCleanup([fd] { close(fd); }); + auto closer = absl::MakeCleanup([fd] { (void)socket_api::Close(fd); }); QuicSocketAddress client_address; if (bind_to_address.IsInitialized()) { @@ -124,7 +124,7 @@ return false; } -void QuicClientDefaultNetworkHelper::CleanUpUDPSocket(int fd) { +void QuicClientDefaultNetworkHelper::CleanUpUDPSocket(SocketFd fd) { CleanUpUDPSocketImpl(fd); fd_address_map_.erase(fd); } @@ -136,12 +136,12 @@ fd_address_map_.clear(); } -void QuicClientDefaultNetworkHelper::CleanUpUDPSocketImpl(int fd) { - if (fd > -1) { +void QuicClientDefaultNetworkHelper::CleanUpUDPSocketImpl(SocketFd fd) { + if (fd != kInvalidSocketFd) { bool success = event_loop_->UnregisterSocket(fd); QUICHE_DCHECK(success || fds_unregistered_externally_); - int rc = close(fd); - QUICHE_DCHECK_EQ(0, rc); + absl::Status rc = socket_api::Close(fd); + QUICHE_DCHECK(rc.ok()) << rc; } } @@ -207,7 +207,7 @@ return fd_address_map_.back().second; } -int QuicClientDefaultNetworkHelper::GetLatestFD() const { +SocketFd QuicClientDefaultNetworkHelper::GetLatestFD() const { if (fd_address_map_.empty()) { return -1; } @@ -221,13 +221,13 @@ client_->session()->ProcessUdpPacket(self_address, peer_address, packet); } -int QuicClientDefaultNetworkHelper::CreateUDPSocket( +SocketFd QuicClientDefaultNetworkHelper::CreateUDPSocket( QuicSocketAddress server_address, bool* overflow_supported) { QuicUdpSocketApi api; - int fd = api.Create(server_address.host().AddressFamilyToInt(), - /*receive_buffer_size =*/kDefaultSocketReceiveBuffer, - /*send_buffer_size =*/kDefaultSocketReceiveBuffer); - if (fd < 0) { + SocketFd fd = api.Create(server_address.host().AddressFamilyToInt(), + /*receive_buffer_size =*/kDefaultSocketReceiveBuffer, + /*send_buffer_size =*/kDefaultSocketReceiveBuffer); + if (fd == kInvalidSocketFd) { return fd; } @@ -242,7 +242,7 @@ return fd; } -bool QuicClientDefaultNetworkHelper::BindInterfaceNameIfNeeded(int fd) { +bool QuicClientDefaultNetworkHelper::BindInterfaceNameIfNeeded(SocketFd fd) { QuicUdpSocketApi api; std::string interface_name = client_->interface_name(); if (!interface_name.empty()) {
diff --git a/quiche/quic/tools/quic_client_default_network_helper.h b/quiche/quic/tools/quic_client_default_network_helper.h index 07b0753..f62bd80 100644 --- a/quiche/quic/tools/quic_client_default_network_helper.h +++ b/quiche/quic/tools/quic_client_default_network_helper.h
@@ -58,20 +58,19 @@ // Accessors provided for convenience, not part of any interface. QuicEventLoop* event_loop() { return event_loop_; } - const quiche::QuicheLinkedHashMap<int, QuicSocketAddress>& fd_address_map() - const { + const quiche::QuicheLinkedHashMap<SocketFd, QuicSocketAddress>& + fd_address_map() const { return fd_address_map_; } // If the client has at least one UDP socket, return the latest created one. // Otherwise, return -1. - int GetLatestFD() const; + SocketFd GetLatestFD() const; - // Create socket for connection to |server_address| with default socket - // options. - // Return fd index. - virtual int CreateUDPSocket(QuicSocketAddress server_address, - bool* overflow_supported); + // Create a socket for connection to |server_address| with default socket + // options. Returns the FD of the resulting socket. + virtual SocketFd CreateUDPSocket(QuicSocketAddress server_address, + bool* overflow_supported); QuicClientBase* client() { return client_; } @@ -80,7 +79,7 @@ } // If |fd| is an open UDP socket, unregister and close it. Otherwise, do // nothing. - void CleanUpUDPSocket(int fd); + void CleanUpUDPSocket(SocketFd fd); // Used for testing. void SetClientPort(int port); @@ -94,10 +93,10 @@ } // Bind a socket to a specific network interface. - bool BindInterfaceNameIfNeeded(int fd); + bool BindInterfaceNameIfNeeded(SocketFd fd); // Actually clean up |fd|. - virtual void CleanUpUDPSocketImpl(int fd); + virtual void CleanUpUDPSocketImpl(SocketFd fd); private: // Listens for events on the client socket. @@ -105,7 +104,7 @@ // Map mapping created UDP sockets to their addresses. By using linked hash // map, the order of socket creation can be recorded. - quiche::QuicheLinkedHashMap<int, QuicSocketAddress> fd_address_map_; + quiche::QuicheLinkedHashMap<SocketFd, QuicSocketAddress> fd_address_map_; // If overflow_supported_ is true, this will be the number of packets dropped // during the lifetime of the server.
diff --git a/quiche/quic/tools/quic_server.cc b/quiche/quic/tools/quic_server.cc index 738d8c9..63e9aca 100644 --- a/quiche/quic/tools/quic_server.cc +++ b/quiche/quic/tools/quic_server.cc
@@ -97,8 +97,8 @@ } QuicServer::~QuicServer() { - close(fd_); - fd_ = -1; + (void)socket_api::Close(fd_); + fd_ = kInvalidSocketFd; // Should be fine without because nothing should send requests to the backend // after `this` is destroyed, but for extra pointer safety, clear the socket