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