iroh_quinn_proto/connection/
state.rs1use bytes::Bytes;
2use tracing::trace;
3
4use crate::frame::Close;
5use crate::{ApplicationClose, ConnectionClose, ConnectionError, TransportError, TransportErrorCode};
6
7#[allow(unreachable_pub)] #[derive(Debug, Clone)]
9pub struct State {
10 inner: InnerState,
12}
13
14impl State {
15 pub(super) fn as_handshake_mut(&mut self) -> Option<&mut Handshake> {
16 if let InnerState::Handshake(ref mut hs) = self.inner {
17 Some(hs)
18 } else {
19 None
20 }
21 }
22
23 pub(super) fn as_handshake(&self) -> Option<&Handshake> {
24 if let InnerState::Handshake(ref hs) = self.inner {
25 Some(hs)
26 } else {
27 None
28 }
29 }
30
31 pub(super) fn as_closed(&self) -> Option<&CloseReason> {
32 if let InnerState::Closed {
33 ref remote_reason, ..
34 } = self.inner
35 {
36 Some(remote_reason)
37 } else {
38 None
39 }
40 }
41
42 #[allow(unreachable_pub)] #[cfg(any(test, fuzzing))]
44 pub fn established() -> Self {
45 Self {
46 inner: InnerState::Established,
47 }
48 }
49
50 pub(super) fn handshake(hs: Handshake) -> Self {
51 Self {
52 inner: InnerState::Handshake(hs),
53 }
54 }
55
56 pub(super) fn move_to_handshake(&mut self, hs: Handshake) {
57 self.inner = InnerState::Handshake(hs);
58 trace!("connection state: handshake");
59 }
60
61 pub(super) fn move_to_established(&mut self) {
62 self.inner = InnerState::Established;
63 trace!("connection state: established");
64 }
65
66 pub(super) fn move_to_drained(&mut self, error: Option<ConnectionError>) {
70 let (error, is_local) = if let Some(error) = error {
71 (Some(error), false)
72 } else {
73 let error = match &mut self.inner {
74 InnerState::Draining { error, .. } => error.take(),
75 InnerState::Drained { .. } => panic!("invalid state transition drained -> drained"),
76 InnerState::Closed { error_read, .. } if *error_read => None,
77 InnerState::Closed { remote_reason, .. } => {
78 let error = match remote_reason.clone().into() {
79 ConnectionError::ConnectionClosed(close) => {
80 if close.error_code == TransportErrorCode::PROTOCOL_VIOLATION {
81 ConnectionError::TransportError(TransportError::new(
82 close.error_code,
83 std::string::String::from_utf8_lossy(&close.reason[..])
84 .to_string(),
85 ))
86 } else {
87 ConnectionError::ConnectionClosed(close)
88 }
89 }
90 e => e,
91 };
92 Some(error)
93 }
94 InnerState::Handshake(_) | InnerState::Established => None,
95 };
96 (error, self.is_local_close())
97 };
98 self.inner = InnerState::Drained { error, is_local };
99 trace!("connection state: drained");
100 }
101
102 pub(super) fn move_to_draining(&mut self, error: Option<ConnectionError>) {
106 assert!(
107 matches!(
108 self.inner,
109 InnerState::Handshake(_) | InnerState::Established | InnerState::Closed { .. }
110 ),
111 "invalid state transition {:?} -> draining",
112 self.as_type()
113 );
114 let is_local = self.is_local_close();
115 self.inner = InnerState::Draining { error, is_local };
116 trace!("connection state: draining");
117 }
118
119 fn is_local_close(&self) -> bool {
120 match self.inner {
121 InnerState::Handshake(_) => false,
122 InnerState::Established => false,
123 InnerState::Closed { is_local, .. } => is_local,
124 InnerState::Draining { is_local, .. } => is_local,
125 InnerState::Drained { is_local, .. } => is_local,
126 }
127 }
128
129 pub(super) fn move_to_closed<R: Into<CloseReason>>(&mut self, reason: R) {
133 assert!(
134 matches!(
135 self.inner,
136 InnerState::Handshake(_) | InnerState::Established | InnerState::Closed { .. }
137 ),
138 "invalid state transition {:?} -> closed",
139 self.as_type()
140 );
141 let remote_reason = reason.into();
142 let is_local = false;
143 trace!(?remote_reason, ?is_local, "connection state: closed");
144 self.inner = InnerState::Closed {
145 error_read: false,
146 remote_reason,
147 is_local,
148 };
149 }
150
151 pub(super) fn move_to_closed_local<R: Into<CloseReason>>(&mut self, reason: R) {
155 assert!(
156 matches!(
157 self.inner,
158 InnerState::Handshake(_) | InnerState::Established | InnerState::Closed { .. }
159 ),
160 "invalid state transition {:?} -> closed (local)",
161 self.as_type()
162 );
163 let remote_reason = reason.into();
164 let is_local = true;
165 trace!(?remote_reason, ?is_local, "connection state: closed");
166 self.inner = InnerState::Closed {
167 error_read: false,
168 remote_reason,
169 is_local,
170 };
171 }
172
173 pub(super) fn is_handshake(&self) -> bool {
174 matches!(self.inner, InnerState::Handshake(_))
175 }
176
177 pub(super) fn is_established(&self) -> bool {
178 matches!(self.inner, InnerState::Established)
179 }
180
181 pub(super) fn is_closed(&self) -> bool {
182 matches!(
183 self.inner,
184 InnerState::Closed { .. } | InnerState::Draining { .. } | InnerState::Drained { .. }
185 )
186 }
187
188 pub(super) fn is_drained(&self) -> bool {
189 matches!(self.inner, InnerState::Drained { .. })
190 }
191
192 pub(super) fn take_error(&mut self) -> Option<ConnectionError> {
193 match &mut self.inner {
194 InnerState::Draining { error, is_local } => {
195 if !*is_local {
196 error.take()
197 } else {
198 None
199 }
200 }
201 InnerState::Drained { error, is_local } => {
202 if !*is_local {
203 error.take()
204 } else {
205 None
206 }
207 }
208 InnerState::Closed {
209 remote_reason,
210 is_local: local_reason,
211 error_read,
212 } => {
213 if *error_read {
214 None
215 } else {
216 *error_read = true;
217 if *local_reason {
218 None
219 } else {
220 Some(remote_reason.clone().into())
221 }
222 }
223 }
224 InnerState::Handshake(_) | InnerState::Established => None,
225 }
226 }
227
228 pub(super) fn as_type(&self) -> StateType {
229 match self.inner {
230 InnerState::Handshake(_) => StateType::Handshake,
231 InnerState::Established => StateType::Established,
232 InnerState::Closed { .. } => StateType::Closed,
233 InnerState::Draining { .. } => StateType::Draining,
234 InnerState::Drained { .. } => StateType::Drained,
235 }
236 }
237}
238
239#[derive(Debug, Clone)]
240pub(super) enum StateType {
241 Handshake,
242 Established,
243 Closed,
244 Draining,
245 Drained,
246}
247
248#[derive(Debug, Clone)]
249pub(super) enum CloseReason {
250 TransportError(TransportError),
251 Connection(ConnectionClose),
252 Application(ApplicationClose),
253}
254
255impl From<TransportError> for CloseReason {
256 fn from(x: TransportError) -> Self {
257 Self::TransportError(x)
258 }
259}
260impl From<ConnectionClose> for CloseReason {
261 fn from(x: ConnectionClose) -> Self {
262 Self::Connection(x)
263 }
264}
265impl From<ApplicationClose> for CloseReason {
266 fn from(x: ApplicationClose) -> Self {
267 Self::Application(x)
268 }
269}
270
271impl From<Close> for CloseReason {
272 fn from(value: Close) -> Self {
273 match value {
274 Close::Application(reason) => Self::Application(reason),
275 Close::Connection(reason) => Self::Connection(reason),
276 }
277 }
278}
279
280impl From<CloseReason> for ConnectionError {
281 fn from(value: CloseReason) -> Self {
282 match value {
283 CloseReason::TransportError(err) => Self::TransportError(err),
284 CloseReason::Connection(reason) => Self::ConnectionClosed(reason),
285 CloseReason::Application(reason) => Self::ApplicationClosed(reason),
286 }
287 }
288}
289
290impl From<CloseReason> for Close {
291 fn from(value: CloseReason) -> Self {
292 match value {
293 CloseReason::TransportError(err) => Self::Connection(err.into()),
294 CloseReason::Connection(reason) => Self::Connection(reason),
295 CloseReason::Application(reason) => Self::Application(reason),
296 }
297 }
298}
299
300#[derive(Debug, Clone)]
301enum InnerState {
302 Handshake(Handshake),
303 Established,
304 Closed {
305 remote_reason: CloseReason,
307 is_local: bool,
309 error_read: bool,
311 },
312 Draining {
313 error: Option<ConnectionError>,
315 is_local: bool,
317 },
318 Drained {
320 error: Option<ConnectionError>,
322 is_local: bool,
324 },
325}
326
327#[allow(unreachable_pub)] #[derive(Debug, Clone)]
329pub struct Handshake {
330 pub(super) rem_cid_set: bool,
334 pub(super) expected_token: Bytes,
338 pub(super) client_hello: Option<Bytes>,
342 pub(super) allow_server_migration: bool,
357}