xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/quic_udp_socket.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #if defined(__APPLE__) && !defined(__APPLE_USE_RFC_3542)
6 // This must be defined before including any system headers.
7 #define __APPLE_USE_RFC_3542
8 #endif  // defined(__APPLE__) && !defined(__APPLE_USE_RFC_3542)
9 
10 #include "quiche/quic/core/quic_udp_socket.h"
11 
12 #include "absl/base/optimization.h"
13 #include "quiche/quic/core/io/socket.h"
14 #include "quiche/quic/platform/api/quic_bug_tracker.h"
15 #include "quiche/quic/platform/api/quic_flag_utils.h"
16 
17 // Common cmsg-related functions are defined below.
18 // Windows and POSIX cmsg formats are actually fairly similar, except the
19 // Windows ones have all of the macros prefixed with WSA_ and all the type names
20 // are different.
21 
22 namespace quic {
23 namespace {
24 
25 #if defined(_WIN32)
26 using PlatformCmsghdr = ::WSACMSGHDR;
27 #if !defined(CMSG_DATA)
28 #define CMSG_DATA WSA_CMSG_DATA
29 #endif  // !defined(CMSG_DATA)
30 #else
31 using PlatformCmsghdr = ::cmsghdr;
32 #endif  // defined(_WIN32)
33 
PopulatePacketInfoFromControlMessageBase(PlatformCmsghdr * cmsg,QuicUdpPacketInfo * packet_info,QuicUdpPacketInfoBitMask packet_info_interested)34 void PopulatePacketInfoFromControlMessageBase(
35     PlatformCmsghdr* cmsg, QuicUdpPacketInfo* packet_info,
36     QuicUdpPacketInfoBitMask packet_info_interested) {
37   if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
38     if (packet_info_interested.IsSet(QuicUdpPacketInfoBit::V6_SELF_IP)) {
39       const in6_pktinfo* info = reinterpret_cast<in6_pktinfo*>(CMSG_DATA(cmsg));
40       const char* addr_data = reinterpret_cast<const char*>(&info->ipi6_addr);
41       int addr_len = sizeof(in6_addr);
42       QuicIpAddress self_v6_ip;
43       if (self_v6_ip.FromPackedString(addr_data, addr_len)) {
44         packet_info->SetSelfV6Ip(self_v6_ip);
45       } else {
46         QUIC_BUG(quic_bug_10751_1) << "QuicIpAddress::FromPackedString failed";
47       }
48     }
49     return;
50   }
51 
52   if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
53     if (packet_info_interested.IsSet(QuicUdpPacketInfoBit::V4_SELF_IP)) {
54       const in_pktinfo* info = reinterpret_cast<in_pktinfo*>(CMSG_DATA(cmsg));
55       const char* addr_data = reinterpret_cast<const char*>(&info->ipi_addr);
56       int addr_len = sizeof(in_addr);
57       QuicIpAddress self_v4_ip;
58       if (self_v4_ip.FromPackedString(addr_data, addr_len)) {
59         packet_info->SetSelfV4Ip(self_v4_ip);
60       } else {
61         QUIC_BUG(quic_bug_10751_2) << "QuicIpAddress::FromPackedString failed";
62       }
63     }
64     return;
65   }
66 }
67 
68 }  // namespace
69 }  // namespace quic
70 
71 #if defined(_WIN32)
72 #include "quiche/quic/core/quic_udp_socket_win.inc"
73 #else
74 #include "quiche/quic/core/quic_udp_socket_posix.inc"
75 #endif
76 
77 namespace quic {
78 
Create(int address_family,int receive_buffer_size,int send_buffer_size,bool ipv6_only)79 QuicUdpSocketFd QuicUdpSocketApi::Create(int address_family,
80                                          int receive_buffer_size,
81                                          int send_buffer_size, bool ipv6_only) {
82   // QUICHE_DCHECK here so the program exits early(before reading packets) in
83   // debug mode. This should have been a static_assert, however it can't be done
84   // on ios/osx because CMSG_SPACE isn't a constant expression there.
85   QUICHE_DCHECK_GE(kDefaultUdpPacketControlBufferSize, kMinCmsgSpaceForRead);
86 
87   absl::StatusOr<SocketFd> socket = socket_api::CreateSocket(
88       quiche::FromPlatformAddressFamily(address_family),
89       socket_api::SocketProtocol::kUdp,
90       /*blocking=*/false);
91 
92   if (!socket.ok()) {
93     QUIC_LOG_FIRST_N(ERROR, 100)
94         << "UDP non-blocking socket creation for address_family="
95         << address_family << " failed: " << socket.status();
96     return kQuicInvalidSocketFd;
97   }
98 
99 #if !defined(_WIN32)
100   SetGoogleSocketOptions(*socket);
101 #endif
102 
103   if (!SetupSocket(*socket, address_family, receive_buffer_size,
104                    send_buffer_size, ipv6_only)) {
105     Destroy(*socket);
106     return kQuicInvalidSocketFd;
107   }
108 
109   return *socket;
110 }
111 
Destroy(QuicUdpSocketFd fd)112 void QuicUdpSocketApi::Destroy(QuicUdpSocketFd fd) {
113   if (fd != kQuicInvalidSocketFd) {
114     absl::Status result = socket_api::Close(fd);
115     if (!result.ok()) {
116       QUIC_LOG_FIRST_N(WARNING, 100)
117           << "Failed to close UDP socket with error " << result;
118     }
119   }
120 }
121 
Bind(QuicUdpSocketFd fd,QuicSocketAddress address)122 bool QuicUdpSocketApi::Bind(QuicUdpSocketFd fd, QuicSocketAddress address) {
123   sockaddr_storage addr = address.generic_address();
124   int addr_len =
125       address.host().IsIPv4() ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);
126   return 0 == bind(fd, reinterpret_cast<sockaddr*>(&addr), addr_len);
127 }
128 
BindInterface(QuicUdpSocketFd fd,const std::string & interface_name)129 bool QuicUdpSocketApi::BindInterface(QuicUdpSocketFd fd,
130                                      const std::string& interface_name) {
131 #if defined(__linux__) && !defined(__ANDROID_API__)
132   if (interface_name.empty() || interface_name.size() >= IFNAMSIZ) {
133     QUIC_BUG(udp_bad_interface_name)
134         << "interface_name must be nonempty and shorter than " << IFNAMSIZ;
135     return false;
136   }
137 
138   return 0 == setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
139                          interface_name.c_str(), interface_name.length());
140 #else
141   (void)fd;
142   (void)interface_name;
143   QUIC_BUG(interface_bind_not_implemented)
144       << "Interface binding is not implemented on this platform";
145   return false;
146 #endif
147 }
148 
EnableDroppedPacketCount(QuicUdpSocketFd fd)149 bool QuicUdpSocketApi::EnableDroppedPacketCount(QuicUdpSocketFd fd) {
150 #if defined(__linux__) && defined(SO_RXQ_OVFL)
151   int get_overflow = 1;
152   return 0 == setsockopt(fd, SOL_SOCKET, SO_RXQ_OVFL, &get_overflow,
153                          sizeof(get_overflow));
154 #else
155   (void)fd;
156   return false;
157 #endif
158 }
159 
EnableReceiveSelfIpAddressForV4(QuicUdpSocketFd fd)160 bool QuicUdpSocketApi::EnableReceiveSelfIpAddressForV4(QuicUdpSocketFd fd) {
161   int get_self_ip = 1;
162   return 0 == setsockopt(fd, IPPROTO_IP, IP_PKTINFO,
163                          reinterpret_cast<char*>(&get_self_ip),
164                          sizeof(get_self_ip));
165 }
166 
EnableReceiveSelfIpAddressForV6(QuicUdpSocketFd fd)167 bool QuicUdpSocketApi::EnableReceiveSelfIpAddressForV6(QuicUdpSocketFd fd) {
168   int get_self_ip = 1;
169   return 0 == setsockopt(fd, IPPROTO_IPV6, kIpv6RecvPacketInfo,
170                          reinterpret_cast<char*>(&get_self_ip),
171                          sizeof(get_self_ip));
172 }
173 
EnableReceiveTimestamp(QuicUdpSocketFd fd)174 bool QuicUdpSocketApi::EnableReceiveTimestamp(QuicUdpSocketFd fd) {
175 #if defined(QUIC_UDP_SOCKET_SUPPORT_LINUX_TIMESTAMPING)
176   int timestamping = SOF_TIMESTAMPING_RX_SOFTWARE | SOF_TIMESTAMPING_SOFTWARE;
177   return 0 == setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, &timestamping,
178                          sizeof(timestamping));
179 #else
180   (void)fd;
181   return false;
182 #endif
183 }
184 
EnableReceiveTtlForV4(QuicUdpSocketFd fd)185 bool QuicUdpSocketApi::EnableReceiveTtlForV4(QuicUdpSocketFd fd) {
186 #if defined(QUIC_UDP_SOCKET_SUPPORT_TTL)
187   int get_ttl = 1;
188   return 0 == setsockopt(fd, IPPROTO_IP, IP_RECVTTL, &get_ttl, sizeof(get_ttl));
189 #else
190   (void)fd;
191   return false;
192 #endif
193 }
194 
EnableReceiveTtlForV6(QuicUdpSocketFd fd)195 bool QuicUdpSocketApi::EnableReceiveTtlForV6(QuicUdpSocketFd fd) {
196 #if defined(QUIC_UDP_SOCKET_SUPPORT_TTL)
197   int get_ttl = 1;
198   return 0 == setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &get_ttl,
199                          sizeof(get_ttl));
200 #else
201   (void)fd;
202   return false;
203 #endif
204 }
205 
206 }  // namespace quic
207