• 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/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