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_sendmmsg_batch_writer.h"
6
7 namespace quic {
8
QuicSendmmsgBatchWriter(std::unique_ptr<QuicBatchWriterBuffer> batch_buffer,int fd)9 QuicSendmmsgBatchWriter::QuicSendmmsgBatchWriter(
10 std::unique_ptr<QuicBatchWriterBuffer> batch_buffer, int fd)
11 : QuicUdpBatchWriter(std::move(batch_buffer), fd) {}
12
CanBatch(const char *,size_t,const QuicIpAddress &,const QuicSocketAddress &,const PerPacketOptions *,const QuicPacketWriterParams &,uint64_t) const13 QuicSendmmsgBatchWriter::CanBatchResult QuicSendmmsgBatchWriter::CanBatch(
14 const char* /*buffer*/, size_t /*buf_len*/,
15 const QuicIpAddress& /*self_address*/,
16 const QuicSocketAddress& /*peer_address*/,
17 const PerPacketOptions* /*options*/,
18 const QuicPacketWriterParams& /*params*/, uint64_t /*release_time*/) const {
19 return CanBatchResult(/*can_batch=*/true, /*must_flush=*/false);
20 }
21
FlushImpl()22 QuicSendmmsgBatchWriter::FlushImplResult QuicSendmmsgBatchWriter::FlushImpl() {
23 return InternalFlushImpl(
24 kCmsgSpaceForIp,
25 [](QuicMMsgHdr* mhdr, int i, const BufferedWrite& buffered_write) {
26 mhdr->SetIpInNextCmsg(i, buffered_write.self_address);
27 });
28 }
29
30 QuicSendmmsgBatchWriter::FlushImplResult
InternalFlushImpl(size_t cmsg_space,const CmsgBuilder & cmsg_builder)31 QuicSendmmsgBatchWriter::InternalFlushImpl(size_t cmsg_space,
32 const CmsgBuilder& cmsg_builder) {
33 QUICHE_DCHECK(!IsWriteBlocked());
34 QUICHE_DCHECK(!buffered_writes().empty());
35
36 FlushImplResult result = {WriteResult(WRITE_STATUS_OK, 0),
37 /*num_packets_sent=*/0, /*bytes_written=*/0};
38 WriteResult& write_result = result.write_result;
39
40 auto first = buffered_writes().cbegin();
41 const auto last = buffered_writes().cend();
42 while (first != last) {
43 QuicMMsgHdr mhdr(first, last, cmsg_space, cmsg_builder);
44
45 int num_packets_sent;
46 write_result = QuicLinuxSocketUtils::WriteMultiplePackets(
47 fd(), &mhdr, &num_packets_sent);
48 QUIC_DVLOG(1) << "WriteMultiplePackets sent " << num_packets_sent
49 << " out of " << mhdr.num_msgs()
50 << " packets. WriteResult=" << write_result;
51
52 if (write_result.status != WRITE_STATUS_OK) {
53 QUICHE_DCHECK_EQ(0, num_packets_sent);
54 break;
55 } else if (num_packets_sent == 0) {
56 QUIC_BUG(quic_bug_10825_1)
57 << "WriteMultiplePackets returned OK, but no packets were sent.";
58 write_result = WriteResult(WRITE_STATUS_ERROR, EIO);
59 break;
60 }
61
62 first += num_packets_sent;
63
64 result.num_packets_sent += num_packets_sent;
65 result.bytes_written += write_result.bytes_written;
66 }
67
68 // Call PopBufferedWrite() even if write_result.status is not WRITE_STATUS_OK,
69 // to deal with partial writes.
70 batch_buffer().PopBufferedWrite(result.num_packets_sent);
71
72 if (write_result.status != WRITE_STATUS_OK) {
73 return result;
74 }
75
76 QUIC_BUG_IF(quic_bug_12537_1, !buffered_writes().empty())
77 << "All packets should have been written on a successful return";
78 write_result.bytes_written = result.bytes_written;
79 return result;
80 }
81
82 } // namespace quic
83