blob: d5c032986070cbb68f183058a4f3d6cbb83d9636 [file] [log] [blame]
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "quic/core/batch_writer/quic_sendmmsg_batch_writer.h"
namespace quic {
QuicSendmmsgBatchWriter::QuicSendmmsgBatchWriter(
std::unique_ptr<QuicBatchWriterBuffer> batch_buffer,
int fd)
: QuicUdpBatchWriter(std::move(batch_buffer), fd) {}
QuicSendmmsgBatchWriter::CanBatchResult QuicSendmmsgBatchWriter::CanBatch(
const char* /*buffer*/,
size_t /*buf_len*/,
const QuicIpAddress& /*self_address*/,
const QuicSocketAddress& /*peer_address*/,
const PerPacketOptions* /*options*/,
uint64_t /*release_time*/) const {
return CanBatchResult(/*can_batch=*/true, /*must_flush=*/false);
}
QuicSendmmsgBatchWriter::FlushImplResult QuicSendmmsgBatchWriter::FlushImpl() {
return InternalFlushImpl(
kCmsgSpaceForIp,
[](QuicMMsgHdr* mhdr, int i, const BufferedWrite& buffered_write) {
mhdr->SetIpInNextCmsg(i, buffered_write.self_address);
});
}
QuicSendmmsgBatchWriter::FlushImplResult
QuicSendmmsgBatchWriter::InternalFlushImpl(size_t cmsg_space,
const CmsgBuilder& cmsg_builder) {
QUICHE_DCHECK(!IsWriteBlocked());
QUICHE_DCHECK(!buffered_writes().empty());
FlushImplResult result = {WriteResult(WRITE_STATUS_OK, 0),
/*num_packets_sent=*/0, /*bytes_written=*/0};
WriteResult& write_result = result.write_result;
auto first = buffered_writes().cbegin();
const auto last = buffered_writes().cend();
while (first != last) {
QuicMMsgHdr mhdr(first, last, cmsg_space, cmsg_builder);
int num_packets_sent;
write_result = QuicLinuxSocketUtils::WriteMultiplePackets(
fd(), &mhdr, &num_packets_sent);
QUIC_DVLOG(1) << "WriteMultiplePackets sent " << num_packets_sent
<< " out of " << mhdr.num_msgs()
<< " packets. WriteResult=" << write_result;
if (write_result.status != WRITE_STATUS_OK) {
QUICHE_DCHECK_EQ(0, num_packets_sent);
break;
} else if (num_packets_sent == 0) {
QUIC_BUG(quic_bug_10825_1)
<< "WriteMultiplePackets returned OK, but no packets were sent.";
write_result = WriteResult(WRITE_STATUS_ERROR, EIO);
break;
}
first += num_packets_sent;
result.num_packets_sent += num_packets_sent;
result.bytes_written += write_result.bytes_written;
}
// Call PopBufferedWrite() even if write_result.status is not WRITE_STATUS_OK,
// to deal with partial writes.
batch_buffer().PopBufferedWrite(result.num_packets_sent);
if (write_result.status != WRITE_STATUS_OK) {
return result;
}
QUIC_BUG_IF(quic_bug_12537_1, !buffered_writes().empty())
<< "All packets should have been written on a successful return";
write_result.bytes_written = result.bytes_written;
return result;
}
} // namespace quic