blob: 3166aba3e47f5f34ccfd79f2462ef609f5a3c04a [file] [log] [blame]
// Copyright (c) 2018 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 "net/third_party/quic/platform/impl/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) 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) {
DCHECK(!IsWriteBlocked());
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) {
DCHECK_EQ(0, num_packets_sent);
break;
} else if (num_packets_sent == 0) {
QUIC_BUG << "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(!buffered_writes().empty())
<< "All packets should have been written on a successful return";
write_result.bytes_written = result.bytes_written;
return result;
}
} // namespace quic