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/batch_writer/quic_gso_batch_writer.h"
6
7 #include <sys/socket.h>
8
9 #include <cstdint>
10 #include <limits>
11 #include <memory>
12 #include <utility>
13
14 #include "quiche/quic/platform/api/quic_ip_address.h"
15 #include "quiche/quic/platform/api/quic_test.h"
16 #include "quiche/quic/test_tools/quic_mock_syscall_wrapper.h"
17
18 using testing::_;
19 using testing::Invoke;
20 using testing::StrictMock;
21
22 namespace quic {
23 namespace test {
24 namespace {
25
PacketLength(const msghdr * msg)26 size_t PacketLength(const msghdr* msg) {
27 size_t length = 0;
28 for (size_t i = 0; i < msg->msg_iovlen; ++i) {
29 length += msg->msg_iov[i].iov_len;
30 }
31 return length;
32 }
33
MillisToNanos(uint64_t milliseconds)34 uint64_t MillisToNanos(uint64_t milliseconds) { return milliseconds * 1000000; }
35
36 class QUICHE_EXPORT TestQuicGsoBatchWriter : public QuicGsoBatchWriter {
37 public:
38 using QuicGsoBatchWriter::batch_buffer;
39 using QuicGsoBatchWriter::buffered_writes;
40 using QuicGsoBatchWriter::CanBatch;
41 using QuicGsoBatchWriter::CanBatchResult;
42 using QuicGsoBatchWriter::GetReleaseTime;
43 using QuicGsoBatchWriter::MaxSegments;
44 using QuicGsoBatchWriter::QuicGsoBatchWriter;
45 using QuicGsoBatchWriter::ReleaseTime;
46
47 static std::unique_ptr<TestQuicGsoBatchWriter>
NewInstanceWithReleaseTimeSupport()48 NewInstanceWithReleaseTimeSupport() {
49 return std::unique_ptr<TestQuicGsoBatchWriter>(new TestQuicGsoBatchWriter(
50 std::make_unique<QuicBatchWriterBuffer>(),
51 /*fd=*/-1, CLOCK_MONOTONIC, ReleaseTimeForceEnabler()));
52 }
53
NowInNanosForReleaseTime() const54 uint64_t NowInNanosForReleaseTime() const override {
55 return MillisToNanos(forced_release_time_ms_);
56 }
57
ForceReleaseTimeMs(uint64_t forced_release_time_ms)58 void ForceReleaseTimeMs(uint64_t forced_release_time_ms) {
59 forced_release_time_ms_ = forced_release_time_ms;
60 }
61
62 private:
63 uint64_t forced_release_time_ms_ = 1;
64 };
65
66 // TestBufferedWrite is a copy-constructible BufferedWrite.
67 struct QUICHE_EXPORT TestBufferedWrite : public BufferedWrite {
68 using BufferedWrite::BufferedWrite;
TestBufferedWritequic::test::__anon2f819bd10111::TestBufferedWrite69 TestBufferedWrite(const TestBufferedWrite& other)
70 : BufferedWrite(other.buffer, other.buf_len, other.self_address,
71 other.peer_address,
72 other.options ? other.options->Clone()
73 : std::unique_ptr<PerPacketOptions>(),
74 QuicPacketWriterParams(), other.release_time) {}
75 };
76
77 // Pointed to by all instances of |BatchCriteriaTestData|. Content not used.
78 static char unused_packet_buffer[kMaxOutgoingPacketSize];
79
80 struct QUICHE_EXPORT BatchCriteriaTestData {
BatchCriteriaTestDataquic::test::__anon2f819bd10111::BatchCriteriaTestData81 BatchCriteriaTestData(size_t buf_len, const QuicIpAddress& self_address,
82 const QuicSocketAddress& peer_address,
83 uint64_t release_time, bool can_batch, bool must_flush)
84 : buffered_write(unused_packet_buffer, buf_len, self_address,
85 peer_address, std::unique_ptr<PerPacketOptions>(),
86 QuicPacketWriterParams(), release_time),
87 can_batch(can_batch),
88 must_flush(must_flush) {}
89
90 TestBufferedWrite buffered_write;
91 // Expected value of CanBatchResult.can_batch when batching |buffered_write|.
92 bool can_batch;
93 // Expected value of CanBatchResult.must_flush when batching |buffered_write|.
94 bool must_flush;
95 };
96
BatchCriteriaTestData_SizeDecrease()97 std::vector<BatchCriteriaTestData> BatchCriteriaTestData_SizeDecrease() {
98 const QuicIpAddress self_addr;
99 const QuicSocketAddress peer_addr;
100 std::vector<BatchCriteriaTestData> test_data_table = {
101 // clang-format off
102 // buf_len self_addr peer_addr t_rel can_batch must_flush
103 {1350, self_addr, peer_addr, 0, true, false},
104 {1350, self_addr, peer_addr, 0, true, false},
105 {1350, self_addr, peer_addr, 0, true, false},
106 {39, self_addr, peer_addr, 0, true, true},
107 {39, self_addr, peer_addr, 0, false, true},
108 {1350, self_addr, peer_addr, 0, false, true},
109 // clang-format on
110 };
111 return test_data_table;
112 }
113
BatchCriteriaTestData_SizeIncrease()114 std::vector<BatchCriteriaTestData> BatchCriteriaTestData_SizeIncrease() {
115 const QuicIpAddress self_addr;
116 const QuicSocketAddress peer_addr;
117 std::vector<BatchCriteriaTestData> test_data_table = {
118 // clang-format off
119 // buf_len self_addr peer_addr t_rel can_batch must_flush
120 {1350, self_addr, peer_addr, 0, true, false},
121 {1350, self_addr, peer_addr, 0, true, false},
122 {1350, self_addr, peer_addr, 0, true, false},
123 {1351, self_addr, peer_addr, 0, false, true},
124 // clang-format on
125 };
126 return test_data_table;
127 }
128
BatchCriteriaTestData_AddressChange()129 std::vector<BatchCriteriaTestData> BatchCriteriaTestData_AddressChange() {
130 const QuicIpAddress self_addr1 = QuicIpAddress::Loopback4();
131 const QuicIpAddress self_addr2 = QuicIpAddress::Loopback6();
132 const QuicSocketAddress peer_addr1(self_addr1, 666);
133 const QuicSocketAddress peer_addr2(self_addr1, 777);
134 const QuicSocketAddress peer_addr3(self_addr2, 666);
135 const QuicSocketAddress peer_addr4(self_addr2, 777);
136 std::vector<BatchCriteriaTestData> test_data_table = {
137 // clang-format off
138 // buf_len self_addr peer_addr t_rel can_batch must_flush
139 {1350, self_addr1, peer_addr1, 0, true, false},
140 {1350, self_addr1, peer_addr1, 0, true, false},
141 {1350, self_addr1, peer_addr1, 0, true, false},
142 {1350, self_addr2, peer_addr1, 0, false, true},
143 {1350, self_addr1, peer_addr2, 0, false, true},
144 {1350, self_addr1, peer_addr3, 0, false, true},
145 {1350, self_addr1, peer_addr4, 0, false, true},
146 {1350, self_addr1, peer_addr4, 0, false, true},
147 // clang-format on
148 };
149 return test_data_table;
150 }
151
BatchCriteriaTestData_ReleaseTime1()152 std::vector<BatchCriteriaTestData> BatchCriteriaTestData_ReleaseTime1() {
153 const QuicIpAddress self_addr;
154 const QuicSocketAddress peer_addr;
155 std::vector<BatchCriteriaTestData> test_data_table = {
156 // clang-format off
157 // buf_len self_addr peer_addr t_rel can_batch must_flush
158 {1350, self_addr, peer_addr, 5, true, false},
159 {1350, self_addr, peer_addr, 5, true, false},
160 {1350, self_addr, peer_addr, 5, true, false},
161 {1350, self_addr, peer_addr, 9, false, true},
162 // clang-format on
163 };
164 return test_data_table;
165 }
166
BatchCriteriaTestData_ReleaseTime2()167 std::vector<BatchCriteriaTestData> BatchCriteriaTestData_ReleaseTime2() {
168 const QuicIpAddress self_addr;
169 const QuicSocketAddress peer_addr;
170 std::vector<BatchCriteriaTestData> test_data_table = {
171 // clang-format off
172 // buf_len self_addr peer_addr t_rel can_batch must_flush
173 {1350, self_addr, peer_addr, 0, true, false},
174 {1350, self_addr, peer_addr, 0, true, false},
175 {1350, self_addr, peer_addr, 0, true, false},
176 {1350, self_addr, peer_addr, 9, false, true},
177 // clang-format on
178 };
179 return test_data_table;
180 }
181
BatchCriteriaTestData_MaxSegments(size_t gso_size)182 std::vector<BatchCriteriaTestData> BatchCriteriaTestData_MaxSegments(
183 size_t gso_size) {
184 const QuicIpAddress self_addr;
185 const QuicSocketAddress peer_addr;
186 std::vector<BatchCriteriaTestData> test_data_table;
187 size_t max_segments = TestQuicGsoBatchWriter::MaxSegments(gso_size);
188 for (size_t i = 0; i < max_segments; ++i) {
189 bool is_last_in_batch = (i + 1 == max_segments);
190 test_data_table.push_back({gso_size, self_addr, peer_addr,
191 /*release_time=*/0, true, is_last_in_batch});
192 }
193 test_data_table.push_back(
194 {gso_size, self_addr, peer_addr, /*release_time=*/0, false, true});
195 return test_data_table;
196 }
197
198 class QuicGsoBatchWriterTest : public QuicTest {
199 protected:
WritePacket(QuicGsoBatchWriter * writer,size_t packet_size)200 WriteResult WritePacket(QuicGsoBatchWriter* writer, size_t packet_size) {
201 return writer->WritePacket(&packet_buffer_[0], packet_size, self_address_,
202 peer_address_, nullptr,
203 QuicPacketWriterParams());
204 }
205
WritePacketWithParams(QuicGsoBatchWriter * writer,QuicPacketWriterParams & params)206 WriteResult WritePacketWithParams(QuicGsoBatchWriter* writer,
207 QuicPacketWriterParams& params) {
208 return writer->WritePacket(&packet_buffer_[0], 1350, self_address_,
209 peer_address_, nullptr, params);
210 }
211
212 QuicIpAddress self_address_ = QuicIpAddress::Any4();
213 QuicSocketAddress peer_address_{QuicIpAddress::Any4(), 443};
214 char packet_buffer_[1500];
215 StrictMock<MockQuicSyscallWrapper> mock_syscalls_;
216 ScopedGlobalSyscallWrapperOverride syscall_override_{&mock_syscalls_};
217 };
218
TEST_F(QuicGsoBatchWriterTest,BatchCriteria)219 TEST_F(QuicGsoBatchWriterTest, BatchCriteria) {
220 std::unique_ptr<TestQuicGsoBatchWriter> writer;
221
222 std::vector<std::vector<BatchCriteriaTestData>> test_data_tables;
223 test_data_tables.emplace_back(BatchCriteriaTestData_SizeDecrease());
224 test_data_tables.emplace_back(BatchCriteriaTestData_SizeIncrease());
225 test_data_tables.emplace_back(BatchCriteriaTestData_AddressChange());
226 test_data_tables.emplace_back(BatchCriteriaTestData_ReleaseTime1());
227 test_data_tables.emplace_back(BatchCriteriaTestData_ReleaseTime2());
228 test_data_tables.emplace_back(BatchCriteriaTestData_MaxSegments(1));
229 test_data_tables.emplace_back(BatchCriteriaTestData_MaxSegments(2));
230 test_data_tables.emplace_back(BatchCriteriaTestData_MaxSegments(1350));
231
232 for (size_t i = 0; i < test_data_tables.size(); ++i) {
233 writer = TestQuicGsoBatchWriter::NewInstanceWithReleaseTimeSupport();
234
235 const auto& test_data_table = test_data_tables[i];
236 for (size_t j = 0; j < test_data_table.size(); ++j) {
237 const BatchCriteriaTestData& test_data = test_data_table[j];
238 SCOPED_TRACE(testing::Message() << "i=" << i << ", j=" << j);
239 QuicPacketWriterParams params;
240 params.release_time_delay = QuicTime::Delta::FromMicroseconds(
241 test_data.buffered_write.release_time);
242 TestQuicGsoBatchWriter::CanBatchResult result = writer->CanBatch(
243 test_data.buffered_write.buffer, test_data.buffered_write.buf_len,
244 test_data.buffered_write.self_address,
245 test_data.buffered_write.peer_address, nullptr, params,
246 test_data.buffered_write.release_time);
247
248 ASSERT_EQ(test_data.can_batch, result.can_batch);
249 ASSERT_EQ(test_data.must_flush, result.must_flush);
250
251 if (result.can_batch) {
252 ASSERT_TRUE(writer->batch_buffer()
253 .PushBufferedWrite(
254 test_data.buffered_write.buffer,
255 test_data.buffered_write.buf_len,
256 test_data.buffered_write.self_address,
257 test_data.buffered_write.peer_address, nullptr,
258 params, test_data.buffered_write.release_time)
259 .succeeded);
260 }
261 }
262 }
263 }
264
TEST_F(QuicGsoBatchWriterTest,WriteSuccess)265 TEST_F(QuicGsoBatchWriterTest, WriteSuccess) {
266 TestQuicGsoBatchWriter writer(/*fd=*/-1);
267
268 ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 1000));
269
270 EXPECT_CALL(mock_syscalls_, Sendmsg(_, _, _))
271 .WillOnce(Invoke([](int /*sockfd*/, const msghdr* msg, int /*flags*/) {
272 EXPECT_EQ(1100u, PacketLength(msg));
273 return 1100;
274 }));
275 ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 1100), WritePacket(&writer, 100));
276 ASSERT_EQ(0u, writer.batch_buffer().SizeInUse());
277 ASSERT_EQ(0u, writer.buffered_writes().size());
278 }
279
TEST_F(QuicGsoBatchWriterTest,WriteBlockDataNotBuffered)280 TEST_F(QuicGsoBatchWriterTest, WriteBlockDataNotBuffered) {
281 TestQuicGsoBatchWriter writer(/*fd=*/-1);
282
283 ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100));
284 ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100));
285
286 EXPECT_CALL(mock_syscalls_, Sendmsg(_, _, _))
287 .WillOnce(Invoke([](int /*sockfd*/, const msghdr* msg, int /*flags*/) {
288 EXPECT_EQ(200u, PacketLength(msg));
289 errno = EWOULDBLOCK;
290 return -1;
291 }));
292 ASSERT_EQ(WriteResult(WRITE_STATUS_BLOCKED, EWOULDBLOCK),
293 WritePacket(&writer, 150));
294 ASSERT_EQ(200u, writer.batch_buffer().SizeInUse());
295 ASSERT_EQ(2u, writer.buffered_writes().size());
296 }
297
TEST_F(QuicGsoBatchWriterTest,WriteBlockDataBuffered)298 TEST_F(QuicGsoBatchWriterTest, WriteBlockDataBuffered) {
299 TestQuicGsoBatchWriter writer(/*fd=*/-1);
300
301 ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100));
302 ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100));
303
304 EXPECT_CALL(mock_syscalls_, Sendmsg(_, _, _))
305 .WillOnce(Invoke([](int /*sockfd*/, const msghdr* msg, int /*flags*/) {
306 EXPECT_EQ(250u, PacketLength(msg));
307 errno = EWOULDBLOCK;
308 return -1;
309 }));
310 ASSERT_EQ(WriteResult(WRITE_STATUS_BLOCKED_DATA_BUFFERED, EWOULDBLOCK),
311 WritePacket(&writer, 50));
312
313 EXPECT_TRUE(writer.IsWriteBlocked());
314
315 ASSERT_EQ(250u, writer.batch_buffer().SizeInUse());
316 ASSERT_EQ(3u, writer.buffered_writes().size());
317 }
318
TEST_F(QuicGsoBatchWriterTest,WriteErrorWithoutDataBuffered)319 TEST_F(QuicGsoBatchWriterTest, WriteErrorWithoutDataBuffered) {
320 TestQuicGsoBatchWriter writer(/*fd=*/-1);
321
322 ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100));
323 ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100));
324
325 EXPECT_CALL(mock_syscalls_, Sendmsg(_, _, _))
326 .WillOnce(Invoke([](int /*sockfd*/, const msghdr* msg, int /*flags*/) {
327 EXPECT_EQ(200u, PacketLength(msg));
328 errno = EPERM;
329 return -1;
330 }));
331 WriteResult error_result = WritePacket(&writer, 150);
332 ASSERT_EQ(WriteResult(WRITE_STATUS_ERROR, EPERM), error_result);
333
334 ASSERT_EQ(3u, error_result.dropped_packets);
335 ASSERT_EQ(0u, writer.batch_buffer().SizeInUse());
336 ASSERT_EQ(0u, writer.buffered_writes().size());
337 }
338
TEST_F(QuicGsoBatchWriterTest,WriteErrorAfterDataBuffered)339 TEST_F(QuicGsoBatchWriterTest, WriteErrorAfterDataBuffered) {
340 TestQuicGsoBatchWriter writer(/*fd=*/-1);
341
342 ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100));
343 ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100));
344
345 EXPECT_CALL(mock_syscalls_, Sendmsg(_, _, _))
346 .WillOnce(Invoke([](int /*sockfd*/, const msghdr* msg, int /*flags*/) {
347 EXPECT_EQ(250u, PacketLength(msg));
348 errno = EPERM;
349 return -1;
350 }));
351 WriteResult error_result = WritePacket(&writer, 50);
352 ASSERT_EQ(WriteResult(WRITE_STATUS_ERROR, EPERM), error_result);
353
354 ASSERT_EQ(3u, error_result.dropped_packets);
355 ASSERT_EQ(0u, writer.batch_buffer().SizeInUse());
356 ASSERT_EQ(0u, writer.buffered_writes().size());
357 }
358
TEST_F(QuicGsoBatchWriterTest,FlushError)359 TEST_F(QuicGsoBatchWriterTest, FlushError) {
360 TestQuicGsoBatchWriter writer(/*fd=*/-1);
361
362 ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100));
363 ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 0), WritePacket(&writer, 100));
364
365 EXPECT_CALL(mock_syscalls_, Sendmsg(_, _, _))
366 .WillOnce(Invoke([](int /*sockfd*/, const msghdr* msg, int /*flags*/) {
367 EXPECT_EQ(200u, PacketLength(msg));
368 errno = EINVAL;
369 return -1;
370 }));
371 WriteResult error_result = writer.Flush();
372 ASSERT_EQ(WriteResult(WRITE_STATUS_ERROR, EINVAL), error_result);
373
374 ASSERT_EQ(2u, error_result.dropped_packets);
375 ASSERT_EQ(0u, writer.batch_buffer().SizeInUse());
376 ASSERT_EQ(0u, writer.buffered_writes().size());
377 }
378
TEST_F(QuicGsoBatchWriterTest,ReleaseTime)379 TEST_F(QuicGsoBatchWriterTest, ReleaseTime) {
380 const WriteResult write_buffered(WRITE_STATUS_OK, 0);
381
382 auto writer = TestQuicGsoBatchWriter::NewInstanceWithReleaseTimeSupport();
383
384 QuicPacketWriterParams params;
385 EXPECT_TRUE(params.release_time_delay.IsZero());
386 EXPECT_FALSE(params.allow_burst);
387 EXPECT_EQ(MillisToNanos(1),
388 writer->GetReleaseTime(params).actual_release_time);
389
390 // The 1st packet has no delay.
391 WriteResult result = WritePacketWithParams(writer.get(), params);
392 ASSERT_EQ(write_buffered, result);
393 EXPECT_EQ(MillisToNanos(1), writer->buffered_writes().back().release_time);
394 EXPECT_EQ(result.send_time_offset, QuicTime::Delta::Zero());
395
396 // The 2nd packet has some delay, but allows burst.
397 params.release_time_delay = QuicTime::Delta::FromMilliseconds(3);
398 params.allow_burst = true;
399 result = WritePacketWithParams(writer.get(), params);
400 ASSERT_EQ(write_buffered, result);
401 EXPECT_EQ(MillisToNanos(1), writer->buffered_writes().back().release_time);
402 EXPECT_EQ(result.send_time_offset, QuicTime::Delta::FromMilliseconds(-3));
403
404 // The 3rd packet has more delay and does not allow burst.
405 // The first 2 packets are flushed due to different release time.
406 EXPECT_CALL(mock_syscalls_, Sendmsg(_, _, _))
407 .WillOnce(Invoke([](int /*sockfd*/, const msghdr* msg, int /*flags*/) {
408 EXPECT_EQ(2700u, PacketLength(msg));
409 errno = 0;
410 return 0;
411 }));
412 params.release_time_delay = QuicTime::Delta::FromMilliseconds(5);
413 params.allow_burst = false;
414 result = WritePacketWithParams(writer.get(), params);
415 ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 2700), result);
416 EXPECT_EQ(MillisToNanos(6), writer->buffered_writes().back().release_time);
417 EXPECT_EQ(result.send_time_offset, QuicTime::Delta::Zero());
418
419 // The 4th packet has same delay, but allows burst.
420 params.allow_burst = true;
421 result = WritePacketWithParams(writer.get(), params);
422 ASSERT_EQ(write_buffered, result);
423 EXPECT_EQ(MillisToNanos(6), writer->buffered_writes().back().release_time);
424 EXPECT_EQ(result.send_time_offset, QuicTime::Delta::Zero());
425
426 // The 5th packet has same delay, allows burst, but is shorter.
427 // Packets 3,4 and 5 are flushed.
428 EXPECT_CALL(mock_syscalls_, Sendmsg(_, _, _))
429 .WillOnce(Invoke([](int /*sockfd*/, const msghdr* msg, int /*flags*/) {
430 EXPECT_EQ(3000u, PacketLength(msg));
431 errno = 0;
432 return 0;
433 }));
434 params.allow_burst = true;
435 EXPECT_EQ(MillisToNanos(6),
436 writer->GetReleaseTime(params).actual_release_time);
437 ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 3000),
438 writer->WritePacket(&packet_buffer_[0], 300, self_address_,
439 peer_address_, nullptr, params));
440 EXPECT_TRUE(writer->buffered_writes().empty());
441
442 // Pretend 1ms has elapsed and the 6th packet has 1ms less delay. In other
443 // words, the release time should still be the same as packets 3-5.
444 writer->ForceReleaseTimeMs(2);
445 params.release_time_delay = QuicTime::Delta::FromMilliseconds(4);
446 result = WritePacketWithParams(writer.get(), params);
447 ASSERT_EQ(write_buffered, result);
448 EXPECT_EQ(MillisToNanos(6), writer->buffered_writes().back().release_time);
449 EXPECT_EQ(result.send_time_offset, QuicTime::Delta::Zero());
450 }
451
TEST_F(QuicGsoBatchWriterTest,EcnCodepoint)452 TEST_F(QuicGsoBatchWriterTest, EcnCodepoint) {
453 const WriteResult write_buffered(WRITE_STATUS_OK, 0);
454
455 auto writer = TestQuicGsoBatchWriter::NewInstanceWithReleaseTimeSupport();
456
457 QuicPacketWriterParams params;
458 EXPECT_TRUE(params.release_time_delay.IsZero());
459 EXPECT_FALSE(params.allow_burst);
460 params.ecn_codepoint = ECN_ECT0;
461
462 // The 1st packet has no delay.
463 WriteResult result = WritePacketWithParams(writer.get(), params);
464 ASSERT_EQ(write_buffered, result);
465 EXPECT_EQ(MillisToNanos(1), writer->buffered_writes().back().release_time);
466 EXPECT_EQ(result.send_time_offset, QuicTime::Delta::Zero());
467
468 // The 2nd packet should be buffered.
469 params.allow_burst = true;
470 result = WritePacketWithParams(writer.get(), params);
471 ASSERT_EQ(write_buffered, result);
472
473 // The 3rd packet changes the ECN codepoint.
474 // The first 2 packets are flushed due to different codepoint.
475 params.ecn_codepoint = ECN_ECT1;
476 EXPECT_CALL(mock_syscalls_, Sendmsg(_, _, _))
477 .WillOnce(Invoke([](int /*sockfd*/, const msghdr* msg, int /*flags*/) {
478 const int kEct0 = 0x02;
479 EXPECT_EQ(2700u, PacketLength(msg));
480 msghdr mutable_msg;
481 memcpy(&mutable_msg, msg, sizeof(*msg));
482 for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&mutable_msg); cmsg != NULL;
483 cmsg = CMSG_NXTHDR(&mutable_msg, cmsg)) {
484 if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_TOS) {
485 EXPECT_EQ(*reinterpret_cast<int*> CMSG_DATA(cmsg), kEct0);
486 break;
487 }
488 }
489 errno = 0;
490 return 0;
491 }));
492 result = WritePacketWithParams(writer.get(), params);
493 ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 2700), result);
494 }
495
TEST_F(QuicGsoBatchWriterTest,EcnCodepointIPv6)496 TEST_F(QuicGsoBatchWriterTest, EcnCodepointIPv6) {
497 const WriteResult write_buffered(WRITE_STATUS_OK, 0);
498
499 self_address_ = QuicIpAddress::Any6();
500 peer_address_ = QuicSocketAddress(QuicIpAddress::Any6(), 443);
501 auto writer = TestQuicGsoBatchWriter::NewInstanceWithReleaseTimeSupport();
502
503 QuicPacketWriterParams params;
504 EXPECT_TRUE(params.release_time_delay.IsZero());
505 EXPECT_FALSE(params.allow_burst);
506 params.ecn_codepoint = ECN_ECT0;
507
508 // The 1st packet has no delay.
509 WriteResult result = WritePacketWithParams(writer.get(), params);
510 ASSERT_EQ(write_buffered, result);
511 EXPECT_EQ(MillisToNanos(1), writer->buffered_writes().back().release_time);
512 EXPECT_EQ(result.send_time_offset, QuicTime::Delta::Zero());
513
514 // The 2nd packet should be buffered.
515 params.allow_burst = true;
516 result = WritePacketWithParams(writer.get(), params);
517 ASSERT_EQ(write_buffered, result);
518
519 // The 3rd packet changes the ECN codepoint.
520 // The first 2 packets are flushed due to different codepoint.
521 params.ecn_codepoint = ECN_ECT1;
522 EXPECT_CALL(mock_syscalls_, Sendmsg(_, _, _))
523 .WillOnce(Invoke([](int /*sockfd*/, const msghdr* msg, int /*flags*/) {
524 const int kEct0 = 0x02;
525 EXPECT_EQ(2700u, PacketLength(msg));
526 msghdr mutable_msg;
527 memcpy(&mutable_msg, msg, sizeof(*msg));
528 for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&mutable_msg); cmsg != NULL;
529 cmsg = CMSG_NXTHDR(&mutable_msg, cmsg)) {
530 if (cmsg->cmsg_level == IPPROTO_IPV6 &&
531 cmsg->cmsg_type == IPV6_TCLASS) {
532 EXPECT_EQ(*reinterpret_cast<int*> CMSG_DATA(cmsg), kEct0);
533 break;
534 }
535 }
536 errno = 0;
537 return 0;
538 }));
539 result = WritePacketWithParams(writer.get(), params);
540 ASSERT_EQ(WriteResult(WRITE_STATUS_OK, 2700), result);
541 }
542
543 } // namespace
544 } // namespace test
545 } // namespace quic
546