Skip to content

Commit 247a07d

Browse files
committed
Move pad_datagram to PacketBuilder::finish_and_track
You always need to remember to handle pad_datagram if needed. While really this always happens just before the call to finish_and_track. Instead this can be done in finish_and_track without any logic change, and this helps avoiding mistakes.
1 parent 2b56ebc commit 247a07d

File tree

3 files changed

+48
-30
lines changed

3 files changed

+48
-30
lines changed

quinn-proto/src/connection/mod.rs

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,7 @@ impl Connection {
583583
}
584584

585585
// If the datagram is full, we need to start a new one.
586-
if buf.len() == buf.datagram_max_offset() {
586+
if buf.datagram_remaining_mut() == 0 {
587587
// Is 1 more datagram allowed?
588588
if buf.num_datagrams() >= buf.max_datagrams() {
589589
// No more datagrams allowed
@@ -656,7 +656,7 @@ impl Connection {
656656
pad_datagram = false;
657657
}
658658

659-
debug_assert!(buf.datagram_max_offset() - buf.len() >= MIN_PACKET_SPACE);
659+
debug_assert!(buf.datagram_remaining_mut() >= MIN_PACKET_SPACE);
660660

661661
//
662662
// From here on, we've determined that a packet will definitely be sent.
@@ -750,10 +750,7 @@ impl Connection {
750750
),
751751
}
752752
}
753-
if pad_datagram {
754-
builder.pad_to(MIN_INITIAL_SIZE);
755-
}
756-
builder.finish_and_track(now, self, path_id, sent_frames);
753+
builder.finish_and_track(now, self, path_id, sent_frames, pad_datagram);
757754
if space_id == self.highest_space {
758755
// Don't send another close packet
759756
self.close = false;
@@ -788,6 +785,7 @@ impl Connection {
788785
non_retransmits: true,
789786
..SentFrames::default()
790787
},
788+
false,
791789
);
792790
self.stats.udp_tx.on_sent(1, buf.len());
793791
return Some(Transmit {
@@ -850,17 +848,18 @@ impl Connection {
850848
// Are we allowed to coalesce AND is there enough space for another *packet*
851849
// in this datagram?
852850
if coalesce
853-
&& builder.buf.segment_size() - builder.predict_packet_size() > MIN_PACKET_SPACE
851+
&& builder
852+
.buf
853+
.datagram_remaining_mut()
854+
.saturating_sub(builder.predict_packet_end())
855+
> MIN_PACKET_SPACE
854856
{
855857
// We can append/coalesce the next packet into the current
856858
// datagram. Finish the current packet without adding extra padding.
857-
builder.finish_and_track(now, self, path_id, sent_frames);
859+
builder.finish_and_track(now, self, path_id, sent_frames, false);
858860
} else {
859861
// We need a new datagram for the next packet. Finish the current
860862
// packet with padding.
861-
if pad_datagram {
862-
builder.pad_to(MIN_INITIAL_SIZE);
863-
}
864863
if builder.buf.num_datagrams() > 1 {
865864
// If too many padding bytes would be required to continue the
866865
// GSO batch after this packet, end the GSO batch here. Ensures
@@ -877,16 +876,14 @@ impl Connection {
877876
// are the only packets for which we might grow `buf_capacity`
878877
// by less than `segment_size`.
879878
const MAX_PADDING: usize = 16;
880-
let packet_len_unpadded = builder.predict_packet_size();
881-
if packet_len_unpadded + MAX_PADDING < builder.buf.segment_size()
882-
|| builder.buf.datagram_start_offset() + builder.buf.segment_size()
883-
> builder.buf.datagram_max_offset()
879+
if builder.buf.datagram_remaining_mut()
880+
> builder.predict_packet_end() + MAX_PADDING
884881
{
885882
trace!(
886-
"GSO truncated by demand for {} padding bytes or loss probe",
887-
builder.buf.segment_size() - packet_len_unpadded
883+
"GSO truncated by demand for {} padding bytes",
884+
builder.buf.datagram_remaining_mut() - builder.predict_packet_end()
888885
);
889-
builder.finish_and_track(now, self, path_id, sent_frames);
886+
builder.finish_and_track(now, self, path_id, sent_frames, pad_datagram);
890887
break;
891888
}
892889

@@ -895,7 +892,7 @@ impl Connection {
895892
builder.pad_to(builder.buf.segment_size() as u16);
896893
}
897894

898-
builder.finish_and_track(now, self, path_id, sent_frames);
895+
builder.finish_and_track(now, self, path_id, sent_frames, pad_datagram);
899896

900897
if buf.num_datagrams() == 1 {
901898
buf.clip_datagram_size();
@@ -924,10 +921,7 @@ impl Connection {
924921
}
925922
} else {
926923
// Nothing more to send. This was the last packet.
927-
if pad_datagram {
928-
builder.pad_to(MIN_INITIAL_SIZE);
929-
}
930-
builder.finish_and_track(now, self, path_id, sent_frames);
924+
builder.finish_and_track(now, self, path_id, sent_frames, pad_datagram);
931925
break;
932926
}
933927
}
@@ -987,7 +981,7 @@ impl Connection {
987981
non_retransmits: true,
988982
..Default::default()
989983
};
990-
builder.finish_and_track(now, self, path_id, sent_frames);
984+
builder.finish_and_track(now, self, path_id, sent_frames, false);
991985

992986
self.stats.path.sent_plpmtud_probes += 1;
993987

quinn-proto/src/connection/packet_builder.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use tracing::{trace, trace_span};
44

55
use super::{Connection, PathId, SentFrames, TransmitBuf, spaces::SentPacket};
66
use 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},
@@ -197,12 +197,16 @@ impl<'a, 'b> PacketBuilder<'a, 'b> {
197197
}
198198

199199
pub(super) fn finish_and_track(
200-
self,
200+
mut self,
201201
now: Instant,
202202
conn: &mut Connection,
203203
path_id: PathId,
204204
sent: SentFrames,
205+
pad_datagram: bool,
205206
) {
207+
if pad_datagram {
208+
self.pad_to(MIN_INITIAL_SIZE);
209+
}
206210
let ack_eliciting = self.ack_eliciting;
207211
let exact_number = self.exact_number;
208212
let space_id = self.space;
@@ -283,15 +287,17 @@ impl<'a, 'b> PacketBuilder<'a, 'b> {
283287
Some((self.exact_number, self.path, packet_crypto)),
284288
);
285289

286-
(self.buf.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)
287293
}
288294

289-
/// Predicts the size of the packet if it were finished now without additional padding
295+
/// The number of additional bytes the current packet would take up if it was finished now
290296
///
291297
/// This will include any padding which is required to make the size large enough to be
292298
/// encrypted correctly.
293-
pub(super) fn predict_packet_size(&self) -> usize {
294-
self.buf.len().max(self.min_size) - self.buf.datagram_start_offset() + self.tag_len
299+
pub(super) fn predict_packet_end(&self) -> usize {
300+
self.buf.len().max(self.min_size) + self.tag_len - self.buf.len()
295301
}
296302

297303
/// Returns the remaining space in the packet that can be taken up by QUIC frames

quinn-proto/src/connection/transmit_buf.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use bytes::BufMut;
2+
use tracing::trace;
23

34
use crate::packet::BufLen;
45

@@ -138,6 +139,13 @@ impl<'a> TransmitBuf<'a> {
138139
/// the last datagram in a batch.
139140
pub(super) fn clip_datagram_size(&mut self) {
140141
debug_assert_eq!(self.num_datagrams, 1);
142+
if self.buf.len() < self.segment_size {
143+
trace!(
144+
segment_size = self.buf.len(),
145+
prev_segment_size = self.segment_size,
146+
"clipped datagram size"
147+
);
148+
}
141149
self.segment_size = self.buf.len();
142150
self.buf_capacity = self.buf.len();
143151
}
@@ -147,6 +155,11 @@ impl<'a> TransmitBuf<'a> {
147155
/// This is also the maximum size datagrams are allowed to be. The first and last
148156
/// datagram in a batch are allowed to be smaller however. After the first datagram the
149157
/// segment size is clipped to the size of the first datagram.
158+
///
159+
/// If the last datagram was created using [`TransmitBuf::start_new_datagram_with_size`]
160+
/// the the segment size will be greater than the current datagram is allowed to be.
161+
/// Thus [`TransmitBuf::datagram_remaining_mut`] should be used if you need to know the
162+
/// amount of data that can be written into the datagram.
150163
pub(super) fn segment_size(&self) -> usize {
151164
self.segment_size
152165
}
@@ -178,6 +191,11 @@ impl<'a> TransmitBuf<'a> {
178191
self.buf_capacity
179192
}
180193

194+
/// Returns the number of bytes that may still be written into this datagram
195+
pub(super) fn datagram_remaining_mut(&self) -> usize {
196+
self.buf_capacity.saturating_sub(self.buf.len())
197+
}
198+
181199
/// Returns `true` if the buffer did not have anything written into it
182200
pub(super) fn is_empty(&self) -> bool {
183201
self.len() == 0

0 commit comments

Comments
 (0)