xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/quic_packet_writer.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2013 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 #ifndef QUICHE_QUIC_CORE_QUIC_PACKET_WRITER_H_
6 #define QUICHE_QUIC_CORE_QUIC_PACKET_WRITER_H_
7 
8 #include <cstddef>
9 #include <optional>
10 #include <utility>
11 
12 #include "quiche/quic/core/quic_packets.h"
13 #include "quiche/quic/platform/api/quic_export.h"
14 #include "quiche/quic/platform/api/quic_ip_address.h"
15 #include "quiche/quic/platform/api/quic_socket_address.h"
16 
17 namespace quic {
18 
19 struct WriteResult;
20 
21 // This class allows a platform to pass instructions to an associated child of
22 // QuicWriter without intervening QUIC code understanding anything about its
23 // contents.
24 class QUICHE_EXPORT PerPacketOptions {
25  public:
~PerPacketOptions()26   virtual ~PerPacketOptions() {}
27 
28   // Returns a heap-allocated copy of |this|.
29   //
30   // The subclass implementation of this method should look like this:
31   //   return std::make_unique<MyAwesomePerPacketOptions>(*this);
32   //
33   // This method is declared pure virtual in order to ensure the subclasses
34   // would not forget to override it.
35   virtual std::unique_ptr<PerPacketOptions> Clone() const = 0;
36 };
37 
38 // The owner of QuicPacketWriter can pass control information via this struct.
39 struct QUICHE_EXPORT QuicPacketWriterParams {
40   // Specifies ideal release time delay for this packet.
41   QuicTime::Delta release_time_delay = QuicTime::Delta::Zero();
42   // Whether it is allowed to send this packet without |release_time_delay|.
43   bool allow_burst = false;
44   // ECN codepoint to use when sending this packet.
45   QuicEcnCodepoint ecn_codepoint = ECN_NOT_ECT;
46 };
47 
48 // An interface between writers and the entity managing the
49 // socket (in our case the QuicDispatcher).  This allows the Dispatcher to
50 // control writes, and manage any writers who end up write blocked.
51 // A concrete writer works in one of the two modes:
52 // - PassThrough mode. This is the default mode. Caller calls WritePacket with
53 //   caller-allocated packet buffer. Unless the writer is blocked, each call to
54 //   WritePacket triggers a write using the underlying socket API.
55 //
56 // - Batch mode. In this mode, a call to WritePacket may not cause a packet to
57 //   be sent using the underlying socket API. Instead, multiple packets are
58 //   saved in the writer's internal buffer until they are flushed. The flush can
59 //   be explicit, by calling Flush, or implicit, e.g. by calling
60 //   WritePacket when the internal buffer is near full.
61 //
62 // Buffer management:
63 // In Batch mode, a writer manages an internal buffer, which is large enough to
64 // hold multiple packets' data. If the caller calls WritePacket with a
65 // caller-allocated packet buffer, the writer will memcpy the buffer into the
66 // internal buffer. Caller can also avoid this memcpy by:
67 // 1. Call GetNextWriteLocation to get a pointer P into the internal buffer.
68 // 2. Serialize the packet directly to P.
69 // 3. Call WritePacket with P as the |buffer|.
70 class QUICHE_EXPORT QuicPacketWriter {
71  public:
~QuicPacketWriter()72   virtual ~QuicPacketWriter() {}
73 
74   // PassThrough mode:
75   // Sends the packet out to the peer, with some optional per-packet options.
76   // If the write succeeded, the result's status is WRITE_STATUS_OK and
77   // bytes_written is populated. If the write failed, the result's status is
78   // WRITE_STATUS_BLOCKED or WRITE_STATUS_ERROR and error_code is populated.
79   //
80   // Batch mode:
81   // If the writer is blocked, return WRITE_STATUS_BLOCKED immediately.
82   // If the packet can be batched with other buffered packets, save the packet
83   // to the internal buffer.
84   // If the packet can not be batched, or the internal buffer is near full after
85   // it is buffered, the internal buffer is flushed to free up space.
86   // Return WriteResult(WRITE_STATUS_OK, <bytes_flushed>) on success. When
87   // <bytes_flushed> is zero, it means the packet is buffered and not flushed.
88   // Return WRITE_STATUS_BLOCKED if the packet is not buffered and the socket is
89   // blocked while flushing.
90   // Otherwise return an error status.
91   //
92   // Options must be either null, or created for the particular QuicPacketWriter
93   // implementation. Options may be ignored, depending on the implementation.
94   //
95   // Some comment about memory management if |buffer| was previously acquired
96   // by a call to "GetNextWriteLocation()":
97   //
98   // a) When WRITE_STATUS_OK is returned, the caller expects the writer owns the
99   // packet buffers and they will be released when the write finishes.
100   //
101   // b) When this function returns any status >= WRITE_STATUS_ERROR, the caller
102   // expects the writer releases the buffer (if needed) before the function
103   // returns.
104   //
105   // c) When WRITE_STATUS_BLOCKED is returned, the caller makes a copy of the
106   // buffer and will retry after unblock, so if |payload| is allocated from
107   // GetNextWriteLocation(), it
108   //    1) needs to be released before return, and
109   //    2) the content of |payload| should not change after return.
110   //
111   // d) When WRITE_STATUS_BLOCKED_DATA_BUFFERED is returned, the caller expects
112   // 1) the writer owns the packet buffers, and 2) the writer will re-send the
113   // packet when it unblocks.
114   virtual WriteResult WritePacket(const char* buffer, size_t buf_len,
115                                   const QuicIpAddress& self_address,
116                                   const QuicSocketAddress& peer_address,
117                                   PerPacketOptions* options,
118                                   const QuicPacketWriterParams& params) = 0;
119 
120   // Returns true if the network socket is not writable.
121   virtual bool IsWriteBlocked() const = 0;
122 
123   // Records that the socket has become writable, for example when an EPOLLOUT
124   // is received or an asynchronous write completes.
125   virtual void SetWritable() = 0;
126 
127   // The error code used by the writer to indicate that the write failed due to
128   // supplied packet being too big.  This is equivalent to returning
129   // WRITE_STATUS_MSG_TOO_BIG as a status.
130   virtual std::optional<int> MessageTooBigErrorCode() const = 0;
131 
132   // Returns the maximum size of the packet which can be written using this
133   // writer for the supplied peer address.  This size may actually exceed the
134   // size of a valid QUIC packet.
135   virtual QuicByteCount GetMaxPacketSize(
136       const QuicSocketAddress& peer_address) const = 0;
137 
138   // Returns true if the socket supports release timestamp.
139   virtual bool SupportsReleaseTime() const = 0;
140 
141   // True=Batch mode. False=PassThrough mode.
142   virtual bool IsBatchMode() const = 0;
143 
144   // Returns true if the writer will mark ECN on packets it writes.
145   virtual bool SupportsEcn() const = 0;
146 
147   // PassThrough mode: Return {nullptr, nullptr}
148   //
149   // Batch mode:
150   // Return the QuicPacketBuffer for the next packet. A minimum of
151   // kMaxOutgoingPacketSize is guaranteed to be available from the returned
152   // address. If the internal buffer does not have enough space,
153   // {nullptr, nullptr} is returned. All arguments should be identical to the
154   // follow-up call to |WritePacket|, they are here to allow advanced packet
155   // memory management in packet writers, e.g. one packet buffer pool per
156   // |peer_address|.
157   //
158   // If QuicPacketBuffer.release_buffer is !nullptr, it should be called iff
159   // the caller does not call WritePacket for the returned buffer.
160   virtual QuicPacketBuffer GetNextWriteLocation(
161       const QuicIpAddress& self_address,
162       const QuicSocketAddress& peer_address) = 0;
163 
164   // PassThrough mode: Return WriteResult(WRITE_STATUS_OK, 0).
165   //
166   // Batch mode:
167   // Try send all buffered packets.
168   // - Return WriteResult(WRITE_STATUS_OK, <bytes_flushed>) if all buffered
169   //   packets were sent successfully.
170   // - Return WRITE_STATUS_BLOCKED if the underlying socket is blocked while
171   //   sending. Some packets may have been sent, packets not sent will stay in
172   //   the internal buffer.
173   // - Return a status >= WRITE_STATUS_ERROR if an error was encuontered while
174   //   sending. As this is not a re-tryable error, any batched packets which
175   //   were on memory acquired via GetNextWriteLocation() should be released and
176   //   the batch should be dropped.
177   virtual WriteResult Flush() = 0;
178 };
179 
180 }  // namespace quic
181 
182 #endif  // QUICHE_QUIC_CORE_QUIC_PACKET_WRITER_H_
183