• 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 #include "quiche/quic/core/quic_linux_socket_utils.h"
6 
7 #include <netinet/in.h>
8 #include <stdint.h>
9 
10 #include <cstddef>
11 #include <sstream>
12 #include <string>
13 #include <vector>
14 
15 #include "quiche/quic/platform/api/quic_test.h"
16 #include "quiche/quic/test_tools/quic_mock_syscall_wrapper.h"
17 #include "quiche/common/quiche_circular_deque.h"
18 
19 using testing::_;
20 using testing::InSequence;
21 using testing::Invoke;
22 
23 namespace quic {
24 namespace test {
25 namespace {
26 
27 class QuicLinuxSocketUtilsTest : public QuicTest {
28  protected:
TestWriteMultiplePackets(int fd,const quiche::QuicheCircularDeque<BufferedWrite>::const_iterator & first,const quiche::QuicheCircularDeque<BufferedWrite>::const_iterator & last,int * num_packets_sent)29   WriteResult TestWriteMultiplePackets(
30       int fd,
31       const quiche::QuicheCircularDeque<BufferedWrite>::const_iterator& first,
32       const quiche::QuicheCircularDeque<BufferedWrite>::const_iterator& last,
33       int* num_packets_sent) {
34     QuicMMsgHdr mhdr(
35         first, last, kCmsgSpaceForIp,
36         [](QuicMMsgHdr* mhdr, int i, const BufferedWrite& buffered_write) {
37           mhdr->SetIpInNextCmsg(i, buffered_write.self_address);
38         });
39 
40     WriteResult res =
41         QuicLinuxSocketUtils::WriteMultiplePackets(fd, &mhdr, num_packets_sent);
42     return res;
43   }
44 
45   MockQuicSyscallWrapper mock_syscalls_;
46   ScopedGlobalSyscallWrapperOverride syscall_override_{&mock_syscalls_};
47 };
48 
CheckIpAndTtlInCbuf(msghdr * hdr,const void * cbuf,const QuicIpAddress & self_addr,int ttl)49 void CheckIpAndTtlInCbuf(msghdr* hdr, const void* cbuf,
50                          const QuicIpAddress& self_addr, int ttl) {
51   const bool is_ipv4 = self_addr.IsIPv4();
52   const size_t ip_cmsg_space = is_ipv4 ? kCmsgSpaceForIpv4 : kCmsgSpaceForIpv6;
53 
54   EXPECT_EQ(cbuf, hdr->msg_control);
55   EXPECT_EQ(ip_cmsg_space + CMSG_SPACE(sizeof(uint16_t)), hdr->msg_controllen);
56 
57   cmsghdr* cmsg = CMSG_FIRSTHDR(hdr);
58   EXPECT_EQ(cmsg->cmsg_len, is_ipv4 ? CMSG_LEN(sizeof(in_pktinfo))
59                                     : CMSG_LEN(sizeof(in6_pktinfo)));
60   EXPECT_EQ(cmsg->cmsg_level, is_ipv4 ? IPPROTO_IP : IPPROTO_IPV6);
61   EXPECT_EQ(cmsg->cmsg_type, is_ipv4 ? IP_PKTINFO : IPV6_PKTINFO);
62 
63   const std::string& self_addr_str = self_addr.ToPackedString();
64   if (is_ipv4) {
65     in_pktinfo* pktinfo = reinterpret_cast<in_pktinfo*>(CMSG_DATA(cmsg));
66     EXPECT_EQ(0, memcmp(&pktinfo->ipi_spec_dst, self_addr_str.c_str(),
67                         self_addr_str.length()));
68   } else {
69     in6_pktinfo* pktinfo = reinterpret_cast<in6_pktinfo*>(CMSG_DATA(cmsg));
70     EXPECT_EQ(0, memcmp(&pktinfo->ipi6_addr, self_addr_str.c_str(),
71                         self_addr_str.length()));
72   }
73 
74   cmsg = CMSG_NXTHDR(hdr, cmsg);
75   EXPECT_EQ(cmsg->cmsg_len, CMSG_LEN(sizeof(int)));
76   EXPECT_EQ(cmsg->cmsg_level, is_ipv4 ? IPPROTO_IP : IPPROTO_IPV6);
77   EXPECT_EQ(cmsg->cmsg_type, is_ipv4 ? IP_TTL : IPV6_HOPLIMIT);
78   EXPECT_EQ(ttl, *reinterpret_cast<int*>(CMSG_DATA(cmsg)));
79 
80   EXPECT_EQ(nullptr, CMSG_NXTHDR(hdr, cmsg));
81 }
82 
CheckMsghdrWithoutCbuf(const msghdr * hdr,const void * buffer,size_t buf_len,const QuicSocketAddress & peer_addr)83 void CheckMsghdrWithoutCbuf(const msghdr* hdr, const void* buffer,
84                             size_t buf_len,
85                             const QuicSocketAddress& peer_addr) {
86   EXPECT_EQ(
87       peer_addr.host().IsIPv4() ? sizeof(sockaddr_in) : sizeof(sockaddr_in6),
88       hdr->msg_namelen);
89   sockaddr_storage peer_generic_addr = peer_addr.generic_address();
90   EXPECT_EQ(0, memcmp(hdr->msg_name, &peer_generic_addr, hdr->msg_namelen));
91   EXPECT_EQ(1u, hdr->msg_iovlen);
92   EXPECT_EQ(buffer, hdr->msg_iov->iov_base);
93   EXPECT_EQ(buf_len, hdr->msg_iov->iov_len);
94   EXPECT_EQ(0, hdr->msg_flags);
95   EXPECT_EQ(nullptr, hdr->msg_control);
96   EXPECT_EQ(0u, hdr->msg_controllen);
97 }
98 
CheckIpAndGsoSizeInCbuf(msghdr * hdr,const void * cbuf,const QuicIpAddress & self_addr,uint16_t gso_size)99 void CheckIpAndGsoSizeInCbuf(msghdr* hdr, const void* cbuf,
100                              const QuicIpAddress& self_addr,
101                              uint16_t gso_size) {
102   const bool is_ipv4 = self_addr.IsIPv4();
103   const size_t ip_cmsg_space = is_ipv4 ? kCmsgSpaceForIpv4 : kCmsgSpaceForIpv6;
104 
105   EXPECT_EQ(cbuf, hdr->msg_control);
106   EXPECT_EQ(ip_cmsg_space + CMSG_SPACE(sizeof(uint16_t)), hdr->msg_controllen);
107 
108   cmsghdr* cmsg = CMSG_FIRSTHDR(hdr);
109   EXPECT_EQ(cmsg->cmsg_len, is_ipv4 ? CMSG_LEN(sizeof(in_pktinfo))
110                                     : CMSG_LEN(sizeof(in6_pktinfo)));
111   EXPECT_EQ(cmsg->cmsg_level, is_ipv4 ? IPPROTO_IP : IPPROTO_IPV6);
112   EXPECT_EQ(cmsg->cmsg_type, is_ipv4 ? IP_PKTINFO : IPV6_PKTINFO);
113 
114   const std::string& self_addr_str = self_addr.ToPackedString();
115   if (is_ipv4) {
116     in_pktinfo* pktinfo = reinterpret_cast<in_pktinfo*>(CMSG_DATA(cmsg));
117     EXPECT_EQ(0, memcmp(&pktinfo->ipi_spec_dst, self_addr_str.c_str(),
118                         self_addr_str.length()));
119   } else {
120     in6_pktinfo* pktinfo = reinterpret_cast<in6_pktinfo*>(CMSG_DATA(cmsg));
121     EXPECT_EQ(0, memcmp(&pktinfo->ipi6_addr, self_addr_str.c_str(),
122                         self_addr_str.length()));
123   }
124 
125   cmsg = CMSG_NXTHDR(hdr, cmsg);
126   EXPECT_EQ(cmsg->cmsg_len, CMSG_LEN(sizeof(uint16_t)));
127   EXPECT_EQ(cmsg->cmsg_level, SOL_UDP);
128   EXPECT_EQ(cmsg->cmsg_type, UDP_SEGMENT);
129   EXPECT_EQ(gso_size, *reinterpret_cast<uint16_t*>(CMSG_DATA(cmsg)));
130 
131   EXPECT_EQ(nullptr, CMSG_NXTHDR(hdr, cmsg));
132 }
133 
TEST_F(QuicLinuxSocketUtilsTest,QuicMsgHdr)134 TEST_F(QuicLinuxSocketUtilsTest, QuicMsgHdr) {
135   QuicSocketAddress peer_addr(QuicIpAddress::Loopback4(), 1234);
136   char packet_buf[1024];
137 
138   QuicMsgHdr quic_hdr(packet_buf, sizeof(packet_buf), peer_addr, nullptr, 0);
139   CheckMsghdrWithoutCbuf(quic_hdr.hdr(), packet_buf, sizeof(packet_buf),
140                          peer_addr);
141 
142   for (bool is_ipv4 : {true, false}) {
143     QuicIpAddress self_addr =
144         is_ipv4 ? QuicIpAddress::Loopback4() : QuicIpAddress::Loopback6();
145     alignas(cmsghdr) char cbuf[kCmsgSpaceForIp + kCmsgSpaceForTTL];
146     QuicMsgHdr quic_hdr(packet_buf, sizeof(packet_buf), peer_addr, cbuf,
147                         sizeof(cbuf));
148     msghdr* hdr = const_cast<msghdr*>(quic_hdr.hdr());
149 
150     EXPECT_EQ(nullptr, hdr->msg_control);
151     EXPECT_EQ(0u, hdr->msg_controllen);
152 
153     quic_hdr.SetIpInNextCmsg(self_addr);
154     EXPECT_EQ(cbuf, hdr->msg_control);
155     const size_t ip_cmsg_space =
156         is_ipv4 ? kCmsgSpaceForIpv4 : kCmsgSpaceForIpv6;
157     EXPECT_EQ(ip_cmsg_space, hdr->msg_controllen);
158 
159     if (is_ipv4) {
160       *quic_hdr.GetNextCmsgData<int>(IPPROTO_IP, IP_TTL) = 32;
161     } else {
162       *quic_hdr.GetNextCmsgData<int>(IPPROTO_IPV6, IPV6_HOPLIMIT) = 32;
163     }
164 
165     CheckIpAndTtlInCbuf(hdr, cbuf, self_addr, 32);
166   }
167 }
168 
TEST_F(QuicLinuxSocketUtilsTest,QuicMMsgHdr)169 TEST_F(QuicLinuxSocketUtilsTest, QuicMMsgHdr) {
170   quiche::QuicheCircularDeque<BufferedWrite> buffered_writes;
171   char packet_buf1[1024];
172   char packet_buf2[512];
173   buffered_writes.emplace_back(
174       packet_buf1, sizeof(packet_buf1), QuicIpAddress::Loopback4(),
175       QuicSocketAddress(QuicIpAddress::Loopback4(), 4));
176   buffered_writes.emplace_back(
177       packet_buf2, sizeof(packet_buf2), QuicIpAddress::Loopback6(),
178       QuicSocketAddress(QuicIpAddress::Loopback6(), 6));
179 
180   QuicMMsgHdr quic_mhdr_without_cbuf(buffered_writes.begin(),
181                                      buffered_writes.end(), 0);
182   for (size_t i = 0; i < buffered_writes.size(); ++i) {
183     const BufferedWrite& bw = buffered_writes[i];
184     CheckMsghdrWithoutCbuf(&quic_mhdr_without_cbuf.mhdr()[i].msg_hdr, bw.buffer,
185                            bw.buf_len, bw.peer_address);
186   }
187 
188   QuicMMsgHdr quic_mhdr_with_cbuf(
189       buffered_writes.begin(), buffered_writes.end(),
190       kCmsgSpaceForIp + kCmsgSpaceForSegmentSize,
191       [](QuicMMsgHdr* mhdr, int i, const BufferedWrite& buffered_write) {
192         mhdr->SetIpInNextCmsg(i, buffered_write.self_address);
193         *mhdr->GetNextCmsgData<uint16_t>(i, SOL_UDP, UDP_SEGMENT) = 1300;
194       });
195   for (size_t i = 0; i < buffered_writes.size(); ++i) {
196     const BufferedWrite& bw = buffered_writes[i];
197     msghdr* hdr = &quic_mhdr_with_cbuf.mhdr()[i].msg_hdr;
198     CheckIpAndGsoSizeInCbuf(hdr, hdr->msg_control, bw.self_address, 1300);
199   }
200 }
201 
TEST_F(QuicLinuxSocketUtilsTest,WriteMultiplePackets_NoPacketsToSend)202 TEST_F(QuicLinuxSocketUtilsTest, WriteMultiplePackets_NoPacketsToSend) {
203   int num_packets_sent;
204   quiche::QuicheCircularDeque<BufferedWrite> buffered_writes;
205 
206   EXPECT_CALL(mock_syscalls_, Sendmmsg(_, _, _, _)).Times(0);
207 
208   EXPECT_EQ(WriteResult(WRITE_STATUS_ERROR, EINVAL),
209             TestWriteMultiplePackets(1, buffered_writes.begin(),
210                                      buffered_writes.end(), &num_packets_sent));
211 }
212 
TEST_F(QuicLinuxSocketUtilsTest,WriteMultiplePackets_WriteBlocked)213 TEST_F(QuicLinuxSocketUtilsTest, WriteMultiplePackets_WriteBlocked) {
214   int num_packets_sent;
215   quiche::QuicheCircularDeque<BufferedWrite> buffered_writes;
216   buffered_writes.emplace_back(nullptr, 0, QuicIpAddress(),
217                                QuicSocketAddress(QuicIpAddress::Any4(), 0));
218 
219   EXPECT_CALL(mock_syscalls_, Sendmmsg(_, _, _, _))
220       .WillOnce(Invoke([](int /*fd*/, mmsghdr* /*msgvec*/,
221                           unsigned int /*vlen*/, int /*flags*/) {
222         errno = EWOULDBLOCK;
223         return -1;
224       }));
225 
226   EXPECT_EQ(WriteResult(WRITE_STATUS_BLOCKED, EWOULDBLOCK),
227             TestWriteMultiplePackets(1, buffered_writes.begin(),
228                                      buffered_writes.end(), &num_packets_sent));
229   EXPECT_EQ(0, num_packets_sent);
230 }
231 
TEST_F(QuicLinuxSocketUtilsTest,WriteMultiplePackets_WriteError)232 TEST_F(QuicLinuxSocketUtilsTest, WriteMultiplePackets_WriteError) {
233   int num_packets_sent;
234   quiche::QuicheCircularDeque<BufferedWrite> buffered_writes;
235   buffered_writes.emplace_back(nullptr, 0, QuicIpAddress(),
236                                QuicSocketAddress(QuicIpAddress::Any4(), 0));
237 
238   EXPECT_CALL(mock_syscalls_, Sendmmsg(_, _, _, _))
239       .WillOnce(Invoke([](int /*fd*/, mmsghdr* /*msgvec*/,
240                           unsigned int /*vlen*/, int /*flags*/) {
241         errno = EPERM;
242         return -1;
243       }));
244 
245   EXPECT_EQ(WriteResult(WRITE_STATUS_ERROR, EPERM),
246             TestWriteMultiplePackets(1, buffered_writes.begin(),
247                                      buffered_writes.end(), &num_packets_sent));
248   EXPECT_EQ(0, num_packets_sent);
249 }
250 
TEST_F(QuicLinuxSocketUtilsTest,WriteMultiplePackets_WriteSuccess)251 TEST_F(QuicLinuxSocketUtilsTest, WriteMultiplePackets_WriteSuccess) {
252   int num_packets_sent;
253   quiche::QuicheCircularDeque<BufferedWrite> buffered_writes;
254   const int kNumBufferedWrites = 10;
255   static_assert(kNumBufferedWrites < 256, "Must be less than 256");
256   std::vector<std::string> buffer_holder;
257   for (int i = 0; i < kNumBufferedWrites; ++i) {
258     size_t buf_len = (i + 1) * 2;
259     std::ostringstream buffer_ostream;
260     while (buffer_ostream.str().length() < buf_len) {
261       buffer_ostream << i;
262     }
263     buffer_holder.push_back(buffer_ostream.str().substr(0, buf_len - 1) + '$');
264 
265     buffered_writes.emplace_back(buffer_holder.back().data(), buf_len,
266                                  QuicIpAddress(),
267                                  QuicSocketAddress(QuicIpAddress::Any4(), 0));
268 
269     // Leave the first self_address uninitialized.
270     if (i != 0) {
271       ASSERT_TRUE(buffered_writes.back().self_address.FromString("127.0.0.1"));
272     }
273 
274     std::ostringstream peer_ip_ostream;
275     QuicIpAddress peer_ip_address;
276     peer_ip_ostream << "127.0.1." << i + 1;
277     ASSERT_TRUE(peer_ip_address.FromString(peer_ip_ostream.str()));
278     buffered_writes.back().peer_address =
279         QuicSocketAddress(peer_ip_address, i + 1);
280   }
281 
282   InSequence s;
283 
284   for (int expected_num_packets_sent : {1, 2, 3, 10}) {
285     SCOPED_TRACE(testing::Message()
286                  << "expected_num_packets_sent=" << expected_num_packets_sent);
287     EXPECT_CALL(mock_syscalls_, Sendmmsg(_, _, _, _))
288         .WillOnce(Invoke([&](int /*fd*/, mmsghdr* msgvec, unsigned int vlen,
289                              int /*flags*/) {
290           EXPECT_LE(static_cast<unsigned int>(expected_num_packets_sent), vlen);
291           for (unsigned int i = 0; i < vlen; ++i) {
292             const BufferedWrite& buffered_write = buffered_writes[i];
293             const msghdr& hdr = msgvec[i].msg_hdr;
294             EXPECT_EQ(1u, hdr.msg_iovlen);
295             EXPECT_EQ(buffered_write.buffer, hdr.msg_iov->iov_base);
296             EXPECT_EQ(buffered_write.buf_len, hdr.msg_iov->iov_len);
297             sockaddr_storage expected_peer_address =
298                 buffered_write.peer_address.generic_address();
299             EXPECT_EQ(0, memcmp(&expected_peer_address, hdr.msg_name,
300                                 sizeof(sockaddr_storage)));
301             EXPECT_EQ(buffered_write.self_address.IsInitialized(),
302                       hdr.msg_control != nullptr);
303           }
304           return expected_num_packets_sent;
305         }))
306         .RetiresOnSaturation();
307 
308     int expected_bytes_written = 0;
309     for (auto it = buffered_writes.cbegin();
310          it != buffered_writes.cbegin() + expected_num_packets_sent; ++it) {
311       expected_bytes_written += it->buf_len;
312     }
313 
314     EXPECT_EQ(
315         WriteResult(WRITE_STATUS_OK, expected_bytes_written),
316         TestWriteMultiplePackets(1, buffered_writes.cbegin(),
317                                  buffered_writes.cend(), &num_packets_sent));
318     EXPECT_EQ(expected_num_packets_sent, num_packets_sent);
319   }
320 }
321 
322 }  // namespace
323 }  // namespace test
324 }  // namespace quic
325