1use bytes::{BufMut, Bytes};
2use rand::RngExt;
3use tracing::{debug, trace, trace_span};
4
5use super::{Connection, PathId, SentFrames, TransmitBuf, spaces::SentPacket};
6use crate::{
7 ConnectionId, FrameStats, Instant, MIN_INITIAL_SIZE, TransportError,
8 coding::Encodable,
9 connection::{ConnectionSide, EncryptionLevel, qlog::QlogSentPacket, spaces::Retransmits},
10 frame::EncodableFrame,
11 packet::{FIXED_BIT, Header, InitialHeader, LongType, PacketNumber, PartialEncode, SpaceId},
12};
13
14pub(super) struct PacketBuilder<'a, 'b> {
23 pub(super) buf: &'a mut TransmitBuf<'b>,
24 pub(super) space: SpaceId,
25 path: PathId,
26 pub(super) partial_encode: PartialEncode,
27 pub(super) ack_eliciting: bool,
28 pub(super) packet_number: u64,
29 pub(super) can_coalesce: bool,
31 pub(super) min_size: usize,
34 pub(super) tag_len: usize,
35 level: EncryptionLevel,
36 pub(super) _span: tracing::span::EnteredSpan,
37 qlog: QlogSentPacket,
38 sent_frames: SentFrames,
39}
40
41impl<'a, 'b> PacketBuilder<'a, 'b> {
42 pub(super) fn new(
47 now: Instant,
48 space_id: SpaceId,
49 path_id: PathId,
50 dst_cid: ConnectionId,
51 buffer: &'a mut TransmitBuf<'b>,
52 conn: &mut Connection,
53 ) -> Option<Self>
54 where
55 'b: 'a,
56 {
57 let mut qlog = QlogSentPacket::default();
58
59 let version = conn.version;
60 let (_header_crypto, _packet_crypto, level) = conn
62 .crypto_state
63 .encryption_keys(space_id.kind(), conn.side.side())
64 .expect("tried to build packet without encryption keys");
65
66 let remaining_packet_budget = conn
67 .crypto_state
68 .remaining_packet_budget(level)
69 .expect("keys are installed");
70
71 if level == EncryptionLevel::OneRtt {
72 if remaining_packet_budget == 0 {
74 debug!("routine key update due to phase exhaustion");
75 conn.force_key_update();
76 }
77 } else {
78 if remaining_packet_budget == 0 {
80 let close = TransportError::AEAD_LIMIT_REACHED("confidentiality limit reached");
81 conn.kill(close.into());
82 return None;
83 } else if remaining_packet_budget == 1 {
84 let close = TransportError::AEAD_LIMIT_REACHED("confidentiality limit reached");
85 conn.close_inner(now, close.into());
86 }
87 }
88
89 let (header_crypto, packet_crypto, level) = conn
90 .crypto_state
91 .encryption_keys(space_id.kind(), conn.side.side())
92 .expect("verified");
93
94 let space = &mut conn.spaces[space_id];
95 let packet_number = space.for_path(path_id).get_tx_number(&mut conn.rng);
96 let span = trace_span!("send", space = ?space_id, pn = packet_number, %path_id).entered();
97
98 let number = PacketNumber::new(
99 packet_number,
100 space.for_path(path_id).largest_acked_packet_pn.unwrap_or(0),
101 );
102 let header = match level {
103 EncryptionLevel::OneRtt => Header::Short {
104 dst_cid,
105 number,
106 spin: if conn.spin_enabled {
107 conn.spin
108 } else {
109 conn.rng.random()
110 },
111 key_phase: conn.crypto_state.key_phase,
112 },
113 EncryptionLevel::ZeroRtt => Header::Long {
114 ty: LongType::ZeroRtt,
115 src_cid: conn.handshake_cid,
116 dst_cid,
117 number,
118 version,
119 },
120 EncryptionLevel::Handshake => Header::Long {
121 ty: LongType::Handshake,
122 src_cid: conn.handshake_cid,
123 dst_cid,
124 number,
125 version,
126 },
127 EncryptionLevel::Initial => Header::Initial(InitialHeader {
128 src_cid: conn.handshake_cid,
129 dst_cid,
130 token: match &conn.side {
131 ConnectionSide::Client { token, .. } => token.clone(),
132 ConnectionSide::Server { .. } => Bytes::new(),
133 },
134 number,
135 version,
136 }),
137 };
138
139 let partial_encode = header.encode(buffer);
140 if conn.peer_params.grease_quic_bit && conn.rng.random() {
141 buffer.as_mut_slice()[partial_encode.start] ^= FIXED_BIT;
142 }
143
144 let (sample_size, tag_len) = (header_crypto.sample_size(), packet_crypto.tag_len());
145
146 let min_size = Ord::max(
155 buffer.len() + (sample_size + 4).saturating_sub(number.len() + tag_len),
156 partial_encode.start + dst_cid.len() + 6,
157 );
158 let max_size = buffer.datagram_max_offset() - tag_len;
159 debug_assert!(max_size >= min_size);
160
161 qlog.header(&header, Some(packet_number), level, path_id);
162
163 Some(Self {
164 buf: buffer,
165 space: space_id,
166 path: path_id,
167 partial_encode,
168 packet_number,
169 can_coalesce: header.can_coalesce(),
170 min_size,
171 tag_len,
172 level,
173 ack_eliciting: false,
174 qlog,
175 sent_frames: SentFrames::default(),
176 _span: span,
177 })
178 }
179
180 #[cfg(test)]
181 pub(crate) fn simple_data_buf(buf: &'a mut TransmitBuf<'b>) -> Self {
182 Self {
183 buf,
184 space: SpaceId::Data,
185 path: PathId::ZERO,
186 partial_encode: PartialEncode::no_header(),
187 ack_eliciting: true,
188 packet_number: 0,
189 can_coalesce: true,
190 min_size: 0,
191 tag_len: 0,
192 _span: trace_span!("test").entered(),
193 qlog: QlogSentPacket::default(),
194 sent_frames: SentFrames::default(),
195 level: EncryptionLevel::Initial,
196 }
197 }
198
199 pub(super) fn pad_to(&mut self, min_size: u16) {
202 self.min_size = Ord::max(
206 self.min_size,
207 self.buf.datagram_start_offset() + (min_size as usize) - self.tag_len,
208 );
209 }
210
211 pub(super) fn write_frame<'c>(
220 &mut self,
221 frame: impl Into<EncodableFrame<'c>>,
222 stats: &mut FrameStats,
223 ) {
224 self.write_frame_with_log_msg(frame, stats, None);
225 }
226
227 pub(super) fn write_frame_with_log_msg<'c>(
236 &mut self,
237 frame: impl Into<EncodableFrame<'c>>,
238 stats: &mut FrameStats,
239 msg: Option<&'static str>,
240 ) {
241 let frame = frame.into();
242 frame.encode(&mut self.frame_space_mut());
243 self.ack_eliciting |= frame.is_ack_eliciting();
244 stats.record(frame.get_type());
245 self.qlog.record(&frame);
246 match msg {
247 Some(msg) => trace!(%frame, msg),
248 None => trace!(%frame),
249 }
250 self.sent_frames.record_sent_frame(frame);
251 }
252
253 fn frame_space_mut(&mut self) -> bytes::buf::Limit<&mut TransmitBuf<'b>> {
259 self.buf.limit(self.frame_space_remaining())
260 }
261
262 pub(super) fn sent_frames(&self) -> &SentFrames {
263 &self.sent_frames
264 }
265
266 pub(super) fn finish_and_track(
267 mut self,
268 now: Instant,
269 conn: &mut Connection,
270 path_id: PathId,
271 pad_datagram: PadDatagram,
272 ) {
273 match pad_datagram {
274 PadDatagram::No => (),
275 PadDatagram::ToSize(size) => self.pad_to(size),
276 PadDatagram::ToSegmentSize => self.pad_to(self.buf.segment_size() as u16),
277 PadDatagram::ToMinMtu => self.pad_to(MIN_INITIAL_SIZE),
278 }
279 let ack_eliciting = self.ack_eliciting;
280 let packet_number = self.packet_number;
281 let space_id = self.space;
282 let (size, padded, sent) = self.finish(conn, now);
283
284 let size = match padded || ack_eliciting {
285 true => size as u16,
286 false => 0,
287 };
288
289 let is_mtud_probe =
290 conn.path_data(path_id).mtud.in_flight_mtu_probe() == Some(packet_number);
291 {
292 let path_stats = conn.path_stats.get_mut(path_id);
293 path_stats.sent_packets += 1;
294 path_stats.sent_bytes += size as u64;
295 path_stats.sent_plpmtud_probes += is_mtud_probe as u64;
296 }
297
298 let packet = SentPacket {
299 path_generation: conn.paths.get_mut(&path_id).unwrap().data.generation(),
300 largest_acked: sent.largest_acked,
301 time_sent: now,
302 size,
303 ack_eliciting,
304 retransmits: sent.retransmits,
305 path_retransmits: sent.path_retransmits,
306 stream_frames: sent.stream_frames,
307 };
308
309 conn.paths.get_mut(&path_id).unwrap().data.sent(
310 packet_number,
311 packet,
312 conn.spaces[space_id].for_path(path_id),
313 );
314 conn.reset_keep_alive(path_id, now);
315 if size != 0 {
316 if ack_eliciting {
317 conn.spaces[space_id]
318 .for_path(path_id)
319 .time_of_last_ack_eliciting_packet = Some(now);
320 if conn.path_data(path_id).permit_idle_reset {
321 conn.reset_idle_timeout(now, space_id.kind(), path_id);
322 }
323 conn.path_data_mut(path_id).permit_idle_reset = false;
324 conn.path_data_mut(path_id)
325 .congestion
326 .on_packet_sent(now, size, packet_number)
327 }
328 conn.set_loss_detection_timer(now, path_id);
329 conn.path_data_mut(path_id).pacing.on_transmit(size);
330 }
331 }
332
333 pub(super) fn finish(
335 mut self,
336 conn: &mut Connection,
337 now: Instant,
338 ) -> (usize, bool, SentFrames) {
339 debug_assert!(
340 self.buf.len() <= self.buf.datagram_max_offset() - self.tag_len,
341 "packet exceeds maximum size"
342 );
343 let pad = self.buf.len() < self.min_size;
344 if pad {
345 let padding = self.min_size - self.buf.len();
346 trace!("PADDING * {}", padding);
347 self.buf.put_bytes(0, padding);
348 self.qlog.frame_padding(padding);
349 }
350
351 let (header_crypto, packet_crypto) = conn
352 .crypto_state
353 .local_crypto(self.level)
354 .expect("tried to send packet without keys");
355
356 debug_assert_eq!(
357 packet_crypto.tag_len(),
358 self.tag_len,
359 "Mismatching crypto tag len"
360 );
361
362 self.buf.put_bytes(0, packet_crypto.tag_len());
363 let encode_start = self.partial_encode.start;
364 let packet_buf = &mut self.buf.as_mut_slice()[encode_start..];
365 self.partial_encode.finish(
367 packet_buf,
368 header_crypto,
369 Some((self.packet_number, self.path, packet_crypto)),
370 );
371
372 conn.crypto_state.inc_sent_with_keys(self.level);
373
374 let packet_len = self.buf.len() - encode_start;
375 trace!(size = %packet_len, "wrote packet");
376 self.qlog.finalize(packet_len);
377 conn.qlog.emit_packet_sent(self.qlog, now);
378 (packet_len, pad, self.sent_frames)
379 }
380
381 pub(super) fn predict_packet_end(&self) -> usize {
386 self.buf.len().max(self.min_size) + self.tag_len - self.buf.len()
387 }
388
389 pub(super) fn frame_space_remaining(&self) -> usize {
394 let max_offset = self.buf.datagram_max_offset() - self.tag_len;
395 max_offset.saturating_sub(self.buf.len())
396 }
397
398 pub(crate) fn require_padding(&mut self) {
399 self.sent_frames.requires_padding = true;
400 }
401
402 pub(crate) fn retransmits_mut(&mut self) -> &mut Retransmits {
403 self.sent_frames.retransmits_mut()
404 }
405}
406
407#[derive(Debug, Copy, Clone)]
408pub(super) enum PadDatagram {
409 No,
411 ToSize(u16),
413 ToSegmentSize,
418 ToMinMtu,
420}
421
422impl std::ops::BitOrAssign for PadDatagram {
423 fn bitor_assign(&mut self, rhs: Self) {
424 *self = *self | rhs;
425 }
426}
427
428impl std::ops::BitOr for PadDatagram {
429 type Output = Self;
430
431 fn bitor(self, rhs: Self) -> Self::Output {
432 match (self, rhs) {
433 (Self::No, rhs) => rhs,
434 (Self::ToSize(size), Self::No) => Self::ToSize(size),
435 (Self::ToSize(a), Self::ToSize(b)) => Self::ToSize(a.max(b)),
436 (Self::ToSize(_), Self::ToSegmentSize) => Self::ToSegmentSize,
437 (Self::ToSize(_), Self::ToMinMtu) => Self::ToMinMtu,
438 (Self::ToSegmentSize, Self::No) => Self::ToSegmentSize,
439 (Self::ToSegmentSize, Self::ToSize(_)) => Self::ToSegmentSize,
440 (Self::ToSegmentSize, Self::ToSegmentSize) => Self::ToSegmentSize,
441 (Self::ToSegmentSize, Self::ToMinMtu) => Self::ToMinMtu,
442 (Self::ToMinMtu, _) => Self::ToMinMtu,
443 }
444 }
445}