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