net_wire/quic/transport_parameters/
value.rs1use core::fmt;
4
5use super::super::packet::header::QuicConnectionId;
6use super::super::varint::{QuicVarInt, QuicVarIntParseError};
7use super::{QuicTransportParameter, QuicTransportParameterId};
8
9#[derive(Clone, Copy, Debug, Eq, PartialEq)]
11pub enum QuicTransportParameterValueKind {
12 Integer,
14 ConnectionId,
16 StatelessResetToken,
18 DisableActiveMigration,
20 PreferredAddress,
22}
23
24#[derive(Clone, Copy, Debug, Eq, PartialEq)]
29pub enum QuicTransportParameterValueError {
30 WrongId {
32 kind: QuicTransportParameterValueKind,
34 actual: QuicTransportParameterId,
36 },
37 MalformedInteger {
39 error: QuicVarIntParseError,
41 },
42 TrailingIntegerBytes {
44 parsed: usize,
46 available: usize,
48 },
49 WrongLength {
51 kind: QuicTransportParameterValueKind,
53 expected: usize,
55 actual: usize,
57 },
58 ConnectionIdTooLong {
60 maximum: usize,
62 actual: usize,
64 },
65 PreferredAddressConnectionIdLength {
67 actual: u8,
69 },
70 PreferredAddressIncomplete {
72 offset: usize,
74 required: usize,
76 available: usize,
78 },
79 PreferredAddressTrailingBytes {
81 offset: usize,
83 available: usize,
85 },
86}
87
88impl fmt::Display for QuicTransportParameterValueError {
89 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90 match self {
91 Self::WrongId { kind, actual } => write!(
92 f,
93 "QUIC transport parameter ID {} does not have the {kind:?} payload layout",
94 actual.raw()
95 ),
96 Self::MalformedInteger { error } => {
97 write!(
98 f,
99 "QUIC transport parameter integer payload cannot be parsed: {error}"
100 )
101 }
102 Self::TrailingIntegerBytes { parsed, available } => write!(
103 f,
104 "QUIC transport parameter integer payload has trailing bytes: integer uses {parsed} bytes, payload has {available}"
105 ),
106 Self::WrongLength {
107 kind,
108 expected,
109 actual,
110 } => write!(
111 f,
112 "QUIC transport parameter {kind:?} payload has wrong length: need {expected} bytes, have {actual}"
113 ),
114 Self::ConnectionIdTooLong { maximum, actual } => write!(
115 f,
116 "QUIC transport parameter connection ID is too long: maximum {maximum} bytes, have {actual}"
117 ),
118 Self::PreferredAddressConnectionIdLength { actual } => write!(
119 f,
120 "QUIC preferred-address connection-ID length is outside 1..=20: {actual}"
121 ),
122 Self::PreferredAddressIncomplete {
123 offset,
124 required,
125 available,
126 } => write!(
127 f,
128 "QUIC preferred-address value at offset {offset} is incomplete: need {required} bytes, have {available}"
129 ),
130 Self::PreferredAddressTrailingBytes { offset, available } => write!(
131 f,
132 "QUIC preferred-address value has {available} trailing bytes at offset {offset}"
133 ),
134 }
135 }
136}
137
138#[derive(Clone, Copy, Debug, Eq, PartialEq)]
140pub struct QuicPreferredAddress<'a> {
141 bytes: &'a [u8],
142 ipv4_address: &'a [u8; 4],
143 ipv4_port: u16,
144 ipv6_address: &'a [u8; 16],
145 ipv6_port: u16,
146 connection_id: QuicConnectionId<'a>,
147 stateless_reset_token: &'a [u8; 16],
148}
149
150impl<'a> QuicPreferredAddress<'a> {
151 pub const fn as_bytes(self) -> &'a [u8] {
153 self.bytes
154 }
155
156 pub const fn ipv4_address(self) -> &'a [u8; 4] {
158 self.ipv4_address
159 }
160
161 pub const fn ipv4_port(self) -> u16 {
163 self.ipv4_port
164 }
165
166 pub const fn ipv6_address(self) -> &'a [u8; 16] {
168 self.ipv6_address
169 }
170
171 pub const fn ipv6_port(self) -> u16 {
173 self.ipv6_port
174 }
175
176 pub const fn connection_id(self) -> QuicConnectionId<'a> {
178 self.connection_id
179 }
180
181 pub const fn stateless_reset_token(self) -> &'a [u8; 16] {
183 self.stateless_reset_token
184 }
185}
186
187impl<'a> QuicTransportParameter<'a> {
188 pub fn integer(self) -> Result<QuicVarInt<'a>, QuicTransportParameterValueError> {
190 if !is_integer_id(self.parameter_id()) {
191 return Err(wrong_id(
192 QuicTransportParameterValueKind::Integer,
193 self.parameter_id(),
194 ));
195 }
196 let value = QuicVarInt::parse(self.value)
197 .map_err(|error| QuicTransportParameterValueError::MalformedInteger { error })?;
198 if value.byte_len() != self.value.len() {
199 return Err(QuicTransportParameterValueError::TrailingIntegerBytes {
200 parsed: value.byte_len(),
201 available: self.value.len(),
202 });
203 }
204 Ok(value)
205 }
206
207 pub fn connection_id(self) -> Result<QuicConnectionId<'a>, QuicTransportParameterValueError> {
209 if !is_connection_id_id(self.parameter_id()) {
210 return Err(wrong_id(
211 QuicTransportParameterValueKind::ConnectionId,
212 self.parameter_id(),
213 ));
214 }
215 if self.value.len() > 20 {
216 return Err(QuicTransportParameterValueError::ConnectionIdTooLong {
217 maximum: 20,
218 actual: self.value.len(),
219 });
220 }
221 Ok(QuicConnectionId::new(self.value))
222 }
223
224 pub fn stateless_reset_token(self) -> Result<&'a [u8; 16], QuicTransportParameterValueError> {
226 if self.parameter_id() != QuicTransportParameterId::STATELESS_RESET_TOKEN {
227 return Err(wrong_id(
228 QuicTransportParameterValueKind::StatelessResetToken,
229 self.parameter_id(),
230 ));
231 }
232 if self.value.len() != 16 {
233 return Err(QuicTransportParameterValueError::WrongLength {
234 kind: QuicTransportParameterValueKind::StatelessResetToken,
235 expected: 16,
236 actual: self.value.len(),
237 });
238 }
239 self.value
240 .try_into()
241 .map_err(|_| QuicTransportParameterValueError::WrongLength {
242 kind: QuicTransportParameterValueKind::StatelessResetToken,
243 expected: 16,
244 actual: self.value.len(),
245 })
246 }
247
248 pub fn disable_active_migration(self) -> Result<(), QuicTransportParameterValueError> {
250 if self.parameter_id() != QuicTransportParameterId::DISABLE_ACTIVE_MIGRATION {
251 return Err(wrong_id(
252 QuicTransportParameterValueKind::DisableActiveMigration,
253 self.parameter_id(),
254 ));
255 }
256 if !self.value.is_empty() {
257 return Err(QuicTransportParameterValueError::WrongLength {
258 kind: QuicTransportParameterValueKind::DisableActiveMigration,
259 expected: 0,
260 actual: self.value.len(),
261 });
262 }
263 Ok(())
264 }
265
266 pub fn preferred_address(
268 self,
269 ) -> Result<QuicPreferredAddress<'a>, QuicTransportParameterValueError> {
270 if self.parameter_id() != QuicTransportParameterId::PREFERRED_ADDRESS {
271 return Err(wrong_id(
272 QuicTransportParameterValueKind::PreferredAddress,
273 self.parameter_id(),
274 ));
275 }
276 parse_preferred_address(self.value)
277 }
278}
279
280fn wrong_id(
281 kind: QuicTransportParameterValueKind,
282 actual: QuicTransportParameterId,
283) -> QuicTransportParameterValueError {
284 QuicTransportParameterValueError::WrongId { kind, actual }
285}
286
287const fn is_integer_id(id: QuicTransportParameterId) -> bool {
288 matches!(
289 id.raw(),
290 0x01 | 0x03 | 0x04 | 0x05 | 0x06 | 0x07 | 0x08 | 0x09 | 0x0a | 0x0b | 0x0e
291 )
292}
293
294const fn is_connection_id_id(id: QuicTransportParameterId) -> bool {
295 matches!(id.raw(), 0x00 | 0x0f | 0x10)
296}
297
298fn preferred_incomplete(
299 offset: usize,
300 required: usize,
301 available: usize,
302) -> QuicTransportParameterValueError {
303 QuicTransportParameterValueError::PreferredAddressIncomplete {
304 offset,
305 required,
306 available,
307 }
308}
309
310fn parse_preferred_address<'a>(
311 bytes: &'a [u8],
312) -> Result<QuicPreferredAddress<'a>, QuicTransportParameterValueError> {
313 let available = bytes.len();
314 if available < 4 {
315 return Err(preferred_incomplete(0, 4, available));
316 }
317 if available < 6 {
318 return Err(preferred_incomplete(4, 6, available));
319 }
320 if available < 22 {
321 return Err(preferred_incomplete(6, 22, available));
322 }
323 if available < 24 {
324 return Err(preferred_incomplete(22, 24, available));
325 }
326 if available < 25 {
327 return Err(preferred_incomplete(24, 25, available));
328 }
329
330 let connection_id_len = usize::from(bytes[24]);
331 if connection_id_len == 0 || connection_id_len > 20 {
332 return Err(
333 QuicTransportParameterValueError::PreferredAddressConnectionIdLength {
334 actual: bytes[24],
335 },
336 );
337 }
338 let connection_id_end = 25 + connection_id_len;
339 if available < connection_id_end {
340 return Err(preferred_incomplete(25, connection_id_end, available));
341 }
342 let token_end = connection_id_end + 16;
343 if available < token_end {
344 return Err(preferred_incomplete(
345 connection_id_end,
346 token_end,
347 available,
348 ));
349 }
350 if available > token_end {
351 return Err(
352 QuicTransportParameterValueError::PreferredAddressTrailingBytes {
353 offset: token_end,
354 available: available - token_end,
355 },
356 );
357 }
358
359 let ipv4_address = bytes[..4]
360 .try_into()
361 .map_err(|_| preferred_incomplete(0, 4, available))?;
362 let ipv6_address = bytes[6..22]
363 .try_into()
364 .map_err(|_| preferred_incomplete(6, 22, available))?;
365 let stateless_reset_token = bytes[connection_id_end..token_end]
366 .try_into()
367 .map_err(|_| preferred_incomplete(connection_id_end, token_end, available))?;
368 Ok(QuicPreferredAddress {
369 bytes,
370 ipv4_address,
371 ipv4_port: u16::from_be_bytes([bytes[4], bytes[5]]),
372 ipv6_address,
373 ipv6_port: u16::from_be_bytes([bytes[22], bytes[23]]),
374 connection_id: QuicConnectionId::new(&bytes[25..connection_id_end]),
375 stateless_reset_token,
376 })
377}