blob: 34c801acd35c208758859865a42ada0443691d25 [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 <cstdint>
#include "quiche/quic/core/batch_writer/quic_batch_writer_buffer.h"
#include "quiche/quic/core/quic_packet_writer.h"
#include "quiche/quic/core/quic_types.h"
#include "quiche/quic/platform/api/quic_ip_address.h"
#include "quiche/quic/platform/api/quic_socket_address.h"
namespace quic {
// QuicBatchWriterBase implements logic common to all derived batch writers,
// including maintaining write blockage state and a skeleton implemention of
// WritePacket().
// A derived batch writer must override the FlushImpl() function to send all
// buffered writes in a batch. It must also override the CanBatch() function
// to control whether/when a WritePacket() call should flush.
class QUICHE_EXPORT QuicBatchWriterBase : public QuicPacketWriter {
explicit QuicBatchWriterBase(
std::unique_ptr<QuicBatchWriterBuffer> batch_buffer);
// ATTENTION: If this write triggered a flush, and the flush failed, all
// buffered packets will be dropped to allow the next write to work. The
// number of dropped packets can be found in WriteResult.dropped_packets.
WriteResult WritePacket(const char* buffer, size_t buf_len,
const QuicIpAddress& self_address,
const QuicSocketAddress& peer_address,
PerPacketOptions* options,
const QuicPacketWriterParams& params) override;
bool IsWriteBlocked() const final { return write_blocked_; }
void SetWritable() final { write_blocked_ = false; }
std::optional<int> MessageTooBigErrorCode() const override {
return EMSGSIZE;
QuicByteCount GetMaxPacketSize(
const QuicSocketAddress& /*peer_address*/) const final {
return kMaxOutgoingPacketSize;
bool SupportsReleaseTime() const override { return false; }
bool IsBatchMode() const final { return true; }
bool SupportsEcn() const override { return false; }
QuicPacketBuffer GetNextWriteLocation(
const QuicIpAddress& /*self_address*/,
const QuicSocketAddress& /*peer_address*/) final {
// No need to explicitly delete QuicBatchWriterBuffer.
return {batch_buffer_->GetNextWriteLocation(), nullptr};
WriteResult Flush() override;
const QuicBatchWriterBuffer& batch_buffer() const { return *batch_buffer_; }
QuicBatchWriterBuffer& batch_buffer() { return *batch_buffer_; }
const quiche::QuicheCircularDeque<BufferedWrite>& buffered_writes() const {
return batch_buffer_->buffered_writes();
// Given the release delay in |options| and the state of |batch_buffer_|, get
// the absolute release time.
struct QUICHE_EXPORT ReleaseTime {
// The actual (absolute) release time.
uint64_t actual_release_time = 0;
// The difference between |actual_release_time| and ideal release time,
// which is (now + |options->release_time_delay|).
QuicTime::Delta release_time_offset = QuicTime::Delta::Zero();
virtual ReleaseTime GetReleaseTime(
const QuicPacketWriterParams& /*params*/) const {
<< "Should not be called since release time is unsupported.";
return ReleaseTime{0, QuicTime::Delta::Zero()};
struct QUICHE_EXPORT CanBatchResult {
CanBatchResult(bool can_batch, bool must_flush)
: can_batch(can_batch), must_flush(must_flush) {}
// Whether this write can be batched with existing buffered writes.
bool can_batch;
// If |can_batch|, whether the caller must flush after this packet is
// buffered.
// Always true if not |can_batch|.
bool must_flush;
// Given the existing buffered writes(in buffered_writes()), whether a new
// write(in the arguments) can be batched.
virtual CanBatchResult CanBatch(const char* buffer, size_t buf_len,
const QuicIpAddress& self_address,
const QuicSocketAddress& peer_address,
const PerPacketOptions* options,
const QuicPacketWriterParams& params,
uint64_t release_time) const = 0;
struct QUICHE_EXPORT FlushImplResult {
// The return value of the Flush() interface, which is:
// - WriteResult(WRITE_STATUS_OK, <bytes_flushed>) if all buffered writes
// were sent successfully.
// - WRITE_STATUS_BLOCKED or WRITE_STATUS_ERROR, if the batch write is
// blocked or returned an error while sending. If a portion of buffered
// writes were sent successfully, |FlushImplResult.num_packets_sent| and
// |FlushImplResult.bytes_written| contain the number of successfully sent
// packets and their total bytes.
WriteResult write_result;
int num_packets_sent;
// If write_result.status == WRITE_STATUS_OK, |bytes_written| will be equal
// to write_result.bytes_written. Otherwise |bytes_written| will be the
// number of bytes written before WRITE_BLOCK or WRITE_ERROR happened.
int bytes_written;
// Send all buffered writes(in buffered_writes()) in a batch.
// buffered_writes() is guaranteed to be non-empty when this function is
// called.
virtual FlushImplResult FlushImpl() = 0;
WriteResult InternalWritePacket(const char* buffer, size_t buf_len,
const QuicIpAddress& self_address,
const QuicSocketAddress& peer_address,
PerPacketOptions* options,
const QuicPacketWriterParams& params);
// Calls FlushImpl() and check its post condition.
FlushImplResult CheckedFlush();
bool write_blocked_;
std::unique_ptr<QuicBatchWriterBuffer> batch_buffer_;
// QuicUdpBatchWriter is a batch writer backed by a UDP socket.
class QUICHE_EXPORT QuicUdpBatchWriter : public QuicBatchWriterBase {
QuicUdpBatchWriter(std::unique_ptr<QuicBatchWriterBuffer> batch_buffer,
int fd)
: QuicBatchWriterBase(std::move(batch_buffer)), fd_(fd) {}
int fd() const { return fd_; }
const int fd_;
} // namespace quic