// Copyright 2013 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. #ifndef QUICHE_QUIC_CORE_QUIC_PACKET_WRITER_H_ #define QUICHE_QUIC_CORE_QUIC_PACKET_WRITER_H_ #include #include #include "quic/core/quic_packets.h" #include "quic/platform/api/quic_export.h" #include "quic/platform/api/quic_socket_address.h" namespace quic { struct WriteResult; struct QUIC_EXPORT_PRIVATE PerPacketOptions { virtual ~PerPacketOptions() {} // Returns a heap-allocated copy of |this|. // // The subclass implementation of this method should look like this: // return std::make_unique(*this); // // This method is declared pure virtual in order to ensure the subclasses // would not forget to override it. virtual std::unique_ptr Clone() const = 0; // Specifies ideal release time delay for this packet. QuicTime::Delta release_time_delay = QuicTime::Delta::Zero(); // Whether it is allowed to send this packet without |release_time_delay|. bool allow_burst = false; }; // An interface between writers and the entity managing the // socket (in our case the QuicDispatcher). This allows the Dispatcher to // control writes, and manage any writers who end up write blocked. // A concrete writer works in one of the two modes: // - PassThrough mode. This is the default mode. Caller calls WritePacket with // caller-allocated packet buffer. Unless the writer is blocked, each call to // WritePacket triggers a write using the underlying socket API. // // - Batch mode. In this mode, a call to WritePacket may not cause a packet to // be sent using the underlying socket API. Instead, multiple packets are // saved in the writer's internal buffer until they are flushed. The flush can // be explicit, by calling Flush, or implicit, e.g. by calling // WritePacket when the internal buffer is near full. // // Buffer management: // In Batch mode, a writer manages an internal buffer, which is large enough to // hold multiple packets' data. If the caller calls WritePacket with a // caller-allocated packet buffer, the writer will memcpy the buffer into the // internal buffer. Caller can also avoid this memcpy by: // 1. Call GetNextWriteLocation to get a pointer P into the internal buffer. // 2. Serialize the packet directly to P. // 3. Call WritePacket with P as the |buffer|. class QUIC_EXPORT_PRIVATE QuicPacketWriter { public: virtual ~QuicPacketWriter() {} // PassThrough mode: // Sends the packet out to the peer, with some optional per-packet options. // If the write succeeded, the result's status is WRITE_STATUS_OK and // bytes_written is populated. If the write failed, the result's status is // WRITE_STATUS_BLOCKED or WRITE_STATUS_ERROR and error_code is populated. // // Batch mode: // If the writer is blocked, return WRITE_STATUS_BLOCKED immediately. // If the packet can be batched with other buffered packets, save the packet // to the internal buffer. // If the packet can not be batched, or the internal buffer is near full after // it is buffered, the internal buffer is flushed to free up space. // Return WriteResult(WRITE_STATUS_OK, ) on success. When // is zero, it means the packet is buffered and not flushed. // Return WRITE_STATUS_BLOCKED if the packet is not buffered and the socket is // blocked while flushing. // Otherwise return an error status. // // Options must be either null, or created for the particular QuicPacketWriter // implementation. Options may be ignored, depending on the implementation. // // Some comment about memory management if |buffer| was previously acquired // by a call to "GetNextWriteLocation()": // // a) When WRITE_STATUS_OK is returned, the caller expects the writer owns the // packet buffers and they will be released when the write finishes. // // b) When this function returns any status >= WRITE_STATUS_ERROR, the caller // expects the writer releases the buffer (if needed) before the function // returns. // // c) When WRITE_STATUS_BLOCKED is returned, the caller makes a copy of the // buffer and will retry after unblock, so if |payload| is allocated from // GetNextWriteLocation(), it // 1) needs to be released before return, and // 2) the content of |payload| should not change after return. // // d) When WRITE_STATUS_BLOCKED_DATA_BUFFERED is returned, the caller expects // 1) the writer owns the packet buffers, and 2) the writer will re-send the // packet when it unblocks. virtual WriteResult WritePacket(const char* buffer, size_t buf_len, const QuicIpAddress& self_address, const QuicSocketAddress& peer_address, PerPacketOptions* options) = 0; // Returns true if the network socket is not writable. virtual bool IsWriteBlocked() const = 0; // Records that the socket has become writable, for example when an EPOLLOUT // is received or an asynchronous write completes. virtual void SetWritable() = 0; // Returns the maximum size of the packet which can be written using this // writer for the supplied peer address. This size may actually exceed the // size of a valid QUIC packet. virtual QuicByteCount GetMaxPacketSize( const QuicSocketAddress& peer_address) const = 0; // Returns true if the socket supports release timestamp. virtual bool SupportsReleaseTime() const = 0; // True=Batch mode. False=PassThrough mode. virtual bool IsBatchMode() const = 0; // PassThrough mode: Return {nullptr, nullptr} // // Batch mode: // Return the QuicPacketBuffer for the next packet. A minimum of // kMaxOutgoingPacketSize is guaranteed to be available from the returned // address. If the internal buffer does not have enough space, // {nullptr, nullptr} is returned. All arguments should be identical to the // follow-up call to |WritePacket|, they are here to allow advanced packet // memory management in packet writers, e.g. one packet buffer pool per // |peer_address|. // // If QuicPacketBuffer.release_buffer is !nullptr, it should be called iff // the caller does not call WritePacket for the returned buffer. virtual QuicPacketBuffer GetNextWriteLocation( const QuicIpAddress& self_address, const QuicSocketAddress& peer_address) = 0; // PassThrough mode: Return WriteResult(WRITE_STATUS_OK, 0). // // Batch mode: // Try send all buffered packets. // - Return WriteResult(WRITE_STATUS_OK, ) if all buffered // packets were sent successfully. // - Return WRITE_STATUS_BLOCKED if the underlying socket is blocked while // sending. Some packets may have been sent, packets not sent will stay in // the internal buffer. // - Return a status >= WRITE_STATUS_ERROR if an error was encuontered while // sending. As this is not a re-tryable error, any batched packets which // were on memory acquired via GetNextWriteLocation() should be released and // the batch should be dropped. virtual WriteResult Flush() = 0; }; } // namespace quic #endif // QUICHE_QUIC_CORE_QUIC_PACKET_WRITER_H_