| // 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 "quiche/quic/core/quic_udp_socket.h" | 
 |  | 
 | #include <string> | 
 |  | 
 | #include "absl/base/optimization.h" | 
 | #include "quiche/quic/core/io/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, | 
 |     QuicUdpPacketInfoBitMask 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); | 
 | #endif | 
 |  | 
 |   if (!SetupSocket(*socket, address_family, receive_buffer_size, | 
 |                    send_buffer_size, ipv6_only)) { | 
 |     Destroy(*socket); | 
 |     return kQuicInvalidSocketFd; | 
 |   } | 
 |  | 
 |   return *socket; | 
 | } | 
 |  | 
 | 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(QUIC_UDP_SOCKET_SUPPORT_LINUX_TIMESTAMPING) | 
 |   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 |