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