1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
use std::{fmt, net::SocketAddr};
use bytes::{Buf, BufMut, BytesMut};
use crate::FourTuple;
use crate::PathId;
use crate::{Duration, Instant, MAX_CID_SIZE, ResetToken, coding::BufExt, packet::PartialDecode};
/// Events sent from an Endpoint to a Connection
#[derive(Debug)]
pub struct ConnectionEvent(pub(crate) ConnectionEventInner);
#[derive(Debug)]
pub(crate) enum ConnectionEventInner {
/// A datagram has been received for the Connection
Datagram(DatagramConnectionEvent),
/// New connection identifiers have been issued for the Connection
NewIdentifiers(Vec<IssuedCid>, Instant, usize, Option<Duration>),
}
/// Variant of [`ConnectionEventInner`].
#[derive(Debug)]
pub(crate) struct DatagramConnectionEvent {
pub(crate) now: Instant,
pub(crate) network_path: FourTuple,
pub(crate) path_id: PathId,
pub(crate) ecn: Option<EcnCodepoint>,
pub(crate) first_decode: PartialDecode,
pub(crate) remaining: Option<BytesMut>,
}
/// Events sent from a Connection to an Endpoint
#[derive(Debug)]
pub struct EndpointEvent(pub(crate) EndpointEventInner);
impl EndpointEvent {
/// Construct an event that indicating that a `Connection` will no longer emit events
///
/// Useful for notifying an `Endpoint` that a `Connection` has been destroyed outside of the
/// usual state machine flow, e.g. when being dropped by the user.
pub fn drained() -> Self {
Self(EndpointEventInner::Drained)
}
/// Determine whether this is the last event a `Connection` will emit
///
/// Useful for determining when connection-related event loop state can be freed.
pub fn is_drained(&self) -> bool {
self.0 == EndpointEventInner::Drained
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub(crate) enum EndpointEventInner {
/// The connection has been drained
Drained,
/// The connection has a new active reset token
///
/// Whenever the connection switches to a new remote CID issued by the peer, it also
/// switches the matching reset token that can be used to abort this connection. This
/// event provides a new reset token for the active remote CID.
ResetToken(PathId, SocketAddr, ResetToken),
/// Retire the remotely issued reset token for a path, without replacing it with a new one
///
/// This is like `ResetToken` above, but without replacing the `ResetToken` with a new
/// one. See `ConnectionIndex::connection_reset_tokens`.
RetireResetToken(PathId),
/// The connection needs connection identifiers.
///
/// The fields are:
/// - The path ID for which the identifiers are needed.
/// - The time when the identifiers were needed, not used to generate the CIDs but sent
/// back via the [`ConnectionEventInner::NewIdentifiers`] so the connection can track
/// the lifetime of when it needs to be rotated. should be rotated.
/// - The number of CIDs needed.
NeedIdentifiers(PathId, Instant, u64),
/// Retire a locally issued CID
///
/// Stop routing connection ID for this sequence number to the connection
/// When `bool == true`, a new connection ID will be issued to peer
RetireConnectionId(Instant, PathId, u64, bool),
}
/// Protocol-level identifier for a connection.
///
/// Mainly useful for identifying this connection's packets on the wire with tools like Wireshark.
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[cfg_attr(test, derive(test_strategy::Arbitrary))]
pub struct ConnectionId {
/// length of CID
#[cfg_attr(test, strategy(1u8..=MAX_CID_SIZE as u8))]
len: u8,
/// CID in byte array
bytes: [u8; MAX_CID_SIZE],
}
impl ConnectionId {
/// Construct cid from byte array
pub fn new(bytes: &[u8]) -> Self {
debug_assert!(bytes.len() <= MAX_CID_SIZE);
let mut res = Self {
len: bytes.len() as u8,
bytes: [0; MAX_CID_SIZE],
};
res.bytes[..bytes.len()].copy_from_slice(bytes);
res
}
/// Constructs cid by reading `len` bytes from a `Buf`
///
/// Callers need to assure that `buf.remaining() >= len`
pub fn from_buf(buf: &mut (impl Buf + ?Sized), len: usize) -> Self {
debug_assert!(len <= MAX_CID_SIZE);
let mut res = Self {
len: len as u8,
bytes: [0; MAX_CID_SIZE],
};
buf.copy_to_slice(&mut res[..len]);
res
}
pub(crate) fn len(&self) -> usize {
self.len as usize
}
/// Decode from long header format
pub(crate) fn decode_long(buf: &mut impl Buf) -> Option<Self> {
let len = buf.get::<u8>().ok()? as usize;
match len > MAX_CID_SIZE || buf.remaining() < len {
false => Some(Self::from_buf(buf, len)),
true => None,
}
}
/// Encode in long header format
pub(crate) fn encode_long(&self, buf: &mut impl BufMut) {
buf.put_u8(self.len() as u8);
buf.put_slice(self);
}
}
impl ::std::ops::Deref for ConnectionId {
type Target = [u8];
fn deref(&self) -> &[u8] {
&self.bytes[0..self.len as usize]
}
}
impl ::std::ops::DerefMut for ConnectionId {
fn deref_mut(&mut self) -> &mut [u8] {
&mut self.bytes[0..self.len as usize]
}
}
impl fmt::Debug for ConnectionId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.bytes[0..self.len as usize].fmt(f)
}
}
impl fmt::Display for ConnectionId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for byte in self.iter() {
write!(f, "{byte:02x}")?;
}
Ok(())
}
}
/// Explicit congestion notification codepoint
#[repr(u8)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum EcnCodepoint {
/// The ECT(0) codepoint, indicating that an endpoint is ECN-capable
Ect0 = 0b10,
/// The ECT(1) codepoint, indicating that an endpoint is ECN-capable
Ect1 = 0b01,
/// The CE codepoint, signalling that congestion was experienced
Ce = 0b11,
}
impl EcnCodepoint {
/// Create new object from the given bits
pub fn from_bits(x: u8) -> Option<Self> {
use EcnCodepoint::*;
Some(match x & 0b11 {
0b10 => Ect0,
0b01 => Ect1,
0b11 => Ce,
_ => {
return None;
}
})
}
/// Returns whether the codepoint is a CE, signalling that congestion was experienced
pub fn is_ce(self) -> bool {
matches!(self, Self::Ce)
}
}
#[derive(Debug, Copy, Clone)]
pub(crate) struct IssuedCid {
pub(crate) path_id: PathId,
pub(crate) sequence: u64,
pub(crate) id: ConnectionId,
pub(crate) reset_token: ResetToken,
}