ant_quic/connection/
stats.rs

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