ant_quic/connection/
stats.rs

1//! Connection statistics
2
3use crate::{Dir, Duration, frame::Frame};
4
5/// Statistics about UDP datagrams transmitted or received on a connection
6#[derive(Default, Debug, Copy, Clone)]
7#[non_exhaustive]
8pub struct UdpStats {
9    /// The amount of UDP datagrams observed
10    pub datagrams: u64,
11    /// The total amount of bytes which have been transferred inside UDP datagrams
12    pub bytes: u64,
13    /// The amount of I/O operations executed
14    ///
15    /// Can be less than `datagrams` when GSO, GRO, and/or batched system calls are in use.
16    pub ios: u64,
17}
18
19impl UdpStats {
20    pub(crate) fn on_sent(&mut self, datagrams: u64, bytes: usize) {
21        self.datagrams += datagrams;
22        self.bytes += bytes as u64;
23        self.ios += 1;
24    }
25}
26
27/// Number of frames transmitted of each frame type
28#[derive(Default, Copy, Clone)]
29#[non_exhaustive]
30#[allow(missing_docs)]
31pub struct FrameStats {
32    pub acks: u64,
33    pub ack_frequency: u64,
34    pub crypto: u64,
35    pub connection_close: u64,
36    pub data_blocked: u64,
37    pub datagram: u64,
38    pub handshake_done: u8,
39    pub immediate_ack: u64,
40    pub max_data: u64,
41    pub max_stream_data: u64,
42    pub max_streams_bidi: u64,
43    pub max_streams_uni: u64,
44    pub new_connection_id: u64,
45    pub new_token: u64,
46    pub path_challenge: u64,
47    pub path_response: u64,
48    pub ping: u64,
49    pub reset_stream: u64,
50    pub retire_connection_id: u64,
51    pub stream_data_blocked: u64,
52    pub streams_blocked_bidi: u64,
53    pub streams_blocked_uni: u64,
54    pub stop_sending: u64,
55    pub stream: u64,
56}
57
58impl FrameStats {
59    pub(crate) fn record(&mut self, frame: &Frame) {
60        match frame {
61            Frame::Padding => {}
62            Frame::Ping => self.ping += 1,
63            Frame::Ack(_) => self.acks += 1,
64            Frame::ResetStream(_) => self.reset_stream += 1,
65            Frame::StopSending(_) => self.stop_sending += 1,
66            Frame::Crypto(_) => self.crypto += 1,
67            Frame::Datagram(_) => self.datagram += 1,
68            Frame::NewToken(_) => self.new_token += 1,
69            Frame::MaxData(_) => self.max_data += 1,
70            Frame::MaxStreamData { .. } => self.max_stream_data += 1,
71            Frame::MaxStreams { dir, .. } => {
72                if *dir == Dir::Bi {
73                    self.max_streams_bidi += 1;
74                } else {
75                    self.max_streams_uni += 1;
76                }
77            }
78            Frame::DataBlocked { .. } => self.data_blocked += 1,
79            Frame::Stream(_) => self.stream += 1,
80            Frame::StreamDataBlocked { .. } => self.stream_data_blocked += 1,
81            Frame::StreamsBlocked { dir, .. } => {
82                if *dir == Dir::Bi {
83                    self.streams_blocked_bidi += 1;
84                } else {
85                    self.streams_blocked_uni += 1;
86                }
87            }
88            Frame::NewConnectionId(_) => self.new_connection_id += 1,
89            Frame::RetireConnectionId { .. } => self.retire_connection_id += 1,
90            Frame::PathChallenge(_) => self.path_challenge += 1,
91            Frame::PathResponse(_) => self.path_response += 1,
92            Frame::Close(_) => self.connection_close += 1,
93            Frame::AckFrequency(_) => self.ack_frequency += 1,
94            Frame::ImmediateAck => self.immediate_ack += 1,
95            Frame::HandshakeDone => self.handshake_done = self.handshake_done.saturating_add(1),
96            Frame::AddAddress(_) => { /* NAT traversal frames - not counted in basic stats */ }
97            Frame::PunchMeNow(_) => { /* NAT traversal frames - not counted in basic stats */ }
98            Frame::RemoveAddress(_) => { /* NAT traversal frames - not counted in basic stats */ }
99        }
100    }
101}
102
103impl std::fmt::Debug for FrameStats {
104    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
105        f.debug_struct("FrameStats")
106            .field("ACK", &self.acks)
107            .field("ACK_FREQUENCY", &self.ack_frequency)
108            .field("CONNECTION_CLOSE", &self.connection_close)
109            .field("CRYPTO", &self.crypto)
110            .field("DATA_BLOCKED", &self.data_blocked)
111            .field("DATAGRAM", &self.datagram)
112            .field("HANDSHAKE_DONE", &self.handshake_done)
113            .field("IMMEDIATE_ACK", &self.immediate_ack)
114            .field("MAX_DATA", &self.max_data)
115            .field("MAX_STREAM_DATA", &self.max_stream_data)
116            .field("MAX_STREAMS_BIDI", &self.max_streams_bidi)
117            .field("MAX_STREAMS_UNI", &self.max_streams_uni)
118            .field("NEW_CONNECTION_ID", &self.new_connection_id)
119            .field("NEW_TOKEN", &self.new_token)
120            .field("PATH_CHALLENGE", &self.path_challenge)
121            .field("PATH_RESPONSE", &self.path_response)
122            .field("PING", &self.ping)
123            .field("RESET_STREAM", &self.reset_stream)
124            .field("RETIRE_CONNECTION_ID", &self.retire_connection_id)
125            .field("STREAM_DATA_BLOCKED", &self.stream_data_blocked)
126            .field("STREAMS_BLOCKED_BIDI", &self.streams_blocked_bidi)
127            .field("STREAMS_BLOCKED_UNI", &self.streams_blocked_uni)
128            .field("STOP_SENDING", &self.stop_sending)
129            .field("STREAM", &self.stream)
130            .finish()
131    }
132}
133
134/// Statistics related to a transmission path
135#[derive(Debug, Default, Copy, Clone)]
136#[non_exhaustive]
137pub struct PathStats {
138    /// Current best estimate of this connection's latency (round-trip-time)
139    pub rtt: Duration,
140    /// Current congestion window of the connection
141    pub cwnd: u64,
142    /// Congestion events on the connection
143    pub congestion_events: u64,
144    /// The amount of packets lost on this path
145    pub lost_packets: u64,
146    /// The amount of bytes lost on this path
147    pub lost_bytes: u64,
148    /// The amount of packets sent on this path
149    pub sent_packets: u64,
150    /// The amount of PLPMTUD probe packets sent on this path (also counted by `sent_packets`)
151    pub sent_plpmtud_probes: u64,
152    /// The amount of PLPMTUD probe packets lost on this path (ignored by `lost_packets` and
153    /// `lost_bytes`)
154    pub lost_plpmtud_probes: u64,
155    /// The number of times a black hole was detected in the path
156    pub black_holes_detected: u64,
157    /// Largest UDP payload size the path currently supports
158    pub current_mtu: u16,
159}
160
161/// Connection statistics
162#[derive(Debug, Default, Copy, Clone)]
163#[non_exhaustive]
164pub struct ConnectionStats {
165    /// Statistics about UDP datagrams transmitted on a connection
166    pub udp_tx: UdpStats,
167    /// Statistics about UDP datagrams received on a connection
168    pub udp_rx: UdpStats,
169    /// Statistics about frames transmitted on a connection
170    pub frame_tx: FrameStats,
171    /// Statistics about frames received on a connection
172    pub frame_rx: FrameStats,
173    /// Statistics related to the current transmission path
174    pub path: PathStats,
175}