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