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