s2n_quic_core/recovery/
sent_packets.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::{
5    frame::ack_elicitation::AckElicitation, inet::ExplicitCongestionNotification, path,
6    time::Timestamp, transmission,
7};
8
9//= https://www.rfc-editor.org/rfc/rfc9002#appendix-A.1
10
11//= https://www.rfc-editor.org/rfc/rfc9002#appendix-A.1.1
12
13#[cfg(feature = "alloc")]
14pub type SentPackets<PacketInfo> = crate::packet::number::Map<SentPacketInfo<PacketInfo>>;
15
16#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
17#[non_exhaustive]
18pub struct SentPacketInfo<PacketInfo> {
19    /// Indicates whether the packet counts towards bytes in flight
20    pub congestion_controlled: bool,
21    /// The number of bytes sent in the packet, not including UDP or IP overhead,
22    /// but including QUIC framing overhead
23    pub sent_bytes: u16,
24    /// The time the packet was sent
25    pub time_sent: Timestamp,
26    /// Indicates whether a packet is ack-eliciting
27    pub ack_elicitation: AckElicitation,
28    /// The ID of the Path the packet was sent on
29    pub path_id: path::Id,
30    /// The ECN marker (if any) sent on the datagram that contained this packet
31    pub ecn: ExplicitCongestionNotification,
32    /// Indicates if the packet was part of a probe transmission
33    pub transmission_mode: transmission::Mode,
34    /// Additional packet metadata dictated by the congestion controller
35    pub cc_packet_info: PacketInfo,
36}
37
38impl<PacketInfo> SentPacketInfo<PacketInfo> {
39    pub fn new(
40        congestion_controlled: bool,
41        sent_bytes: usize,
42        time_sent: Timestamp,
43        ack_elicitation: AckElicitation,
44        path_id: path::Id,
45        ecn: ExplicitCongestionNotification,
46        transmission_mode: transmission::Mode,
47        cc_packet_info: PacketInfo,
48    ) -> Self {
49        debug_assert_eq!(
50            sent_bytes > 0,
51            congestion_controlled,
52            "sent bytes should be zero for packets that are not congestion controlled"
53        );
54
55        SentPacketInfo {
56            congestion_controlled,
57            sent_bytes: sent_bytes
58                .try_into()
59                .expect("sent_bytes exceeds max UDP payload size"),
60            time_sent,
61            ack_elicitation,
62            path_id,
63            ecn,
64            transmission_mode,
65            cc_packet_info,
66        }
67    }
68}
69
70#[cfg(test)]
71mod test {
72    use crate::{
73        frame::ack_elicitation::AckElicitation,
74        inet::ExplicitCongestionNotification,
75        path,
76        recovery::SentPacketInfo,
77        time::{Clock, NoopClock},
78        transmission,
79    };
80
81    #[test]
82    #[should_panic]
83    fn too_large_packet() {
84        SentPacketInfo::new(
85            true,
86            u16::MAX as usize + 1,
87            NoopClock.get_time(),
88            AckElicitation::Eliciting,
89            unsafe { path::Id::new(0) },
90            ExplicitCongestionNotification::default(),
91            transmission::Mode::Normal,
92            (),
93        );
94    }
95
96    #[test]
97    #[cfg_attr(miri, ignore)] // snapshot tests don't work on miri
98    fn sent_packet_info_size_test() {
99        insta::assert_debug_snapshot!(
100            stringify!(sent_packet_info_size_test),
101            core::mem::size_of::<SentPacketInfo<()>>()
102        );
103
104        assert_eq!(
105            core::mem::size_of::<Option<SentPacketInfo<()>>>(),
106            core::mem::size_of::<SentPacketInfo<()>>()
107        );
108    }
109}