xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/quic_linux_socket_utils.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 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 #ifndef QUICHE_QUIC_CORE_QUIC_LINUX_SOCKET_UTILS_H_
6 #define QUICHE_QUIC_CORE_QUIC_LINUX_SOCKET_UTILS_H_
7 
8 #include <errno.h>
9 #include <stddef.h>
10 #include <string.h>
11 #include <sys/socket.h>
12 #include <sys/uio.h>
13 
14 #include <deque>
15 #include <functional>
16 #include <iterator>
17 #include <memory>
18 #include <type_traits>
19 #include <utility>
20 
21 #include "quiche/quic/core/quic_packet_writer.h"
22 #include "quiche/quic/core/quic_types.h"
23 #include "quiche/quic/platform/api/quic_bug_tracker.h"
24 #include "quiche/quic/platform/api/quic_ip_address.h"
25 #include "quiche/quic/platform/api/quic_logging.h"
26 #include "quiche/quic/platform/api/quic_socket_address.h"
27 #include "quiche/common/quiche_callbacks.h"
28 
29 #ifndef SOL_UDP
30 #define SOL_UDP 17
31 #endif
32 
33 #ifndef UDP_SEGMENT
34 #define UDP_SEGMENT 103
35 #endif
36 
37 #ifndef UDP_MAX_SEGMENTS
38 #define UDP_MAX_SEGMENTS (1 << 6UL)
39 #endif
40 
41 #ifndef SO_TXTIME
42 #define SO_TXTIME 61
43 #endif
44 
45 namespace quic {
46 
47 inline constexpr int kCmsgSpaceForIpv4 = CMSG_SPACE(sizeof(in_pktinfo));
48 inline constexpr int kCmsgSpaceForIpv6 = CMSG_SPACE(sizeof(in6_pktinfo));
49 // kCmsgSpaceForIp should be big enough to hold both IPv4 and IPv6 packet info.
50 inline constexpr int kCmsgSpaceForIp = (kCmsgSpaceForIpv4 < kCmsgSpaceForIpv6)
51                                            ? kCmsgSpaceForIpv6
52                                            : kCmsgSpaceForIpv4;
53 
54 inline constexpr int kCmsgSpaceForSegmentSize = CMSG_SPACE(sizeof(uint16_t));
55 
56 inline constexpr int kCmsgSpaceForTxTime = CMSG_SPACE(sizeof(uint64_t));
57 
58 inline constexpr int kCmsgSpaceForTTL = CMSG_SPACE(sizeof(int));
59 
60 inline constexpr int kCmsgSpaceForTOS = CMSG_SPACE(sizeof(int));
61 
62 // QuicMsgHdr is used to build msghdr objects that can be used send packets via
63 // ::sendmsg.
64 //
65 // Example:
66 //   // cbuf holds control messages(cmsgs). The size is determined from what
67 //   // cmsgs will be set for this msghdr.
68 //   char cbuf[kCmsgSpaceForIp + kCmsgSpaceForSegmentSize];
69 //   QuicMsgHdr hdr(packet_buf, packet_buf_len, peer_addr, cbuf, sizeof(cbuf));
70 //
71 //   // Set IP in cmsgs.
72 //   hdr.SetIpInNextCmsg(self_addr);
73 //
74 //   // Set GSO size in cmsgs.
75 //   *hdr.GetNextCmsgData<uint16_t>(SOL_UDP, UDP_SEGMENT) = 1200;
76 //
77 //   QuicLinuxSocketUtils::WritePacket(fd, hdr);
78 class QUICHE_EXPORT QuicMsgHdr {
79  public:
80   QuicMsgHdr(const char* buffer, size_t buf_len,
81              const QuicSocketAddress& peer_address, char* cbuf,
82              size_t cbuf_size);
83 
84   // Set IP info in the next cmsg. Both IPv4 and IPv6 are supported.
85   void SetIpInNextCmsg(const QuicIpAddress& self_address);
86 
87   template <typename DataType>
GetNextCmsgData(int cmsg_level,int cmsg_type)88   DataType* GetNextCmsgData(int cmsg_level, int cmsg_type) {
89     return reinterpret_cast<DataType*>(
90         GetNextCmsgDataInternal(cmsg_level, cmsg_type, sizeof(DataType)));
91   }
92 
hdr()93   const msghdr* hdr() const { return &hdr_; }
94 
95  protected:
96   void* GetNextCmsgDataInternal(int cmsg_level, int cmsg_type,
97                                 size_t data_size);
98 
99   msghdr hdr_;
100   iovec iov_;
101   sockaddr_storage raw_peer_address_;
102   char* cbuf_;
103   const size_t cbuf_size_;
104   // The last cmsg populated so far. nullptr means nothing has been populated.
105   cmsghdr* cmsg_;
106 };
107 
108 // BufferedWrite holds all information needed to send a packet.
109 struct QUICHE_EXPORT BufferedWrite {
BufferedWriteBufferedWrite110   BufferedWrite(const char* buffer, size_t buf_len,
111                 const QuicIpAddress& self_address,
112                 const QuicSocketAddress& peer_address)
113       : BufferedWrite(buffer, buf_len, self_address, peer_address,
114                       std::unique_ptr<PerPacketOptions>(),
115                       QuicPacketWriterParams(), /*release_time=*/0) {}
116 
BufferedWriteBufferedWrite117   BufferedWrite(const char* buffer, size_t buf_len,
118                 const QuicIpAddress& self_address,
119                 const QuicSocketAddress& peer_address,
120                 std::unique_ptr<PerPacketOptions> options,
121                 const QuicPacketWriterParams& params, uint64_t release_time)
122       : buffer(buffer),
123         buf_len(buf_len),
124         self_address(self_address),
125         peer_address(peer_address),
126         options(std::move(options)),
127         params(params),
128         release_time(release_time) {}
129 
130   const char* buffer;  // Not owned.
131   size_t buf_len;
132   QuicIpAddress self_address;
133   QuicSocketAddress peer_address;
134   std::unique_ptr<PerPacketOptions> options;
135   QuicPacketWriterParams params;
136 
137   // The release time according to the owning packet writer's clock, which is
138   // often not a QuicClock. Calculated from packet writer's Now() and the
139   // release time delay in |options|.
140   // 0 means it can be sent at the same time as the previous packet in a batch,
141   // or can be sent Now() if this is the first packet of a batch.
142   uint64_t release_time;
143 };
144 
145 // QuicMMsgHdr is used to build mmsghdr objects that can be used to send
146 // multiple packets at once via ::sendmmsg.
147 //
148 // Example:
149 //   quiche::QuicheCircularDeque<BufferedWrite> buffered_writes;
150 //   ... (Populate buffered_writes) ...
151 //
152 //   QuicMMsgHdr mhdr(
153 //       buffered_writes.begin(), buffered_writes.end(), kCmsgSpaceForIp,
154 //       [](QuicMMsgHdr* mhdr, int i, const BufferedWrite& buffered_write) {
155 //         mhdr->SetIpInNextCmsg(i, buffered_write.self_address);
156 //       });
157 //
158 //   int num_packets_sent;
159 //   QuicSocketUtils::WriteMultiplePackets(fd, &mhdr, &num_packets_sent);
160 class QUICHE_EXPORT QuicMMsgHdr {
161  public:
162   using ControlBufferInitializer = quiche::UnretainedCallback<void(
163       QuicMMsgHdr* mhdr, int i, const BufferedWrite& buffered_write)>;
164   template <typename IteratorT>
165   QuicMMsgHdr(
166       const IteratorT& first, const IteratorT& last, size_t cbuf_size,
167       ControlBufferInitializer cbuf_initializer =
168           +[](quic::QuicMMsgHdr*, int, const quic::BufferedWrite&) {})
num_msgs_(std::distance (first,last))169       : num_msgs_(std::distance(first, last)), cbuf_size_(cbuf_size) {
170     static_assert(
171         std::is_same<typename std::iterator_traits<IteratorT>::value_type,
172                      BufferedWrite>::value,
173         "Must iterate over a collection of BufferedWrite.");
174 
175     QUICHE_DCHECK_LE(0, num_msgs_);
176     if (num_msgs_ == 0) {
177       return;
178     }
179 
180     storage_.reset(new char[StorageSize()]);
181     memset(&storage_[0], 0, StorageSize());
182 
183     int i = -1;
184     for (auto it = first; it != last; ++it) {
185       ++i;
186 
187       InitOneHeader(i, *it);
188       cbuf_initializer(this, i, *it);
189     }
190   }
191 
192   void SetIpInNextCmsg(int i, const QuicIpAddress& self_address);
193 
194   template <typename DataType>
GetNextCmsgData(int i,int cmsg_level,int cmsg_type)195   DataType* GetNextCmsgData(int i, int cmsg_level, int cmsg_type) {
196     return reinterpret_cast<DataType*>(
197         GetNextCmsgDataInternal(i, cmsg_level, cmsg_type, sizeof(DataType)));
198   }
199 
mhdr()200   mmsghdr* mhdr() { return GetMMsgHdr(0); }
201 
num_msgs()202   int num_msgs() const { return num_msgs_; }
203 
204   // Get the total number of bytes in the first |num_packets_sent| packets.
205   int num_bytes_sent(int num_packets_sent);
206 
207  protected:
208   void InitOneHeader(int i, const BufferedWrite& buffered_write);
209 
210   void* GetNextCmsgDataInternal(int i, int cmsg_level, int cmsg_type,
211                                 size_t data_size);
212 
StorageSize()213   size_t StorageSize() const {
214     return num_msgs_ *
215            (sizeof(mmsghdr) + sizeof(iovec) + sizeof(sockaddr_storage) +
216             sizeof(cmsghdr*) + cbuf_size_);
217   }
218 
GetMMsgHdr(int i)219   mmsghdr* GetMMsgHdr(int i) {
220     auto* first = reinterpret_cast<mmsghdr*>(&storage_[0]);
221     return &first[i];
222   }
223 
GetIov(int i)224   iovec* GetIov(int i) {
225     auto* first = reinterpret_cast<iovec*>(GetMMsgHdr(num_msgs_));
226     return &first[i];
227   }
228 
GetPeerAddressStorage(int i)229   sockaddr_storage* GetPeerAddressStorage(int i) {
230     auto* first = reinterpret_cast<sockaddr_storage*>(GetIov(num_msgs_));
231     return &first[i];
232   }
233 
GetCmsgHdr(int i)234   cmsghdr** GetCmsgHdr(int i) {
235     auto* first = reinterpret_cast<cmsghdr**>(GetPeerAddressStorage(num_msgs_));
236     return &first[i];
237   }
238 
GetCbuf(int i)239   char* GetCbuf(int i) {
240     auto* first = reinterpret_cast<char*>(GetCmsgHdr(num_msgs_));
241     return &first[i * cbuf_size_];
242   }
243 
244   const int num_msgs_;
245   // Size of cmsg buffer for each message.
246   const size_t cbuf_size_;
247   // storage_ holds the memory of
248   // |num_msgs_| mmsghdr
249   // |num_msgs_| iovec
250   // |num_msgs_| sockaddr_storage, for peer addresses
251   // |num_msgs_| cmsghdr*
252   // |num_msgs_| cbuf, each of size cbuf_size
253   std::unique_ptr<char[]> storage_;
254 };
255 
256 class QUICHE_EXPORT QuicLinuxSocketUtils {
257  public:
258   // Return the UDP segment size of |fd|, 0 means segment size has not been set
259   // on this socket. If GSO is not supported, return -1.
260   static int GetUDPSegmentSize(int fd);
261 
262   // Enable release time on |fd|.
263   static bool EnableReleaseTime(int fd, clockid_t clockid);
264 
265   // If the msghdr contains an IP_TTL entry, this will set ttl to the correct
266   // value and return true. Otherwise it will return false.
267   static bool GetTtlFromMsghdr(struct msghdr* hdr, int* ttl);
268 
269   // Set IP(self_address) in |cmsg_data|. Does not touch other fields in the
270   // containing cmsghdr.
271   static void SetIpInfoInCmsgData(const QuicIpAddress& self_address,
272                                   void* cmsg_data);
273 
274   // A helper for WritePacket which fills in the cmsg with the supplied self
275   // address.
276   // Returns the length of the packet info structure used.
277   static size_t SetIpInfoInCmsg(const QuicIpAddress& self_address,
278                                 cmsghdr* cmsg);
279 
280   // Writes the packet in |hdr| to the socket, using ::sendmsg.
281   static WriteResult WritePacket(int fd, const QuicMsgHdr& hdr);
282 
283   // Writes the packets in |mhdr| to the socket, using ::sendmmsg if available.
284   static WriteResult WriteMultiplePackets(int fd, QuicMMsgHdr* mhdr,
285                                           int* num_packets_sent);
286 };
287 
288 }  // namespace quic
289 
290 #endif  // QUICHE_QUIC_CORE_QUIC_LINUX_SOCKET_UTILS_H_
291