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