ant_quic/
connection_lifecycle.rs1use std::fmt;
2
3use crate::{ConnectionError, VarInt};
4
5pub const ANT_QUIC_CLOSE_CODE_BASE: u32 = 0x4E5B00;
9const CLOSE_CODE_SUPERSEDED: u32 = ANT_QUIC_CLOSE_CODE_BASE;
10const CLOSE_CODE_READER_EXIT: u32 = ANT_QUIC_CLOSE_CODE_BASE + 0x01;
11const CLOSE_CODE_PEER_SHUTDOWN: u32 = ANT_QUIC_CLOSE_CODE_BASE + 0x02;
12const CLOSE_CODE_BANNED: u32 = ANT_QUIC_CLOSE_CODE_BASE + 0x03;
13const CLOSE_CODE_LIFECYCLE_CLEANUP: u32 = ANT_QUIC_CLOSE_CODE_BASE + 0x04;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
17pub enum ConnectionCloseReason {
18 Superseded,
20 ReaderExit,
22 PeerShutdown,
24 Banned,
26 LifecycleCleanup,
28 ApplicationClosed,
30 ConnectionClosed,
32 TimedOut,
34 Reset,
36 TransportError,
38 LocallyClosed,
40 VersionMismatch,
42 CidsExhausted,
44 Unknown,
46}
47
48impl ConnectionCloseReason {
49 pub fn app_error_code(self) -> Option<VarInt> {
51 let code = match self {
52 Self::Superseded => CLOSE_CODE_SUPERSEDED,
53 Self::ReaderExit => CLOSE_CODE_READER_EXIT,
54 Self::PeerShutdown => CLOSE_CODE_PEER_SHUTDOWN,
55 Self::Banned => CLOSE_CODE_BANNED,
56 Self::LifecycleCleanup => CLOSE_CODE_LIFECYCLE_CLEANUP,
57 Self::ApplicationClosed
58 | Self::ConnectionClosed
59 | Self::TimedOut
60 | Self::Reset
61 | Self::TransportError
62 | Self::LocallyClosed
63 | Self::VersionMismatch
64 | Self::CidsExhausted
65 | Self::Unknown => return None,
66 };
67 Some(VarInt::from_u32(code))
68 }
69
70 pub fn as_str(self) -> &'static str {
72 match self {
73 Self::Superseded => "Superseded",
74 Self::ReaderExit => "ReaderExit",
75 Self::PeerShutdown => "PeerShutdown",
76 Self::Banned => "Banned",
77 Self::LifecycleCleanup => "LifecycleCleanup",
78 Self::ApplicationClosed => "ApplicationClosed",
79 Self::ConnectionClosed => "ConnectionClosed",
80 Self::TimedOut => "TimedOut",
81 Self::Reset => "Reset",
82 Self::TransportError => "TransportError",
83 Self::LocallyClosed => "LocallyClosed",
84 Self::VersionMismatch => "VersionMismatch",
85 Self::CidsExhausted => "CidsExhausted",
86 Self::Unknown => "Unknown",
87 }
88 }
89
90 pub fn reason_bytes(self) -> &'static [u8] {
92 self.as_str().as_bytes()
93 }
94
95 pub fn from_app_error_code(code: VarInt) -> Option<Self> {
97 match code.into_inner() as u32 {
98 CLOSE_CODE_SUPERSEDED => Some(Self::Superseded),
99 CLOSE_CODE_READER_EXIT => Some(Self::ReaderExit),
100 CLOSE_CODE_PEER_SHUTDOWN => Some(Self::PeerShutdown),
101 CLOSE_CODE_BANNED => Some(Self::Banned),
102 CLOSE_CODE_LIFECYCLE_CLEANUP => Some(Self::LifecycleCleanup),
103 _ => None,
104 }
105 }
106
107 pub fn from_connection_error(error: &ConnectionError) -> Self {
109 match error {
110 ConnectionError::ApplicationClosed(frame) => {
111 Self::from_app_error_code(frame.error_code).unwrap_or(Self::ApplicationClosed)
112 }
113 ConnectionError::ConnectionClosed(_) => Self::ConnectionClosed,
114 ConnectionError::TransportError(_) => Self::TransportError,
115 ConnectionError::VersionMismatch => Self::VersionMismatch,
116 ConnectionError::Reset => Self::Reset,
117 ConnectionError::TimedOut => Self::TimedOut,
118 ConnectionError::LocallyClosed => Self::LocallyClosed,
119 ConnectionError::CidsExhausted => Self::CidsExhausted,
120 }
121 }
122}
123
124impl fmt::Display for ConnectionCloseReason {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 f.write_str(self.as_str())
127 }
128}
129
130#[derive(Debug, Clone, Copy, PartialEq, Eq)]
131pub(crate) enum ConnectionLifecycleState {
132 Live,
133 Superseded {
134 replaced_by_generation: u64,
135 },
136 Closing {
137 reason: ConnectionCloseReason,
138 },
139 Closed {
140 reason: ConnectionCloseReason,
141 closed_at_unix_ms: u64,
142 },
143}
144
145impl ConnectionLifecycleState {
146 pub(crate) fn name(self) -> &'static str {
147 match self {
148 Self::Live => "Live",
149 Self::Superseded { .. } => "Superseded",
150 Self::Closing { .. } => "Closing",
151 Self::Closed { .. } => "Closed",
152 }
153 }
154}