1- use bytes:: Bytes ;
1+ use bytes:: { BufMut , Bytes } ;
22use rand:: Rng ;
33use tracing:: { trace, trace_span} ;
44
5- use super :: { Connection , PathId , SentFrames , spaces:: SentPacket } ;
5+ use super :: { Connection , PathId , SentFrames , TransmitBuf , spaces:: SentPacket } ;
66use crate :: {
7- ConnectionId , Instant , TransportError , TransportErrorCode ,
7+ ConnectionId , Instant , MIN_INITIAL_SIZE , TransportError , TransportErrorCode ,
88 connection:: ConnectionSide ,
99 frame:: { self , Close } ,
1010 packet:: { FIXED_BIT , Header , InitialHeader , LongType , PacketNumber , PartialEncode , SpaceId } ,
1111} ;
1212
13- pub ( super ) struct PacketBuilder {
14- pub ( super ) datagram_start : usize ,
13+ /// QUIC packet builder
14+ ///
15+ /// This allows building QUIC packets: it takes care of writing the header, allows writing
16+ /// frames and on [`PacketBuilder::finish`] (or [`PacketBuilder::finish_and_track`]) it
17+ /// encrypts the packet so it is ready to be sent on the wire.
18+ ///
19+ /// The builder manages the write buffer into which the packet is written, and directly
20+ /// implements [`BufMut`] to write frames into the packet.
21+ pub ( super ) struct PacketBuilder < ' a , ' b > {
22+ pub ( super ) buf : & ' a mut TransmitBuf < ' b > ,
1523 pub ( super ) space : SpaceId ,
1624 path : PathId ,
1725 pub ( super ) partial_encode : PartialEncode ,
@@ -21,14 +29,11 @@ pub(super) struct PacketBuilder {
2129 /// Smallest absolute position in the associated buffer that must be occupied by this packet's
2230 /// frames
2331 pub ( super ) min_size : usize ,
24- /// Largest absolute position in the associated buffer that may be occupied by this packet's
25- /// frames
26- pub ( super ) max_size : usize ,
2732 pub ( super ) tag_len : usize ,
2833 pub ( super ) _span : tracing:: span:: EnteredSpan ,
2934}
3035
31- impl PacketBuilder {
36+ impl < ' a , ' b > PacketBuilder < ' a , ' b > {
3237 /// Write a new packet header to `buffer` and determine the packet's properties
3338 ///
3439 /// Marks the connection drained and returns `None` if the confidentiality limit would be
@@ -38,12 +43,13 @@ impl PacketBuilder {
3843 space_id : SpaceId ,
3944 path_id : PathId ,
4045 dst_cid : ConnectionId ,
41- buffer : & mut Vec < u8 > ,
42- buffer_capacity : usize ,
43- datagram_start : usize ,
46+ buffer : & ' a mut TransmitBuf < ' b > ,
4447 ack_eliciting : bool ,
4548 conn : & mut Connection ,
46- ) -> Option < Self > {
49+ ) -> Option < Self >
50+ where
51+ ' b : ' a ,
52+ {
4753 let version = conn. version ;
4854 // Initiate key update if we're approaching the confidentiality limit
4955 let sent_with_keys = conn. spaces [ space_id] . sent_with_keys ( ) ;
@@ -125,7 +131,7 @@ impl PacketBuilder {
125131 } ;
126132 let partial_encode = header. encode ( buffer) ;
127133 if conn. peer_params . grease_quic_bit && conn. rng . random ( ) {
128- buffer[ partial_encode. start ] ^= FIXED_BIT ;
134+ buffer. as_mut_slice ( ) [ partial_encode. start ] ^= FIXED_BIT ;
129135 }
130136
131137 let ( sample_size, tag_len) = if let Some ( ref crypto) = space. crypto {
@@ -152,18 +158,17 @@ impl PacketBuilder {
152158 buffer. len ( ) + ( sample_size + 4 ) . saturating_sub ( number. len ( ) + tag_len) ,
153159 partial_encode. start + dst_cid. len ( ) + 6 ,
154160 ) ;
155- let max_size = buffer_capacity - tag_len;
161+ let max_size = buffer . datagram_max_offset ( ) - tag_len;
156162 debug_assert ! ( max_size >= min_size) ;
157163
158164 Some ( Self {
159- datagram_start ,
165+ buf : buffer ,
160166 space : space_id,
161167 path : path_id,
162168 partial_encode,
163169 exact_number,
164170 short_header : header. is_short ( ) ,
165171 min_size,
166- max_size,
167172 tag_len,
168173 ack_eliciting,
169174 _span : span,
@@ -178,26 +183,34 @@ impl PacketBuilder {
178183 // already.
179184 self . min_size = Ord :: max (
180185 self . min_size ,
181- self . datagram_start + ( min_size as usize ) - self . tag_len ,
186+ self . buf . datagram_start_offset ( ) + ( min_size as usize ) - self . tag_len ,
182187 ) ;
183188 }
184189
190+ /// Returns a writable buffer limited to the remaining frame space
191+ ///
192+ /// The [`BufMut::remaining_mut`] call on the returned buffer indicates the amount of
193+ /// space available to write QUIC frames into.
194+ // In rust 1.82 we can use `-> impl BufMut + use<'_, 'a, 'b>`
195+ pub ( super ) fn frame_space_mut ( & mut self ) -> bytes:: buf:: Limit < & mut TransmitBuf < ' b > > {
196+ self . buf . limit ( self . frame_space_remaining ( ) )
197+ }
198+
185199 pub ( super ) fn finish_and_track (
186- self ,
200+ mut self ,
187201 now : Instant ,
188202 conn : & mut Connection ,
189203 path_id : PathId ,
190- sent : Option < SentFrames > ,
191- buffer : & mut Vec < u8 > ,
204+ sent : SentFrames ,
205+ pad_datagram : bool ,
192206 ) {
207+ if pad_datagram {
208+ self . pad_to ( MIN_INITIAL_SIZE ) ;
209+ }
193210 let ack_eliciting = self . ack_eliciting ;
194211 let exact_number = self . exact_number ;
195212 let space_id = self . space ;
196- let ( size, padded) = self . finish ( conn, buffer) ;
197- let sent = match sent {
198- Some ( sent) => sent,
199- None => return ,
200- } ;
213+ let ( size, padded) = self . finish ( conn) ;
201214
202215 let size = match padded || ack_eliciting {
203216 true => size as u16 ,
@@ -237,11 +250,15 @@ impl PacketBuilder {
237250 }
238251
239252 /// Encrypt packet, returning the length of the packet and whether padding was added
240- pub ( super ) fn finish ( self , conn : & mut Connection , buffer : & mut Vec < u8 > ) -> ( usize , bool ) {
241- let pad = buffer. len ( ) < self . min_size ;
253+ pub ( super ) fn finish ( self , conn : & mut Connection ) -> ( usize , bool ) {
254+ debug_assert ! (
255+ self . buf. len( ) <= self . buf. datagram_max_offset( ) - self . tag_len,
256+ "packet exceeds maximum size"
257+ ) ;
258+ let pad = self . buf . len ( ) < self . min_size ;
242259 if pad {
243- trace ! ( "PADDING * {}" , self . min_size - buffer . len( ) ) ;
244- buffer . resize ( self . min_size , 0 ) ;
260+ trace ! ( "PADDING * {}" , self . min_size - self . buf . len( ) ) ;
261+ self . buf . put_bytes ( 0 , self . min_size - self . buf . len ( ) ) ;
245262 }
246263
247264 let space = & conn. spaces [ self . space ] ;
@@ -260,16 +277,35 @@ impl PacketBuilder {
260277 "Mismatching crypto tag len"
261278 ) ;
262279
263- buffer . resize ( buffer . len ( ) + packet_crypto. tag_len ( ) , 0 ) ;
280+ self . buf . put_bytes ( 0 , packet_crypto. tag_len ( ) ) ;
264281 let encode_start = self . partial_encode . start ;
265- let packet_buf = & mut buffer [ encode_start..] ;
282+ let packet_buf = & mut self . buf . as_mut_slice ( ) [ encode_start..] ;
266283 // for packet protection, PathId(0) and no path are equivalent.
267284 self . partial_encode . finish (
268285 packet_buf,
269286 header_crypto,
270287 Some ( ( self . exact_number , self . path , packet_crypto) ) ,
271288 ) ;
272289
273- ( buffer. len ( ) - encode_start, pad)
290+ let packet_len = self . buf . len ( ) - encode_start;
291+ trace ! ( size = %packet_len, short_header = %self . short_header, "wrote packet" ) ;
292+ ( packet_len, pad)
293+ }
294+
295+ /// The number of additional bytes the current packet would take up if it was finished now
296+ ///
297+ /// This will include any padding which is required to make the size large enough to be
298+ /// encrypted correctly.
299+ pub ( super ) fn predict_packet_end ( & self ) -> usize {
300+ self . buf . len ( ) . max ( self . min_size ) + self . tag_len - self . buf . len ( )
301+ }
302+
303+ /// Returns the remaining space in the packet that can be taken up by QUIC frames
304+ ///
305+ /// This leaves space in the datagram for the cryptographic tag that needs to be written
306+ /// when the packet is finished.
307+ pub ( super ) fn frame_space_remaining ( & self ) -> usize {
308+ let max_offset = self . buf . datagram_max_offset ( ) - self . tag_len ;
309+ max_offset. saturating_sub ( self . buf . len ( ) )
274310 }
275311}
0 commit comments