1use std::{
2 borrow::Cow,
3 fmt::{self, Display},
4 mem,
5 net::{IpAddr, SocketAddr},
6 ops::{Range, RangeInclusive},
7};
8
9use bytes::{Buf, BufMut, Bytes};
10use tinyvec::TinyVec;
11
12use crate::{
13 Dir, MAX_CID_SIZE, RESET_TOKEN_SIZE, ResetToken, StreamId, TransportError, TransportErrorCode,
14 VarInt,
15 coding::{self, BufExt, BufMutExt, Decodable, Encodable, UnexpectedEnd},
16 connection::PathId,
17 range_set::ArrayRangeSet,
18 shared::{ConnectionId, EcnCodepoint},
19};
20
21#[cfg(feature = "qlog")]
22use super::connection::qlog::ToQlog;
23
24#[cfg(test)]
25use crate::varint::varint_u64;
26#[cfg(test)]
27use proptest::{collection, prelude::any, strategy::Strategy};
28#[cfg(test)]
29use test_strategy::Arbitrary;
30
31#[derive(
32 Copy, Clone, Eq, PartialEq, derive_more::Debug, derive_more::Display, enum_assoc::Assoc,
33)]
34#[cfg_attr(test, derive(Arbitrary))]
35#[display(rename_all = "SCREAMING_SNAKE_CASE")]
36#[allow(missing_docs)]
37#[func(
38 pub(crate) const fn to_u64(self) -> u64,
39 const fn from_u64(rev: u64) -> Option<Self>,
40)]
41pub enum FrameType {
42 #[assoc(to_u64 = 0x00)]
43 Padding,
44 #[assoc(to_u64 = 0x01)]
45 Ping,
46 #[assoc(to_u64 = 0x02)]
47 Ack,
48 #[assoc(to_u64 = 0x03)]
49 AckEcn,
50 #[assoc(to_u64 = 0x04)]
51 ResetStream,
52 #[assoc(to_u64 = 0x05)]
53 StopSending,
54 #[assoc(to_u64 = 0x06)]
55 Crypto,
56 #[assoc(to_u64 = 0x07)]
57 NewToken,
58 #[assoc(to_u64 = _0.to_u64())]
60 Stream(StreamInfo),
61 #[assoc(to_u64 = 0x10)]
62 MaxData,
63 #[assoc(to_u64 = 0x11)]
64 MaxStreamData,
65 #[assoc(to_u64 = 0x12)]
66 MaxStreamsBidi,
67 #[assoc(to_u64 = 0x13)]
68 MaxStreamsUni,
69 #[assoc(to_u64 = 0x14)]
70 DataBlocked,
71 #[assoc(to_u64 = 0x15)]
72 StreamDataBlocked,
73 #[assoc(to_u64 = 0x16)]
74 StreamsBlockedBidi,
75 #[assoc(to_u64 = 0x17)]
76 StreamsBlockedUni,
77 #[assoc(to_u64 = 0x18)]
78 NewConnectionId,
79 #[assoc(to_u64 = 0x19)]
80 RetireConnectionId,
81 #[assoc(to_u64 = 0x1a)]
82 PathChallenge,
83 #[assoc(to_u64 = 0x1b)]
84 PathResponse,
85 #[assoc(to_u64 = 0x1c)]
86 ConnectionClose,
87 #[assoc(to_u64 = 0x1d)]
88 ApplicationClose,
89 #[assoc(to_u64 = 0x1e)]
90 HandshakeDone,
91 #[assoc(to_u64 = 0xaf)]
93 AckFrequency,
94 #[assoc(to_u64 = 0x1f)]
95 ImmediateAck,
96 #[assoc(to_u64 = _0.to_u64())]
98 Datagram(DatagramInfo),
99 #[assoc(to_u64 = 0x9f81a6)]
101 ObservedIpv4Addr,
102 #[assoc(to_u64 = 0x9f81a7)]
103 ObservedIpv6Addr,
104 #[assoc(to_u64 = 0x3e)]
106 PathAck,
107 #[assoc(to_u64 = 0x3f)]
108 PathAckEcn,
109 #[assoc(to_u64 = 0x3e75)]
110 PathAbandon,
111 #[assoc(to_u64 = 0x3e76)]
112 PathStatusBackup,
113 #[assoc(to_u64 = 0x3e77)]
114 PathStatusAvailable,
115 #[assoc(to_u64 = 0x3e78)]
116 PathNewConnectionId,
117 #[assoc(to_u64 = 0x3e79)]
118 PathRetireConnectionId,
119 #[assoc(to_u64 = 0x3e7a)]
120 MaxPathId,
121 #[assoc(to_u64 = 0x3e7b)]
122 PathsBlocked,
123 #[assoc(to_u64 = 0x3e7c)]
124 PathCidsBlocked,
125 #[assoc(to_u64 = 0x3d7f90)]
127 AddIpv4Address,
128 #[assoc(to_u64 = 0x3d7f91)]
129 AddIpv6Address,
130 #[assoc(to_u64 = 0x3d7f92)]
131 ReachOutAtIpv4,
132 #[assoc(to_u64 = 0x3d7f93)]
133 ReachOutAtIpv6,
134 #[assoc(to_u64 = 0x3d7f94)]
135 RemoveAddress,
136}
137
138#[derive(Debug, PartialEq, Eq, thiserror::Error)]
140#[error("Invalid frame identifier {_0:02x}")]
141pub struct InvalidFrameId(u64);
142
143impl TryFrom<u64> for FrameType {
144 type Error = InvalidFrameId;
145 fn try_from(value: u64) -> Result<Self, Self::Error> {
146 match Self::from_u64(value) {
147 Some(t) => Ok(t),
148 None => {
149 if DatagramInfo::VALUES.contains(&value) {
150 return Ok(Self::Datagram(DatagramInfo(value as u8)));
151 }
152 if StreamInfo::VALUES.contains(&value) {
153 return Ok(Self::Stream(StreamInfo(value as u8)));
154 }
155 Err(InvalidFrameId(value))
156 }
157 }
158 }
159}
160
161impl FrameType {
162 const fn size(&self) -> usize {
164 VarInt(self.to_u64()).size()
165 }
166}
167
168impl Decodable for FrameType {
169 fn decode<B: Buf>(buf: &mut B) -> coding::Result<Self> {
170 Self::try_from(buf.get_var()?).map_err(|_| coding::UnexpectedEnd)
171 }
172}
173
174impl Encodable for FrameType {
175 fn encode<B: BufMut>(&self, buf: &mut B) {
176 buf.write_var(self.to_u64());
177 }
178}
179
180#[derive(derive_more::From, enum_assoc::Assoc, derive_more::Display)]
185#[func(fn encode_inner<B: BufMut>(&self, buf: &mut B) {_0.encode(buf)})]
186#[func(pub(crate) const fn get_type(&self) -> FrameType {_0.get_type()})]
187#[cfg_attr(feature = "qlog", func(pub(crate) fn to_qlog(&self) -> qlog::events::quic::QuicFrame {_0.to_qlog()}))]
188pub(super) enum EncodableFrame<'a> {
189 PathAck(PathAckEncoder<'a>),
190 Ack(AckEncoder<'a>),
191 Close(CloseEncoder<'a>),
192 PathResponse(PathResponse),
193 HandshakeDone(HandshakeDone),
194 ReachOut(ReachOut),
195 ObservedAddr(ObservedAddr),
196 Ping(Ping),
197 ImmediateAck(ImmediateAck),
198 AckFrequency(AckFrequency),
199 PathChallenge(PathChallenge),
200 Crypto(Crypto),
201 PathAbandon(PathAbandon),
202 PathStatusAvailable(PathStatusAvailable),
203 PathStatusBackup(PathStatusBackup),
204 MaxPathId(MaxPathId),
205 PathsBlocked(PathsBlocked),
206 PathCidsBlocked(PathCidsBlocked),
207 ResetStream(ResetStream),
208 StopSending(StopSending),
209 NewConnectionId(NewConnectionId),
210 RetireConnectionId(RetireConnectionId),
211 Datagram(Datagram),
212 NewToken(NewToken),
213 AddAddress(AddAddress),
214 RemoveAddress(RemoveAddress),
215 StreamMeta(StreamMetaEncoder),
216 MaxData(MaxData),
217 MaxStreamData(MaxStreamData),
218 MaxStreams(MaxStreams),
219 StreamsBlocked(StreamsBlocked),
220}
221
222impl<'a> EncodableFrame<'a> {
223 pub(crate) fn is_ack_eliciting(&self) -> bool {
225 match self {
226 EncodableFrame::PathAck(_) | EncodableFrame::Ack(_) | EncodableFrame::Close(_) => false,
227 EncodableFrame::PathResponse(_)
228 | EncodableFrame::HandshakeDone(_)
229 | EncodableFrame::ReachOut(_)
230 | EncodableFrame::ObservedAddr(_)
231 | EncodableFrame::Ping(_)
232 | EncodableFrame::ImmediateAck(_)
233 | EncodableFrame::AckFrequency(_)
234 | EncodableFrame::PathChallenge(_)
235 | EncodableFrame::Crypto(_)
236 | EncodableFrame::PathAbandon(_)
237 | EncodableFrame::PathStatusAvailable(_)
238 | EncodableFrame::PathStatusBackup(_)
239 | EncodableFrame::MaxPathId(_)
240 | EncodableFrame::PathsBlocked(_)
241 | EncodableFrame::PathCidsBlocked(_)
242 | EncodableFrame::ResetStream(_)
243 | EncodableFrame::StopSending(_)
244 | EncodableFrame::NewConnectionId(_)
245 | EncodableFrame::RetireConnectionId(_)
246 | EncodableFrame::Datagram(_)
247 | EncodableFrame::NewToken(_)
248 | EncodableFrame::AddAddress(_)
249 | EncodableFrame::RemoveAddress(_)
250 | EncodableFrame::StreamMeta(_)
251 | EncodableFrame::MaxData(_)
252 | EncodableFrame::MaxStreamData(_)
253 | EncodableFrame::MaxStreams(_)
254 | EncodableFrame::StreamsBlocked(_) => true,
255 }
256 }
257}
258
259impl<'a> Encodable for EncodableFrame<'a> {
260 fn encode<B: BufMut>(&self, buf: &mut B) {
261 self.encode_inner(buf)
262 }
263}
264
265pub(crate) trait FrameStruct {
266 const SIZE_BOUND: usize;
268}
269
270#[derive(Copy, Clone, Eq, PartialEq, derive_more::Debug, derive_more::Display)]
272pub enum MaybeFrame {
273 None,
275 #[display("UNKNOWN({:02x})", _0)]
277 #[debug("Unknown({:02x})", _0)]
278 Unknown(u64),
279 Known(FrameType),
281}
282
283impl MaybeFrame {
284 const fn size(&self) -> usize {
286 match self {
287 Self::None => VarInt(0).size(),
288 Self::Unknown(other) => VarInt(*other).size(),
289 Self::Known(frame_type) => frame_type.size(),
290 }
291 }
292}
293
294impl Decodable for MaybeFrame {
295 fn decode<B: Buf>(buf: &mut B) -> coding::Result<Self> {
296 match FrameType::try_from(buf.get_var()?) {
297 Ok(FrameType::Padding) => Ok(Self::None),
298 Ok(other_frame) => Ok(Self::Known(other_frame)),
299 Err(InvalidFrameId(other)) => Ok(Self::Unknown(other)),
300 }
301 }
302}
303
304impl Encodable for MaybeFrame {
305 fn encode<B: BufMut>(&self, buf: &mut B) {
306 match self {
307 Self::None => buf.write_var(0u64),
308 Self::Unknown(frame_id) => buf.write_var(*frame_id),
309 Self::Known(frame_type) => buf.write(*frame_type),
310 }
311 }
312}
313
314#[cfg(test)]
315impl proptest::arbitrary::Arbitrary for MaybeFrame {
316 type Parameters = ();
317 type Strategy = proptest::strategy::BoxedStrategy<Self>;
318
319 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
320 use proptest::prelude::*;
321 prop_oneof![
322 Just(Self::None),
323 any::<VarInt>().prop_map(|v| Self::Unknown(v.0)),
324 any::<FrameType>()
326 .prop_filter("not Padding", |ft| *ft != FrameType::Padding)
327 .prop_map(MaybeFrame::Known),
328 ]
329 .boxed()
330 }
331}
332
333#[derive(derive_more::Display)]
334#[cfg_attr(test, derive(Arbitrary, Debug, Clone, PartialEq, Eq))]
335#[display("HANDSHAKE_DONE")]
336pub(crate) struct HandshakeDone;
337
338impl HandshakeDone {
339 const fn get_type(&self) -> FrameType {
340 FrameType::HandshakeDone
341 }
342}
343
344impl Encodable for HandshakeDone {
345 fn encode<B: BufMut>(&self, buf: &mut B) {
346 FrameType::HandshakeDone.encode(buf);
347 }
348}
349
350#[derive(derive_more::Display)]
351#[cfg_attr(test, derive(Arbitrary, Debug, Clone, PartialEq, Eq))]
352#[display("PING")]
353pub(crate) struct Ping;
354
355impl Ping {
356 const fn get_type(&self) -> FrameType {
357 FrameType::Ping
358 }
359}
360
361impl Encodable for Ping {
362 fn encode<B: BufMut>(&self, buf: &mut B) {
363 FrameType::Ping.encode(buf);
364 }
365}
366
367#[derive(derive_more::Display)]
368#[cfg_attr(test, derive(Arbitrary, Debug, Clone, PartialEq, Eq))]
369#[display("IMMEDIATE_ACK")]
370pub(crate) struct ImmediateAck;
371
372impl ImmediateAck {
373 const fn get_type(&self) -> FrameType {
374 FrameType::ImmediateAck
375 }
376}
377
378impl Encodable for ImmediateAck {
379 fn encode<B: BufMut>(&self, buf: &mut B) {
380 FrameType::ImmediateAck.encode(buf);
381 }
382}
383
384#[allow(missing_docs)]
385#[derive(Debug, Copy, Clone, Eq, PartialEq, derive_more::Display)]
386#[display("STREAM")]
387#[cfg_attr(test, derive(Arbitrary))]
388pub struct StreamInfo(#[cfg_attr(test, strategy(0x08u8..=0x0f))] u8);
389
390impl StreamInfo {
391 const VALUES: RangeInclusive<u64> = RangeInclusive::new(0x08, 0x0f);
392 fn fin(self) -> bool {
393 self.0 & 0x01 != 0
394 }
395 fn len(self) -> bool {
396 self.0 & 0x02 != 0
397 }
398 fn off(self) -> bool {
399 self.0 & 0x04 != 0
400 }
401
402 const fn to_u64(self) -> u64 {
403 self.0 as u64
404 }
405}
406
407#[allow(missing_docs)]
408#[derive(Debug, Copy, Clone, Eq, PartialEq, derive_more::Display)]
409#[display("DATAGRAM")]
410#[cfg_attr(test, derive(Arbitrary))]
411pub struct DatagramInfo(#[cfg_attr(test, strategy(0x30u8..=0x31))] u8);
412
413impl DatagramInfo {
414 const VALUES: RangeInclusive<u64> = RangeInclusive::new(0x30, 0x31);
415
416 fn len(self) -> bool {
417 self.0 & 0x01 != 0
418 }
419
420 const fn to_u64(self) -> u64 {
421 self.0 as u64
422 }
423}
424
425#[derive(Debug, derive_more::Display)]
426#[cfg_attr(test, derive(Arbitrary))]
427pub(crate) enum Frame {
428 #[display("PADDING")]
429 Padding,
430 #[display("PING")]
431 Ping,
432 Ack(Ack),
433 PathAck(PathAck),
434 ResetStream(ResetStream),
435 StopSending(StopSending),
436 Crypto(Crypto),
437 NewToken(NewToken),
438 Stream(Stream),
439 MaxData(MaxData),
440 MaxStreamData(MaxStreamData),
441 MaxStreams(MaxStreams),
442 DataBlocked(DataBlocked),
443 StreamDataBlocked(StreamDataBlocked),
444 StreamsBlocked(StreamsBlocked),
445 NewConnectionId(NewConnectionId),
446 RetireConnectionId(RetireConnectionId),
447 PathChallenge(PathChallenge),
448 PathResponse(PathResponse),
449 Close(Close),
450 Datagram(Datagram),
451 AckFrequency(AckFrequency),
452 #[display("IMMEDIATE_ACK")]
453 ImmediateAck,
454 #[display("HANDSHAKE_DONE")]
455 HandshakeDone,
456 ObservedAddr(ObservedAddr),
457 PathAbandon(PathAbandon),
458 PathStatusAvailable(PathStatusAvailable),
459 PathStatusBackup(PathStatusBackup),
460 MaxPathId(MaxPathId),
461 PathsBlocked(PathsBlocked),
462 PathCidsBlocked(PathCidsBlocked),
463 AddAddress(AddAddress),
464 ReachOut(ReachOut),
465 RemoveAddress(RemoveAddress),
466}
467
468impl Frame {
469 pub(crate) fn ty(&self) -> FrameType {
470 use Frame::*;
471 match &self {
472 Padding => FrameType::Padding,
473 ResetStream(_) => FrameType::ResetStream,
474 Close(self::Close::Connection(_)) => FrameType::ConnectionClose,
475 Close(self::Close::Application(_)) => FrameType::ConnectionClose,
476 MaxData(_) => FrameType::MaxData,
477 MaxStreamData(_) => FrameType::MaxStreamData,
478 MaxStreams(max_streams) => max_streams.get_type(),
479 Ping => FrameType::Ping,
480 DataBlocked(_) => FrameType::DataBlocked,
481 StreamDataBlocked(sdb) => sdb.get_type(),
482 StreamsBlocked(sb) => sb.get_type(),
483 StopSending { .. } => FrameType::StopSending,
484 RetireConnectionId(retire_frame) => retire_frame.get_type(),
485 Ack(ack) => ack.get_type(),
486 PathAck(path_ack) => path_ack.get_type(),
487 Stream(x) => {
488 let mut ty = *StreamInfo::VALUES.start() as u8;
489 if x.fin {
490 ty |= 0x01;
491 }
492 if x.offset != 0 {
493 ty |= 0x04;
494 }
495 FrameType::Stream(StreamInfo(ty))
497 }
498 PathChallenge(_) => FrameType::PathChallenge,
499 PathResponse(_) => FrameType::PathResponse,
500 NewConnectionId(cid) => cid.get_type(),
501 Crypto(_) => FrameType::Crypto,
502 NewToken(_) => FrameType::NewToken,
503 Datagram(_) => FrameType::Datagram(DatagramInfo(*DatagramInfo::VALUES.start() as u8)),
504 AckFrequency(_) => FrameType::AckFrequency,
505 ImmediateAck => FrameType::ImmediateAck,
506 HandshakeDone => FrameType::HandshakeDone,
507 ObservedAddr(observed) => observed.get_type(),
508 PathAbandon(_) => FrameType::PathAbandon,
509 PathStatusAvailable(_) => FrameType::PathStatusAvailable,
510 PathStatusBackup(_) => FrameType::PathStatusBackup,
511 MaxPathId(_) => FrameType::MaxPathId,
512 PathsBlocked(_) => FrameType::PathsBlocked,
513 PathCidsBlocked(_) => FrameType::PathCidsBlocked,
514 AddAddress(frame) => frame.get_type(),
515 ReachOut(frame) => frame.get_type(),
516 RemoveAddress(_) => self::RemoveAddress::TYPE,
517 }
518 }
519
520 pub(crate) fn is_ack_eliciting(&self) -> bool {
521 !matches!(
522 *self,
523 Self::Ack(_) | Self::PathAck(_) | Self::Padding | Self::Close(_)
524 )
525 }
526
527 pub(crate) fn is_1rtt(&self) -> bool {
529 self.is_multipath_frame() || self.is_qad_frame()
535 }
536
537 fn is_qad_frame(&self) -> bool {
538 matches!(*self, Self::ObservedAddr(_))
539 }
540
541 fn is_multipath_frame(&self) -> bool {
542 matches!(
543 *self,
544 Self::PathAck(_)
545 | Self::PathAbandon(_)
546 | Self::PathStatusBackup(_)
547 | Self::PathStatusAvailable(_)
548 | Self::MaxPathId(_)
549 | Self::PathsBlocked(_)
550 | Self::PathCidsBlocked(_)
551 | Self::NewConnectionId(NewConnectionId {
552 path_id: Some(_),
553 ..
554 })
555 | Self::RetireConnectionId(RetireConnectionId {
556 path_id: Some(_),
557 ..
558 })
559 )
560 }
561}
562
563#[derive(Debug, Clone, Copy, PartialEq, Eq, derive_more::Display)]
564#[cfg_attr(test, derive(Arbitrary))]
565#[display("PATH_CHALLENGE({_0:08x})")]
566pub(crate) struct PathChallenge(pub(crate) u64);
567
568impl PathChallenge {
569 pub(crate) const SIZE_BOUND: usize = 9;
570
571 const fn get_type(&self) -> FrameType {
572 FrameType::PathChallenge
573 }
574}
575
576impl Decodable for PathChallenge {
577 fn decode<B: Buf>(buf: &mut B) -> coding::Result<Self> {
578 Ok(Self(buf.get()?))
579 }
580}
581
582impl Encodable for PathChallenge {
583 fn encode<B: BufMut>(&self, buf: &mut B) {
584 buf.write(FrameType::PathChallenge);
585 buf.write(self.0);
586 }
587}
588
589#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, derive_more::Display)]
590#[cfg_attr(test, derive(Arbitrary))]
591#[display("PATH_RESPONSE({_0:08x})")]
592pub(crate) struct PathResponse(pub(crate) u64);
593
594impl PathResponse {
595 pub(crate) const SIZE_BOUND: usize = 9;
596
597 const fn get_type(&self) -> FrameType {
598 FrameType::PathResponse
599 }
600}
601
602impl Decodable for PathResponse {
603 fn decode<B: Buf>(buf: &mut B) -> coding::Result<Self> {
604 Ok(Self(buf.get()?))
605 }
606}
607
608impl Encodable for PathResponse {
609 fn encode<B: BufMut>(&self, buf: &mut B) {
610 buf.write(FrameType::PathResponse);
611 buf.write(self.0);
612 }
613}
614
615#[derive(Debug, Clone, Copy, derive_more::Display)]
616#[cfg_attr(test, derive(Arbitrary, PartialEq, Eq))]
617#[display("DATA_BLOCKED offset: {_0}")]
618pub(crate) struct DataBlocked(#[cfg_attr(test, strategy(varint_u64()))] pub(crate) u64);
619
620impl Encodable for DataBlocked {
621 fn encode<B: BufMut>(&self, buf: &mut B) {
622 buf.write(FrameType::DataBlocked);
623 buf.write_var(self.0);
624 }
625}
626
627#[derive(Debug, Clone, Copy, derive_more::Display)]
628#[cfg_attr(test, derive(Arbitrary, PartialEq, Eq))]
629#[display("STREAM_DATA_BLOCKED id: {id} offset: {offset}")]
630pub(crate) struct StreamDataBlocked {
631 pub(crate) id: StreamId,
632 #[cfg_attr(test, strategy(varint_u64()))]
633 pub(crate) offset: u64,
634}
635
636impl StreamDataBlocked {
637 const fn get_type(&self) -> FrameType {
638 FrameType::StreamDataBlocked
639 }
640}
641
642impl Encodable for StreamDataBlocked {
643 fn encode<B: BufMut>(&self, buf: &mut B) {
644 buf.write(FrameType::StreamDataBlocked);
645 buf.write(self.id);
646 buf.write_var(self.offset);
647 }
648}
649
650#[derive(Debug, Clone, Copy, derive_more::Display)]
651#[cfg_attr(test, derive(Arbitrary, PartialEq, Eq))]
652#[display("STREAMS_BLOCKED dir: {:?} limit: {limit}", dir)]
653pub(crate) struct StreamsBlocked {
654 pub(crate) dir: Dir,
655 #[cfg_attr(test, strategy(varint_u64()))]
656 pub(crate) limit: u64,
657}
658
659impl StreamsBlocked {
660 const fn get_type(&self) -> FrameType {
661 match self.dir {
662 Dir::Bi => FrameType::StreamsBlockedBidi,
663 Dir::Uni => FrameType::StreamsBlockedUni,
664 }
665 }
666}
667
668impl Encodable for StreamsBlocked {
669 fn encode<B: BufMut>(&self, buf: &mut B) {
670 buf.write(self.get_type());
671 buf.write_var(self.limit);
672 }
673}
674
675#[derive(Debug, Clone, Copy, derive_more::Display)]
676#[cfg_attr(test, derive(Arbitrary, PartialEq, Eq))]
677#[display("MAX_DATA({_0})")]
678pub(crate) struct MaxData(pub(crate) VarInt);
679
680impl MaxData {
681 const fn get_type(&self) -> FrameType {
682 FrameType::MaxData
683 }
684}
685
686impl Decodable for MaxData {
687 fn decode<B: Buf>(buf: &mut B) -> coding::Result<Self> {
688 Ok(Self(buf.get()?))
689 }
690}
691
692impl Encodable for MaxData {
693 fn encode<B: BufMut>(&self, buf: &mut B) {
694 buf.write(FrameType::MaxData);
695 buf.write(self.0);
696 }
697}
698
699#[derive(Debug, Clone, Copy, derive_more::Display)]
700#[cfg_attr(test, derive(Arbitrary, PartialEq, Eq))]
701#[display("MAX_STREAM_DATA id: {id} max: {offset}")]
702pub(crate) struct MaxStreamData {
703 pub(crate) id: StreamId,
704 #[cfg_attr(test, strategy(varint_u64()))]
705 pub(crate) offset: u64,
706}
707
708impl MaxStreamData {
709 const fn get_type(&self) -> FrameType {
710 FrameType::MaxStreamData
711 }
712}
713
714impl Decodable for MaxStreamData {
715 fn decode<B: Buf>(buf: &mut B) -> coding::Result<Self> {
716 Ok(Self {
717 id: buf.get()?,
718 offset: buf.get_var()?,
719 })
720 }
721}
722
723impl Encodable for MaxStreamData {
724 fn encode<B: BufMut>(&self, buf: &mut B) {
725 buf.write(FrameType::MaxStreamData);
726 buf.write(self.id);
727 buf.write_var(self.offset);
728 }
729}
730
731#[derive(Debug, Clone, Copy, derive_more::Display)]
732#[cfg_attr(test, derive(Arbitrary, PartialEq, Eq))]
733#[display("{} count: {count}", self.get_type())]
734pub(crate) struct MaxStreams {
735 pub(crate) dir: Dir,
736 #[cfg_attr(test, strategy(varint_u64()))]
737 pub(crate) count: u64,
738}
739
740impl MaxStreams {
741 const fn get_type(&self) -> FrameType {
742 match self.dir {
743 Dir::Bi => FrameType::MaxStreamsBidi,
744 Dir::Uni => FrameType::MaxStreamsUni,
745 }
746 }
747}
748
749impl Encodable for MaxStreams {
750 fn encode<B: BufMut>(&self, buf: &mut B) {
751 buf.write(self.get_type());
752 buf.write_var(self.count);
753 }
754}
755
756#[derive(Debug, PartialEq, Eq, derive_more::Display)]
757#[cfg_attr(test, derive(Arbitrary))]
758#[display("{} {} seq: {sequence}", self.get_type(), DisplayOption::new("path_id", path_id.as_ref()))]
759pub(crate) struct RetireConnectionId {
760 pub(crate) path_id: Option<PathId>,
761 #[cfg_attr(test, strategy(varint_u64()))]
762 pub(crate) sequence: u64,
763}
764
765impl RetireConnectionId {
766 pub(crate) const SIZE_BOUND: usize = {
768 let type_len = FrameType::RetireConnectionId.size();
769 let seq_max_len = 8usize;
770 type_len + seq_max_len
771 };
772
773 pub(crate) const SIZE_BOUND_MULTIPATH: usize = {
775 let type_len = FrameType::PathRetireConnectionId.size();
776 let path_id_len = VarInt::from_u32(u32::MAX).size();
777 let seq_max_len = 8usize;
778 type_len + path_id_len + seq_max_len
779 };
780
781 pub(crate) fn decode<R: Buf>(bytes: &mut R, read_path: bool) -> coding::Result<Self> {
784 Ok(Self {
785 path_id: if read_path { Some(bytes.get()?) } else { None },
786 sequence: bytes.get_var()?,
787 })
788 }
789
790 const fn get_type(&self) -> FrameType {
792 if self.path_id.is_some() {
793 FrameType::PathRetireConnectionId
794 } else {
795 FrameType::RetireConnectionId
796 }
797 }
798
799 pub(crate) const fn size_bound(path_retire_cid: bool) -> usize {
804 match path_retire_cid {
805 true => Self::SIZE_BOUND_MULTIPATH,
806 false => Self::SIZE_BOUND,
807 }
808 }
809}
810
811impl Encodable for RetireConnectionId {
812 fn encode<W: BufMut>(&self, buf: &mut W) {
813 buf.write(self.get_type());
814 if let Some(id) = self.path_id {
815 buf.write(id);
816 }
817 buf.write_var(self.sequence);
818 }
819}
820
821#[cfg_attr(test, derive(Arbitrary))]
822#[derive(Clone, Debug, derive_more::Display)]
823#[display("CONNECTION_CLOSE error_code={} reason='{}'", self.error_code(), self.reason())]
824pub(crate) enum Close {
825 Connection(ConnectionClose),
826 Application(ApplicationClose),
827}
828
829impl Close {
830 pub(crate) fn encoder(&self, max_len: usize) -> CloseEncoder<'_> {
831 CloseEncoder {
832 close: self,
833 max_len,
834 }
835 }
836
837 pub(crate) fn is_transport_layer(&self) -> bool {
838 matches!(*self, Self::Connection(_))
839 }
840
841 fn error_code(&self) -> u64 {
842 match self {
843 Self::Connection(ConnectionClose { error_code, .. }) => u64::from(*error_code),
844 Self::Application(ApplicationClose { error_code, .. }) => u64::from(*error_code),
845 }
846 }
847
848 fn reason(&self) -> Cow<'_, str> {
849 match self {
850 Self::Connection(ConnectionClose { reason, .. }) => String::from_utf8_lossy(reason),
851 Self::Application(ApplicationClose { reason, .. }) => String::from_utf8_lossy(reason),
852 }
853 }
854}
855
856#[derive(derive_more::Display)]
857#[display("{close}")]
858pub(crate) struct CloseEncoder<'a> {
859 pub(crate) close: &'a Close,
860 max_len: usize,
861}
862
863impl<'a> CloseEncoder<'a> {
864 const fn get_type(&self) -> FrameType {
865 match self.close {
866 Close::Connection(_) => FrameType::ConnectionClose,
867 Close::Application(_) => FrameType::ApplicationClose,
868 }
869 }
870}
871
872impl<'a> Encodable for CloseEncoder<'a> {
873 fn encode<W: BufMut>(&self, out: &mut W) {
874 match self.close {
875 Close::Connection(x) => x.encode(out, self.max_len),
876 Close::Application(x) => x.encode(out, self.max_len),
877 }
878 }
879}
880
881impl From<TransportError> for Close {
882 fn from(x: TransportError) -> Self {
883 Self::Connection(x.into())
884 }
885}
886impl From<ConnectionClose> for Close {
887 fn from(x: ConnectionClose) -> Self {
888 Self::Connection(x)
889 }
890}
891impl From<ApplicationClose> for Close {
892 fn from(x: ApplicationClose) -> Self {
893 Self::Application(x)
894 }
895}
896
897#[derive(Debug, Clone, PartialEq, Eq)]
899#[cfg_attr(test, derive(Arbitrary))]
900pub struct ConnectionClose {
901 pub error_code: TransportErrorCode,
903 pub frame_type: MaybeFrame,
905 #[cfg_attr(test, strategy(proptest::collection::vec(any::<u8>(), 0..64).prop_map(Bytes::from)))]
907 pub reason: Bytes,
908}
909
910impl fmt::Display for ConnectionClose {
911 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
912 self.error_code.fmt(f)?;
913 if !self.reason.as_ref().is_empty() {
914 f.write_str(": ")?;
915 f.write_str(&String::from_utf8_lossy(&self.reason))?;
916 }
917 Ok(())
918 }
919}
920
921impl From<TransportError> for ConnectionClose {
922 fn from(x: TransportError) -> Self {
923 Self {
924 error_code: x.code,
925 frame_type: x.frame,
926 reason: x.reason.into(),
927 }
928 }
929}
930
931impl FrameStruct for ConnectionClose {
932 const SIZE_BOUND: usize = 1 + 8 + 8 + 8;
933}
934
935impl ConnectionClose {
936 pub(crate) fn encode<W: BufMut>(&self, out: &mut W, max_len: usize) {
937 out.write(FrameType::ConnectionClose); out.write(self.error_code); out.write(self.frame_type); let max_len = max_len
941 - 3
942 - self.frame_type.size()
943 - VarInt::from_u64(self.reason.len() as u64).unwrap().size();
944 let actual_len = self.reason.len().min(max_len);
945 out.write_var(actual_len as u64); out.put_slice(&self.reason[0..actual_len]); }
948}
949
950#[derive(Debug, Clone, PartialEq, Eq)]
952#[cfg_attr(test, derive(Arbitrary))]
953pub struct ApplicationClose {
954 pub error_code: VarInt,
956 #[cfg_attr(test, strategy(proptest::collection::vec(any::<u8>(), 0..64).prop_map(Bytes::from)))]
958 pub reason: Bytes,
959}
960
961impl fmt::Display for ApplicationClose {
962 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
963 if !self.reason.as_ref().is_empty() {
964 f.write_str(&String::from_utf8_lossy(&self.reason))?;
965 f.write_str(" (code ")?;
966 self.error_code.fmt(f)?;
967 f.write_str(")")?;
968 } else {
969 self.error_code.fmt(f)?;
970 }
971 Ok(())
972 }
973}
974
975impl FrameStruct for ApplicationClose {
976 const SIZE_BOUND: usize = 1 + 8 + 8;
977}
978
979impl ApplicationClose {
980 pub(crate) fn encode<W: BufMut>(&self, out: &mut W, max_len: usize) {
981 out.write(FrameType::ApplicationClose); out.write(self.error_code); let max_len = max_len - 3 - VarInt::from_u64(self.reason.len() as u64).unwrap().size();
984 let actual_len = self.reason.len().min(max_len);
985 out.write_var(actual_len as u64); out.put_slice(&self.reason[0..actual_len]); }
988}
989
990#[derive(Debug, Clone, Eq, PartialEq, derive_more::Display)]
991#[display("{} path_id: {path_id} ranges: {ranges:?} delay: {delay}µs", self.get_type())]
992pub(crate) struct PathAck {
993 pub path_id: PathId,
994 pub largest: u64,
995 pub delay: u64,
996 pub ranges: ArrayRangeSet,
997 pub ecn: Option<EcnCounts>,
998}
999
1000#[cfg(test)]
1001impl proptest::arbitrary::Arbitrary for PathAck {
1002 type Parameters = ();
1003 type Strategy = proptest::strategy::BoxedStrategy<Self>;
1004
1005 fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
1006 use proptest::prelude::*;
1007 (
1008 any::<PathId>(),
1009 varint_u64(),
1010 any::<ArrayRangeSet>(),
1011 any::<Option<EcnCounts>>(),
1012 )
1013 .prop_map(|(path_id, delay, ranges, ecn)| Self {
1014 path_id,
1015 largest: ranges.max().expect("ranges must be non empty"),
1016 delay,
1017 ranges,
1018 ecn,
1019 })
1020 .boxed()
1021 }
1022}
1023
1024impl PathAck {
1025 pub(crate) fn into_ack(self) -> (Ack, PathId) {
1026 let ack = Ack {
1027 largest: self.largest,
1028 delay: self.delay,
1029 ranges: self.ranges,
1030 ecn: self.ecn,
1031 };
1032
1033 (ack, self.path_id)
1034 }
1035
1036 fn get_type(&self) -> FrameType {
1037 if self.ecn.is_some() {
1038 FrameType::PathAckEcn
1039 } else {
1040 FrameType::PathAck
1041 }
1042 }
1043
1044 pub(crate) fn encoder<'a>(
1045 path_id: PathId,
1046 delay: u64,
1047 ranges: &'a ArrayRangeSet,
1048 ecn: Option<&'a EcnCounts>,
1049 ) -> PathAckEncoder<'a> {
1050 PathAckEncoder {
1051 path_id,
1052 delay,
1053 ranges,
1054 ecn,
1055 }
1056 }
1057}
1058
1059#[derive(derive_more::Display)]
1060#[display("{} path_id: {path_id} ranges: {ranges:?} delay: {delay}µs", self.get_type())]
1061pub(crate) struct PathAckEncoder<'a> {
1062 pub(super) path_id: PathId,
1063 pub(super) delay: u64,
1064 pub(super) ranges: &'a ArrayRangeSet,
1065 pub(super) ecn: Option<&'a EcnCounts>,
1066}
1067
1068impl<'a> PathAckEncoder<'a> {
1069 const fn get_type(&self) -> FrameType {
1070 match self.ecn.is_some() {
1071 true => FrameType::PathAckEcn,
1072 false => FrameType::PathAck,
1073 }
1074 }
1075}
1076
1077impl<'a> Encodable for PathAckEncoder<'a> {
1078 fn encode<W: BufMut>(&self, buf: &mut W) {
1085 let PathAckEncoder {
1086 path_id,
1087 delay,
1088 ranges,
1089 ecn,
1090 } = self;
1091 let mut rest = ranges.iter().rev();
1092 let first = rest
1093 .next()
1094 .expect("Caller has verified ranges is non empty");
1095 let largest = first.end - 1;
1096 let first_size = first.end - first.start;
1097 let kind = match ecn.is_some() {
1098 true => FrameType::PathAckEcn,
1099 false => FrameType::PathAck,
1100 };
1101 buf.write(kind);
1102 buf.write(*path_id);
1103 buf.write_var(largest);
1104 buf.write_var(*delay);
1105 buf.write_var(ranges.len() as u64 - 1);
1106 buf.write_var(first_size - 1);
1107 let mut prev = first.start;
1108 for block in rest {
1109 let size = block.end - block.start;
1110 buf.write_var(prev - block.end - 1);
1111 buf.write_var(size - 1);
1112 prev = block.start;
1113 }
1114 if let Some(x) = ecn {
1115 x.encode(buf)
1116 }
1117 }
1118}
1119
1120#[derive(Debug, Clone, Eq, PartialEq, derive_more::Display)]
1121#[display("{} ranges: {ranges:?} delay: {delay}µs largest: {largest}", self.get_type())]
1122pub(crate) struct Ack {
1123 pub largest: u64,
1124 pub delay: u64,
1125 pub ranges: ArrayRangeSet,
1126 pub ecn: Option<EcnCounts>,
1127}
1128
1129#[cfg(test)]
1130impl proptest::arbitrary::Arbitrary for Ack {
1131 type Parameters = ();
1132 type Strategy = proptest::strategy::BoxedStrategy<Self>;
1133
1134 fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
1135 use proptest::prelude::*;
1136 (
1137 varint_u64(),
1138 any::<ArrayRangeSet>(),
1139 any::<Option<EcnCounts>>(),
1140 )
1141 .prop_map(|(delay, ranges, ecn)| Self {
1142 largest: ranges.max().expect("ranges must be non empty"),
1143 delay,
1144 ranges,
1145 ecn,
1146 })
1147 .boxed()
1148 }
1149}
1150
1151impl Ack {
1152 pub(crate) fn encoder<'a>(
1153 delay: u64,
1154 ranges: &'a ArrayRangeSet,
1155 ecn: Option<&'a EcnCounts>,
1156 ) -> AckEncoder<'a> {
1157 AckEncoder { delay, ranges, ecn }
1158 }
1159
1160 pub(crate) fn iter(&self) -> impl DoubleEndedIterator<Item = Range<u64>> + '_ {
1161 self.ranges.iter()
1162 }
1163
1164 pub(crate) const fn get_type(&self) -> FrameType {
1165 if self.ecn.is_some() {
1166 FrameType::AckEcn
1167 } else {
1168 FrameType::Ack
1169 }
1170 }
1171}
1172
1173#[derive(derive_more::Display)]
1174#[display("{} ranges: {ranges:?} delay: {delay}µs", self.get_type())]
1175pub(crate) struct AckEncoder<'a> {
1176 pub(crate) delay: u64,
1177 pub(crate) ranges: &'a ArrayRangeSet,
1178 pub(crate) ecn: Option<&'a EcnCounts>,
1179}
1180
1181impl<'a> AckEncoder<'a> {
1182 const fn get_type(&self) -> FrameType {
1183 match self.ecn.is_some() {
1184 true => FrameType::AckEcn,
1185 false => FrameType::Ack,
1186 }
1187 }
1188}
1189
1190impl<'a> Encodable for AckEncoder<'a> {
1191 fn encode<W: BufMut>(&self, buf: &mut W) {
1192 let AckEncoder { delay, ranges, ecn } = self;
1193 let mut rest = ranges.iter().rev();
1194 let first = rest.next().unwrap();
1195 let largest = first.end - 1;
1196 let first_size = first.end - first.start;
1197 let kind = match ecn.is_some() {
1198 true => FrameType::AckEcn,
1199 false => FrameType::Ack,
1200 };
1201 buf.write(kind);
1202 buf.write_var(largest);
1203 buf.write_var(*delay);
1204 buf.write_var(ranges.len() as u64 - 1);
1205 buf.write_var(first_size - 1);
1206 let mut prev = first.start;
1207 for block in rest {
1208 let size = block.end - block.start;
1209 buf.write_var(prev - block.end - 1);
1210 buf.write_var(size - 1);
1211 prev = block.start;
1212 }
1213 if let Some(x) = ecn {
1214 x.encode(buf)
1215 }
1216 }
1217}
1218
1219#[cfg_attr(test, derive(Arbitrary))]
1220#[derive(Debug, Copy, Clone, Eq, PartialEq)]
1221pub(crate) struct EcnCounts {
1222 #[cfg_attr(test, strategy(varint_u64()))]
1223 pub ect0: u64,
1224 #[cfg_attr(test, strategy(varint_u64()))]
1225 pub ect1: u64,
1226 #[cfg_attr(test, strategy(varint_u64()))]
1227 pub ce: u64,
1228}
1229
1230impl std::ops::AddAssign<EcnCodepoint> for EcnCounts {
1231 fn add_assign(&mut self, rhs: EcnCodepoint) {
1232 match rhs {
1233 EcnCodepoint::Ect0 => {
1234 self.ect0 += 1;
1235 }
1236 EcnCodepoint::Ect1 => {
1237 self.ect1 += 1;
1238 }
1239 EcnCodepoint::Ce => {
1240 self.ce += 1;
1241 }
1242 }
1243 }
1244}
1245
1246impl EcnCounts {
1247 pub(crate) const ZERO: Self = Self {
1248 ect0: 0,
1249 ect1: 0,
1250 ce: 0,
1251 };
1252}
1253
1254impl Encodable for EcnCounts {
1255 fn encode<W: BufMut>(&self, out: &mut W) {
1256 out.write_var(self.ect0);
1257 out.write_var(self.ect1);
1258 out.write_var(self.ce);
1259 }
1260}
1261
1262#[derive(Debug, Clone, derive_more::Display)]
1263#[cfg_attr(test, derive(Arbitrary, PartialEq, Eq))]
1264#[display("STREAM id: {id} off: {offset} len: {} fin: {fin}", data.len())]
1265pub(crate) struct Stream {
1266 pub(crate) id: StreamId,
1267 #[cfg_attr(test, strategy(varint_u64()))]
1268 pub(crate) offset: u64,
1269 pub(crate) fin: bool,
1270 #[cfg_attr(test, strategy(Strategy::prop_map(collection::vec(any::<u8>(), 0..100), Bytes::from)))]
1271 pub(crate) data: Bytes,
1272}
1273
1274impl FrameStruct for Stream {
1275 const SIZE_BOUND: usize = 1 + 8 + 8 + 8;
1276}
1277
1278#[derive(Debug, Clone, derive_more::Display)]
1280#[display("STREAM id: {id} off: {} len: {} fin: {fin}", offsets.start, offsets.end - offsets.start)]
1281pub(crate) struct StreamMeta {
1282 pub(crate) id: StreamId,
1283 pub(crate) offsets: Range<u64>,
1284 pub(crate) fin: bool,
1285}
1286
1287impl Default for StreamMeta {
1289 fn default() -> Self {
1290 Self {
1291 id: StreamId(0),
1292 offsets: 0..0,
1293 fin: false,
1294 }
1295 }
1296}
1297
1298impl StreamMeta {
1299 pub(crate) fn encoder(self, encode_length: bool) -> StreamMetaEncoder {
1300 StreamMetaEncoder {
1301 meta: self,
1302 encode_length,
1303 }
1304 }
1305
1306 const fn get_type(&self, encode_length: bool) -> StreamInfo {
1307 let mut ty = *StreamInfo::VALUES.start();
1308 if self.offsets.start != 0 {
1309 ty |= 0x04;
1310 }
1311 if encode_length {
1312 ty |= 0x02;
1313 }
1314 if self.fin {
1315 ty |= 0x01;
1316 }
1317 StreamInfo(ty as u8)
1318 }
1319}
1320
1321#[derive(derive_more::Display)]
1322#[display("{meta}")]
1323pub(crate) struct StreamMetaEncoder {
1324 pub(crate) meta: StreamMeta,
1325 encode_length: bool,
1326}
1327
1328impl StreamMetaEncoder {
1329 const fn get_type(&self) -> FrameType {
1330 FrameType::Stream(self.meta.get_type(self.encode_length))
1331 }
1332}
1333
1334impl Encodable for StreamMetaEncoder {
1335 fn encode<W: BufMut>(&self, out: &mut W) {
1336 let Self {
1337 meta,
1338 encode_length,
1339 } = self;
1340 out.write_var(meta.get_type(*encode_length).0 as u64); out.write(meta.id); if meta.offsets.start != 0 {
1343 out.write_var(meta.offsets.start); }
1345 if *encode_length {
1346 out.write_var(meta.offsets.end - meta.offsets.start); }
1348 }
1349}
1350
1351pub(crate) type StreamMetaVec = TinyVec<[StreamMeta; 1]>;
1353
1354#[derive(Debug, Clone, derive_more::Display)]
1355#[cfg_attr(test, derive(Arbitrary, PartialEq, Eq))]
1356#[display("CRYPTO off: {offset} len = {}", data.len())]
1357pub(crate) struct Crypto {
1358 #[cfg_attr(test, strategy(varint_u64()))]
1359 pub(crate) offset: u64,
1360 #[cfg_attr(test, strategy(Strategy::prop_map(collection::vec(any::<u8>(), 0..1024), Bytes::from)))]
1361 pub(crate) data: Bytes,
1362}
1363
1364impl Crypto {
1365 pub(crate) const SIZE_BOUND: usize = 17;
1366
1367 const fn get_type(&self) -> FrameType {
1368 FrameType::Crypto
1369 }
1370}
1371
1372impl Encodable for Crypto {
1373 fn encode<W: BufMut>(&self, out: &mut W) {
1374 out.write(FrameType::Crypto);
1375 out.write_var(self.offset);
1376 out.write_var(self.data.len() as u64);
1377 out.put_slice(&self.data);
1378 }
1379}
1380
1381#[derive(Debug, Clone, derive_more::Display)]
1382#[cfg_attr(test, derive(Arbitrary, PartialEq, Eq))]
1383#[display("NEW_TOKEN")]
1384pub(crate) struct NewToken {
1385 #[cfg_attr(test, strategy(Strategy::prop_map(collection::vec(any::<u8>(), 0..1024), Bytes::from)))]
1386 pub(crate) token: Bytes,
1387}
1388
1389impl Encodable for NewToken {
1390 fn encode<W: BufMut>(&self, out: &mut W) {
1391 out.write(FrameType::NewToken);
1392 out.write_var(self.token.len() as u64);
1393 out.put_slice(&self.token);
1394 }
1395}
1396
1397impl NewToken {
1398 pub(crate) fn size(&self) -> usize {
1399 1 + VarInt::from_u64(self.token.len() as u64).unwrap().size() + self.token.len()
1400 }
1401
1402 const fn get_type(&self) -> FrameType {
1403 FrameType::NewToken
1404 }
1405}
1406
1407#[derive(Debug, Clone, derive_more::Display)]
1408#[cfg_attr(test, derive(Arbitrary, PartialEq, Eq))]
1409#[display("MAX_PATH_ID path_id: {_0}")]
1410pub(crate) struct MaxPathId(pub(crate) PathId);
1411
1412impl MaxPathId {
1413 pub(crate) const SIZE_BOUND: usize =
1414 FrameType::MaxPathId.size() + VarInt(u32::MAX as u64).size();
1415
1416 const fn get_type(&self) -> FrameType {
1417 FrameType::MaxPathId
1418 }
1419}
1420
1421impl Decodable for MaxPathId {
1422 fn decode<B: Buf>(buf: &mut B) -> coding::Result<Self> {
1423 Ok(Self(buf.get()?))
1424 }
1425}
1426
1427impl Encodable for MaxPathId {
1428 fn encode<B: BufMut>(&self, buf: &mut B) {
1429 buf.write(FrameType::MaxPathId);
1430 buf.write(self.0);
1431 }
1432}
1433
1434#[derive(Debug, Clone, PartialEq, Eq, derive_more::Display)]
1435#[cfg_attr(test, derive(Arbitrary))]
1436#[display("PATHS_BLOCKED remote_max_path_id: {_0}")]
1437pub(crate) struct PathsBlocked(pub(crate) PathId);
1438
1439impl PathsBlocked {
1440 pub(crate) const SIZE_BOUND: usize =
1441 FrameType::PathsBlocked.size() + VarInt(u32::MAX as u64).size();
1442
1443 const fn get_type(&self) -> FrameType {
1444 FrameType::PathsBlocked
1445 }
1446}
1447
1448impl Encodable for PathsBlocked {
1449 fn encode<B: BufMut>(&self, buf: &mut B) {
1450 buf.write(FrameType::PathsBlocked);
1451 buf.write(self.0);
1452 }
1453}
1454
1455impl Decodable for PathsBlocked {
1456 fn decode<B: Buf>(buf: &mut B) -> coding::Result<Self> {
1458 Ok(Self(buf.get()?))
1459 }
1460}
1461
1462#[derive(Debug, Clone, PartialEq, Eq, derive_more::Display)]
1463#[cfg_attr(test, derive(Arbitrary))]
1464#[display("PATH_CIDS_BLOCKED path_id: {path_id} next_seq: {next_seq}")]
1465pub(crate) struct PathCidsBlocked {
1466 pub(crate) path_id: PathId,
1467 pub(crate) next_seq: VarInt,
1468}
1469
1470impl PathCidsBlocked {
1471 pub(crate) const SIZE_BOUND: usize =
1472 FrameType::PathCidsBlocked.size() + VarInt(u32::MAX as u64).size() + VarInt::MAX.size();
1473
1474 const fn get_type(&self) -> FrameType {
1475 FrameType::PathCidsBlocked
1476 }
1477}
1478
1479impl Decodable for PathCidsBlocked {
1480 fn decode<R: Buf>(buf: &mut R) -> coding::Result<Self> {
1481 Ok(Self {
1482 path_id: buf.get()?,
1483 next_seq: buf.get()?,
1484 })
1485 }
1486}
1487
1488impl Encodable for PathCidsBlocked {
1489 fn encode<W: BufMut>(&self, buf: &mut W) {
1490 buf.write(FrameType::PathCidsBlocked);
1491 buf.write(self.path_id);
1492 buf.write(self.next_seq);
1493 }
1494}
1495
1496pub(crate) struct Iter {
1497 bytes: Bytes,
1498 last_ty: MaybeFrame,
1499}
1500
1501impl Iter {
1502 pub(crate) fn new(payload: Bytes) -> Result<Self, TransportError> {
1503 if payload.is_empty() {
1504 return Err(TransportError::PROTOCOL_VIOLATION(
1508 "packet payload is empty",
1509 ));
1510 }
1511
1512 Ok(Self {
1513 bytes: payload,
1514 last_ty: MaybeFrame::None,
1515 })
1516 }
1517
1518 fn take_len(&mut self) -> Result<Bytes, UnexpectedEnd> {
1519 let len = self.bytes.get_var()?;
1520 if len > self.bytes.remaining() as u64 {
1521 return Err(UnexpectedEnd);
1522 }
1523 Ok(self.bytes.split_to(len as usize))
1524 }
1525
1526 #[track_caller]
1527 fn try_next(&mut self) -> Result<Frame, IterErr> {
1528 self.last_ty = self.bytes.get()?;
1529
1530 let ty = match self.last_ty {
1531 MaybeFrame::None => FrameType::Padding,
1532 MaybeFrame::Unknown(_other) => return Err(IterErr::InvalidFrameId),
1533 MaybeFrame::Known(frame_type) => frame_type,
1534 };
1535 Ok(match ty {
1536 FrameType::Padding => Frame::Padding,
1537 FrameType::ResetStream => Frame::ResetStream(ResetStream {
1538 id: self.bytes.get()?,
1539 error_code: self.bytes.get()?,
1540 final_offset: self.bytes.get()?,
1541 }),
1542 FrameType::ConnectionClose => Frame::Close(Close::Connection(ConnectionClose {
1543 error_code: self.bytes.get()?,
1544 frame_type: self.bytes.get()?,
1545 reason: self.take_len()?,
1546 })),
1547 FrameType::ApplicationClose => Frame::Close(Close::Application(ApplicationClose {
1548 error_code: self.bytes.get()?,
1549 reason: self.take_len()?,
1550 })),
1551 FrameType::MaxData => Frame::MaxData(self.bytes.get()?),
1552 FrameType::MaxStreamData => Frame::MaxStreamData(self.bytes.get()?),
1553 FrameType::MaxStreamsBidi => Frame::MaxStreams(MaxStreams {
1554 dir: Dir::Bi,
1555 count: self.bytes.get_var()?,
1556 }),
1557 FrameType::MaxStreamsUni => Frame::MaxStreams(MaxStreams {
1558 dir: Dir::Uni,
1559 count: self.bytes.get_var()?,
1560 }),
1561 FrameType::Ping => Frame::Ping,
1562 FrameType::DataBlocked => Frame::DataBlocked(DataBlocked(self.bytes.get_var()?)),
1563 FrameType::StreamDataBlocked => Frame::StreamDataBlocked(StreamDataBlocked {
1564 id: self.bytes.get()?,
1565 offset: self.bytes.get_var()?,
1566 }),
1567 FrameType::StreamsBlockedBidi => Frame::StreamsBlocked(StreamsBlocked {
1568 dir: Dir::Bi,
1569 limit: self.bytes.get_var()?,
1570 }),
1571 FrameType::StreamsBlockedUni => Frame::StreamsBlocked(StreamsBlocked {
1572 dir: Dir::Uni,
1573 limit: self.bytes.get_var()?,
1574 }),
1575 FrameType::StopSending => Frame::StopSending(StopSending {
1576 id: self.bytes.get()?,
1577 error_code: self.bytes.get()?,
1578 }),
1579 FrameType::RetireConnectionId | FrameType::PathRetireConnectionId => {
1580 Frame::RetireConnectionId(RetireConnectionId::decode(
1581 &mut self.bytes,
1582 ty == FrameType::PathRetireConnectionId,
1583 )?)
1584 }
1585 FrameType::Ack => {
1586 let largest = self.bytes.get_var()?;
1587 let delay = self.bytes.get_var()?;
1588 let ranges = read_ack_blocks(&mut self.bytes, largest)?;
1589 Frame::Ack(Ack {
1590 delay,
1591 largest,
1592 ranges,
1593 ecn: None,
1594 })
1595 }
1596 FrameType::AckEcn => {
1597 let largest = self.bytes.get_var()?;
1598 let delay = self.bytes.get_var()?;
1599 let ranges = read_ack_blocks(&mut self.bytes, largest)?;
1600 let ecn = Some(EcnCounts {
1601 ect0: self.bytes.get_var()?,
1602 ect1: self.bytes.get_var()?,
1603 ce: self.bytes.get_var()?,
1604 });
1605
1606 Frame::Ack(Ack {
1607 delay,
1608 largest,
1609 ranges,
1610 ecn,
1611 })
1612 }
1613 FrameType::PathAck => {
1614 let path_id = self.bytes.get()?;
1615 let largest = self.bytes.get_var()?;
1616 let delay = self.bytes.get_var()?;
1617 let ranges = read_ack_blocks(&mut self.bytes, largest)?;
1618 Frame::PathAck(PathAck {
1619 path_id,
1620 delay,
1621 largest,
1622 ranges,
1623 ecn: None,
1624 })
1625 }
1626 FrameType::PathAckEcn => {
1627 let path_id = self.bytes.get()?;
1628 let largest = self.bytes.get_var()?;
1629 let delay = self.bytes.get_var()?;
1630 let ranges = read_ack_blocks(&mut self.bytes, largest)?;
1631 let ecn = Some(EcnCounts {
1632 ect0: self.bytes.get_var()?,
1633 ect1: self.bytes.get_var()?,
1634 ce: self.bytes.get_var()?,
1635 });
1636 Frame::PathAck(PathAck {
1637 path_id,
1638 delay,
1639 largest,
1640 ranges,
1641 ecn,
1642 })
1643 }
1644 FrameType::PathChallenge => Frame::PathChallenge(self.bytes.get()?),
1645 FrameType::PathResponse => Frame::PathResponse(self.bytes.get()?),
1646 FrameType::NewConnectionId | FrameType::PathNewConnectionId => {
1647 let read_path = ty == FrameType::PathNewConnectionId;
1648 Frame::NewConnectionId(NewConnectionId::read(&mut self.bytes, read_path)?)
1649 }
1650 FrameType::Crypto => Frame::Crypto(Crypto {
1651 offset: self.bytes.get_var()?,
1652 data: self.take_len()?,
1653 }),
1654 FrameType::NewToken => Frame::NewToken(NewToken {
1655 token: self.take_len()?,
1656 }),
1657 FrameType::HandshakeDone => Frame::HandshakeDone,
1658 FrameType::AckFrequency => Frame::AckFrequency(AckFrequency {
1659 sequence: self.bytes.get()?,
1660 ack_eliciting_threshold: self.bytes.get()?,
1661 request_max_ack_delay: self.bytes.get()?,
1662 reordering_threshold: self.bytes.get()?,
1663 }),
1664 FrameType::ImmediateAck => Frame::ImmediateAck,
1665 FrameType::ObservedIpv4Addr | FrameType::ObservedIpv6Addr => {
1666 let is_ipv6 = ty == FrameType::ObservedIpv6Addr;
1667 let observed = ObservedAddr::read(&mut self.bytes, is_ipv6)?;
1668 Frame::ObservedAddr(observed)
1669 }
1670 FrameType::PathAbandon => Frame::PathAbandon(PathAbandon::decode(&mut self.bytes)?),
1671 FrameType::PathStatusAvailable => {
1672 Frame::PathStatusAvailable(PathStatusAvailable::decode(&mut self.bytes)?)
1673 }
1674 FrameType::PathStatusBackup => {
1675 Frame::PathStatusBackup(PathStatusBackup::decode(&mut self.bytes)?)
1676 }
1677 FrameType::MaxPathId => Frame::MaxPathId(MaxPathId::decode(&mut self.bytes)?),
1678 FrameType::PathsBlocked => Frame::PathsBlocked(PathsBlocked::decode(&mut self.bytes)?),
1679 FrameType::PathCidsBlocked => {
1680 Frame::PathCidsBlocked(PathCidsBlocked::decode(&mut self.bytes)?)
1681 }
1682 FrameType::AddIpv4Address | FrameType::AddIpv6Address => {
1683 let is_ipv6 = ty == FrameType::AddIpv6Address;
1684 let add_address = AddAddress::read(&mut self.bytes, is_ipv6)?;
1685 Frame::AddAddress(add_address)
1686 }
1687 FrameType::ReachOutAtIpv4 | FrameType::ReachOutAtIpv6 => {
1688 let is_ipv6 = ty == FrameType::ReachOutAtIpv6;
1689 let reach_out = ReachOut::read(&mut self.bytes, is_ipv6)?;
1690 Frame::ReachOut(reach_out)
1691 }
1692 FrameType::RemoveAddress => Frame::RemoveAddress(RemoveAddress::read(&mut self.bytes)?),
1693 FrameType::Stream(s) => Frame::Stream(Stream {
1694 id: self.bytes.get()?,
1695 offset: if s.off() { self.bytes.get_var()? } else { 0 },
1696 fin: s.fin(),
1697 data: if s.len() {
1698 self.take_len()?
1699 } else {
1700 self.take_remaining()
1701 },
1702 }),
1703 FrameType::Datagram(d) => Frame::Datagram(Datagram {
1704 data: if d.len() {
1705 self.take_len()?
1706 } else {
1707 self.take_remaining()
1708 },
1709 }),
1710 })
1711 }
1712
1713 pub(crate) fn take_remaining(&mut self) -> Bytes {
1714 mem::take(&mut self.bytes)
1715 }
1716}
1717
1718impl Iterator for Iter {
1719 type Item = Result<Frame, InvalidFrame>;
1720 fn next(&mut self) -> Option<Self::Item> {
1721 if !self.bytes.has_remaining() {
1722 return None;
1723 }
1724 match self.try_next() {
1725 Ok(x) => Some(Ok(x)),
1726 Err(e) => {
1727 self.bytes.clear();
1729 Some(Err(InvalidFrame {
1730 ty: self.last_ty,
1731 reason: e.reason(),
1732 }))
1733 }
1734 }
1735 }
1736}
1737
1738#[derive(Debug)]
1739pub(crate) struct InvalidFrame {
1740 pub(crate) ty: MaybeFrame,
1741 pub(crate) reason: &'static str,
1742}
1743
1744impl From<InvalidFrame> for TransportError {
1745 fn from(err: InvalidFrame) -> Self {
1746 let mut te = Self::FRAME_ENCODING_ERROR(err.reason);
1747 te.frame = err.ty;
1748 te
1749 }
1750}
1751
1752fn read_ack_blocks(buf: &mut Bytes, mut largest: u64) -> Result<ArrayRangeSet, IterErr> {
1761 let num_blocks = buf.get_var()?;
1763
1764 let mut out = ArrayRangeSet::new();
1765 let mut block_to_block;
1766 let mut range;
1767
1768 for num_block in 0..num_blocks + 1 {
1769 range = buf.get_var()?;
1770 range += 1;
1771
1772 let start = (largest + 1).checked_sub(range).ok_or(IterErr::Malformed)?;
1773
1774 if range > 0 {
1775 out.insert(start..largest + 1);
1776 }
1777
1778 if num_block < num_blocks {
1780 block_to_block = buf.get_var()?;
1782 block_to_block += 1;
1783 block_to_block += range;
1784
1785 largest = largest
1786 .checked_sub(block_to_block)
1787 .ok_or(IterErr::Malformed)?;
1788 }
1789 }
1790
1791 Ok(out)
1792}
1793
1794#[derive(Debug)]
1795enum IterErr {
1796 UnexpectedEnd,
1797 InvalidFrameId,
1798 Malformed,
1799}
1800
1801impl IterErr {
1802 fn reason(&self) -> &'static str {
1803 use IterErr::*;
1804 match *self {
1805 UnexpectedEnd => "unexpected end",
1806 InvalidFrameId => "invalid frame ID",
1807 Malformed => "malformed",
1808 }
1809 }
1810}
1811
1812impl From<UnexpectedEnd> for IterErr {
1813 fn from(_: UnexpectedEnd) -> Self {
1814 Self::UnexpectedEnd
1815 }
1816}
1817
1818#[allow(unreachable_pub)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1820#[cfg_attr(test, derive(Arbitrary))]
1821#[derive(Debug, Copy, Clone, derive_more::Display)]
1822#[display("RESET_STREAM id: {id}")]
1823pub struct ResetStream {
1824 pub(crate) id: StreamId,
1825 pub(crate) error_code: VarInt,
1826 pub(crate) final_offset: VarInt,
1827}
1828
1829impl ResetStream {
1830 const fn get_type(&self) -> FrameType {
1831 FrameType::ResetStream
1832 }
1833}
1834
1835impl FrameStruct for ResetStream {
1836 const SIZE_BOUND: usize = 1 + 8 + 8 + 8;
1837}
1838
1839impl Encodable for ResetStream {
1840 fn encode<W: BufMut>(&self, out: &mut W) {
1841 out.write(FrameType::ResetStream); out.write(self.id); out.write(self.error_code); out.write(self.final_offset); }
1846}
1847
1848#[cfg_attr(test, derive(Arbitrary))]
1849#[derive(Debug, Copy, Clone, derive_more::Display)]
1850#[display("STOP_SENDING id: {id}")]
1851pub(crate) struct StopSending {
1852 pub(crate) id: StreamId,
1853 pub(crate) error_code: VarInt,
1854}
1855
1856impl FrameStruct for StopSending {
1857 const SIZE_BOUND: usize = 1 + 8 + 8;
1858}
1859
1860impl StopSending {
1861 const fn get_type(&self) -> FrameType {
1862 FrameType::StopSending
1863 }
1864}
1865
1866impl Encodable for StopSending {
1867 fn encode<W: BufMut>(&self, out: &mut W) {
1868 out.write(FrameType::StopSending); out.write(self.id); out.write(self.error_code) }
1872}
1873
1874#[derive(Debug, Copy, Clone, PartialEq, Eq, derive_more::Display)]
1875#[display("{} {} seq: {sequence} id: {id}", self.get_type(), DisplayOption::new("path_id", path_id.as_ref()))]
1876pub(crate) struct NewConnectionId {
1877 pub(crate) path_id: Option<PathId>,
1878 pub(crate) sequence: u64,
1879 pub(crate) retire_prior_to: u64,
1880 pub(crate) id: ConnectionId,
1881 pub(crate) reset_token: ResetToken,
1882}
1883
1884#[cfg(test)]
1885fn connection_id_and_reset_token() -> impl Strategy<Value = (crate::ConnectionId, ResetToken)> {
1886 (any::<ConnectionId>(), any::<[u8; 64]>()).prop_map(|(id, reset_key)| {
1887 #[cfg(all(feature = "aws-lc-rs", not(feature = "ring")))]
1888 use aws_lc_rs::hmac;
1889 #[cfg(feature = "ring")]
1890 use ring::hmac;
1891 let key = hmac::Key::new(hmac::HMAC_SHA256, &reset_key);
1892 (id, ResetToken::new(&key, id))
1893 })
1894}
1895
1896#[cfg(test)]
1897impl proptest::arbitrary::Arbitrary for NewConnectionId {
1898 type Parameters = ();
1899 type Strategy = proptest::strategy::BoxedStrategy<Self>;
1900
1901 fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
1902 use proptest::prelude::*;
1903 (
1904 any::<Option<PathId>>(),
1905 varint_u64(),
1906 varint_u64(),
1907 connection_id_and_reset_token(),
1908 )
1909 .prop_map(|(path_id, a, b, (id, reset_token))| {
1910 let sequence = std::cmp::max(a, b);
1911 let retire_prior_to = std::cmp::min(a, b);
1912 Self {
1913 path_id,
1914 sequence,
1915 retire_prior_to,
1916 id,
1917 reset_token,
1918 }
1919 })
1920 .boxed()
1921 }
1922}
1923
1924impl NewConnectionId {
1925 pub(crate) const SIZE_BOUND: usize = {
1927 let type_len = FrameType::NewConnectionId.size();
1928 let seq_max_len = 8usize;
1929 let retire_prior_to_max_len = 8usize;
1930 let cid_len_len = 1;
1931 let cid_len = 160;
1932 let reset_token_len = 16;
1933 type_len + seq_max_len + retire_prior_to_max_len + cid_len_len + cid_len + reset_token_len
1934 };
1935
1936 pub(crate) const SIZE_BOUND_MULTIPATH: usize = {
1938 let type_len = FrameType::PathNewConnectionId.size();
1939 let path_id_len = VarInt::from_u32(u32::MAX).size();
1940 let seq_max_len = 8usize;
1941 let retire_prior_to_max_len = 8usize;
1942 let cid_len_len = 1;
1943 let cid_len = 160;
1944 let reset_token_len = 16;
1945 type_len
1946 + path_id_len
1947 + seq_max_len
1948 + retire_prior_to_max_len
1949 + cid_len_len
1950 + cid_len
1951 + reset_token_len
1952 };
1953
1954 const fn get_type(&self) -> FrameType {
1955 if self.path_id.is_some() {
1956 FrameType::PathNewConnectionId
1957 } else {
1958 FrameType::NewConnectionId
1959 }
1960 }
1961
1962 pub(crate) const fn size_bound(path_new_cid: bool, cid_len: usize) -> usize {
1966 let upper_bound = match path_new_cid {
1967 true => Self::SIZE_BOUND_MULTIPATH,
1968 false => Self::SIZE_BOUND,
1969 };
1970 upper_bound - 160 + cid_len
1972 }
1973
1974 fn read<R: Buf>(bytes: &mut R, read_path: bool) -> Result<Self, IterErr> {
1975 let path_id = if read_path { Some(bytes.get()?) } else { None };
1976 let sequence = bytes.get_var()?;
1977 let retire_prior_to = bytes.get_var()?;
1978 if retire_prior_to > sequence {
1979 return Err(IterErr::Malformed);
1980 }
1981 let length = bytes.get::<u8>()? as usize;
1982 if length > MAX_CID_SIZE || length == 0 {
1983 return Err(IterErr::Malformed);
1984 }
1985 if length > bytes.remaining() {
1986 return Err(IterErr::UnexpectedEnd);
1987 }
1988 let mut stage = [0; MAX_CID_SIZE];
1989 bytes.copy_to_slice(&mut stage[0..length]);
1990 let id = ConnectionId::new(&stage[..length]);
1991 if bytes.remaining() < 16 {
1992 return Err(IterErr::UnexpectedEnd);
1993 }
1994 let mut reset_token = [0; RESET_TOKEN_SIZE];
1995 bytes.copy_to_slice(&mut reset_token);
1996 Ok(Self {
1997 path_id,
1998 sequence,
1999 retire_prior_to,
2000 id,
2001 reset_token: reset_token.into(),
2002 })
2003 }
2004
2005 pub(crate) fn issued(&self) -> crate::shared::IssuedCid {
2006 crate::shared::IssuedCid {
2007 path_id: self.path_id.unwrap_or_default(),
2008 sequence: self.sequence,
2009 id: self.id,
2010 reset_token: self.reset_token,
2011 }
2012 }
2013}
2014
2015impl Encodable for NewConnectionId {
2016 fn encode<W: BufMut>(&self, out: &mut W) {
2017 out.write(self.get_type());
2018 if let Some(id) = self.path_id {
2019 out.write(id);
2020 }
2021 out.write_var(self.sequence);
2022 out.write_var(self.retire_prior_to);
2023 out.write(self.id.len() as u8);
2024 out.put_slice(&self.id);
2025 out.put_slice(&self.reset_token);
2026 }
2027}
2028
2029impl FrameStruct for NewConnectionId {
2030 const SIZE_BOUND: usize = 1 + 8 + 8 + 1 + MAX_CID_SIZE + RESET_TOKEN_SIZE;
2031}
2032
2033#[derive(Debug, Clone, derive_more::Display)]
2035#[cfg_attr(test, derive(Arbitrary))]
2036#[display("DATAGRAM len: {}", data.len())]
2037pub struct Datagram {
2038 #[cfg_attr(test, strategy(Strategy::prop_map(collection::vec(any::<u8>(), 0..100), Bytes::from)))]
2040 pub data: Bytes,
2041}
2042
2043impl FrameStruct for Datagram {
2044 const SIZE_BOUND: usize = 1 + 8;
2045}
2046
2047impl Datagram {
2048 pub(crate) fn size(&self, length: bool) -> usize {
2049 1 + if length {
2050 VarInt::from_u64(self.data.len() as u64).unwrap().size()
2051 } else {
2052 0
2053 } + self.data.len()
2054 }
2055
2056 const fn get_type(&self) -> FrameType {
2057 FrameType::Datagram(DatagramInfo(*DatagramInfo::VALUES.start() as u8))
2058 }
2059}
2060
2061impl Encodable for Datagram {
2062 fn encode<B: BufMut>(&self, out: &mut B) {
2063 const ENCODE_LEN: bool = true;
2065 out.write(FrameType::Datagram(DatagramInfo(
2066 *DatagramInfo::VALUES.start() as u8 | u8::from(ENCODE_LEN),
2067 ))); out.write(VarInt::from_u64(self.data.len() as u64).unwrap()); out.put_slice(&self.data);
2071 }
2072}
2073
2074#[derive(Debug, Copy, Clone, PartialEq, Eq, derive_more::Display)]
2075#[cfg_attr(test, derive(Arbitrary))]
2076#[display("ACK_FREQUENCY max_ack_delay: {}µs", request_max_ack_delay.0)]
2077pub(crate) struct AckFrequency {
2078 pub(crate) sequence: VarInt,
2079 pub(crate) ack_eliciting_threshold: VarInt,
2080 pub(crate) request_max_ack_delay: VarInt,
2081 pub(crate) reordering_threshold: VarInt,
2082}
2083
2084impl AckFrequency {
2085 const fn get_type(&self) -> FrameType {
2086 FrameType::AckFrequency
2087 }
2088}
2089
2090impl Encodable for AckFrequency {
2091 fn encode<W: BufMut>(&self, buf: &mut W) {
2092 buf.write(FrameType::AckFrequency);
2093 buf.write(self.sequence);
2094 buf.write(self.ack_eliciting_threshold);
2095 buf.write(self.request_max_ack_delay);
2096 buf.write(self.reordering_threshold);
2097 }
2098}
2099
2100#[derive(Debug, PartialEq, Eq, Clone, derive_more::Display)]
2105#[display("{} seq_no: {seq_no} addr: {}", self.get_type(), self.socket_addr())]
2106#[cfg_attr(test, derive(Arbitrary))]
2107pub(crate) struct ObservedAddr {
2108 pub(crate) seq_no: VarInt,
2110 pub(crate) ip: IpAddr,
2112 pub(crate) port: u16,
2114}
2115
2116impl ObservedAddr {
2117 pub(crate) fn new<N: Into<VarInt>>(remote: std::net::SocketAddr, seq_no: N) -> Self {
2118 Self {
2119 ip: remote.ip(),
2120 port: remote.port(),
2121 seq_no: seq_no.into(),
2122 }
2123 }
2124
2125 const fn get_type(&self) -> FrameType {
2127 if self.ip.is_ipv6() {
2128 FrameType::ObservedIpv6Addr
2129 } else {
2130 FrameType::ObservedIpv4Addr
2131 }
2132 }
2133
2134 pub(crate) fn size(&self) -> usize {
2136 let type_size = self.get_type().size();
2137 let req_id_bytes = self.seq_no.size();
2138 let ip_bytes = if self.ip.is_ipv6() { 16 } else { 4 };
2139 let port_bytes = 2;
2140 type_size + req_id_bytes + ip_bytes + port_bytes
2141 }
2142
2143 pub(crate) fn read<R: Buf>(bytes: &mut R, is_ipv6: bool) -> coding::Result<Self> {
2148 let seq_no = bytes.get()?;
2149 let ip = if is_ipv6 {
2150 IpAddr::V6(bytes.get()?)
2151 } else {
2152 IpAddr::V4(bytes.get()?)
2153 };
2154 let port = bytes.get()?;
2155 Ok(Self { seq_no, ip, port })
2156 }
2157
2158 pub(crate) fn socket_addr(&self) -> SocketAddr {
2160 (self.ip, self.port).into()
2161 }
2162}
2163
2164impl Encodable for ObservedAddr {
2165 fn encode<W: BufMut>(&self, buf: &mut W) {
2166 buf.write(self.get_type());
2167 buf.write(self.seq_no);
2168 match self.ip {
2169 IpAddr::V4(ipv4_addr) => {
2170 buf.write(ipv4_addr);
2171 }
2172 IpAddr::V6(ipv6_addr) => {
2173 buf.write(ipv6_addr);
2174 }
2175 }
2176 buf.write::<u16>(self.port);
2177 }
2178}
2179
2180#[derive(Debug, PartialEq, Eq, derive_more::Display)]
2183#[cfg_attr(test, derive(Arbitrary))]
2184#[display("PATH_ABANDON path_id: {path_id}")]
2185pub(crate) struct PathAbandon {
2186 pub(crate) path_id: PathId,
2187 pub(crate) error_code: TransportErrorCode,
2188}
2189
2190impl PathAbandon {
2191 pub(crate) const SIZE_BOUND: usize = FrameType::PathAbandon.size() + 8 + 8;
2192
2193 const fn get_type(&self) -> FrameType {
2194 FrameType::PathAbandon
2195 }
2196}
2197
2198impl Encodable for PathAbandon {
2199 fn encode<W: BufMut>(&self, buf: &mut W) {
2200 buf.write(FrameType::PathAbandon);
2201 buf.write(self.path_id);
2202 buf.write(self.error_code);
2203 }
2204}
2205
2206impl Decodable for PathAbandon {
2207 fn decode<R: Buf>(bytes: &mut R) -> coding::Result<Self> {
2208 Ok(Self {
2209 path_id: bytes.get()?,
2210 error_code: bytes.get()?,
2211 })
2212 }
2213}
2214
2215#[derive(Debug, PartialEq, Eq, derive_more::Display)]
2216#[cfg_attr(test, derive(Arbitrary))]
2217#[display("PATH_STATUS_AVAILABLE path_id: {path_id} seq_no: {status_seq_no}")]
2218pub(crate) struct PathStatusAvailable {
2219 pub(crate) path_id: PathId,
2220 pub(crate) status_seq_no: VarInt,
2221}
2222
2223impl PathStatusAvailable {
2224 const TYPE: FrameType = FrameType::PathStatusAvailable;
2225 pub(crate) const SIZE_BOUND: usize = FrameType::PathStatusAvailable.size() + 8 + 8;
2226
2227 const fn get_type(&self) -> FrameType {
2228 FrameType::PathStatusAvailable
2229 }
2230}
2231
2232impl Encodable for PathStatusAvailable {
2233 fn encode<W: BufMut>(&self, buf: &mut W) {
2234 buf.write(Self::TYPE);
2235 buf.write(self.path_id);
2236 buf.write(self.status_seq_no);
2237 }
2238}
2239
2240impl Decodable for PathStatusAvailable {
2241 fn decode<R: Buf>(bytes: &mut R) -> coding::Result<Self> {
2242 Ok(Self {
2243 path_id: bytes.get()?,
2244 status_seq_no: bytes.get()?,
2245 })
2246 }
2247}
2248
2249#[derive(Debug, PartialEq, Eq, derive_more::Display)]
2250#[cfg_attr(test, derive(Arbitrary))]
2251#[display("PATH_STATUS_BACKUP path_id: {path_id} seq_no: {status_seq_no}")]
2252pub(crate) struct PathStatusBackup {
2253 pub(crate) path_id: PathId,
2254 pub(crate) status_seq_no: VarInt,
2255}
2256
2257impl PathStatusBackup {
2258 const TYPE: FrameType = FrameType::PathStatusBackup;
2259
2260 const fn get_type(&self) -> FrameType {
2261 FrameType::PathStatusBackup
2262 }
2263}
2264
2265impl Encodable for PathStatusBackup {
2266 fn encode<W: BufMut>(&self, buf: &mut W) {
2267 buf.write(Self::TYPE);
2268 buf.write(self.path_id);
2269 buf.write(self.status_seq_no);
2270 }
2271}
2272
2273impl Decodable for PathStatusBackup {
2274 fn decode<R: Buf>(bytes: &mut R) -> coding::Result<Self> {
2275 Ok(Self {
2276 path_id: bytes.get()?,
2277 status_seq_no: bytes.get()?,
2278 })
2279 }
2280}
2281
2282#[derive(Debug, PartialEq, Eq, Copy, Clone, PartialOrd, Ord, derive_more::Display)]
2287#[display("{} seq_no: {seq_no} addr: {}", self.get_type(), self.socket_addr())]
2288#[cfg_attr(test, derive(Arbitrary))]
2289pub(crate) struct AddAddress {
2290 pub(crate) seq_no: VarInt,
2293 pub(crate) ip: IpAddr,
2295 pub(crate) port: u16,
2297}
2298
2299#[allow(dead_code)]
2301impl AddAddress {
2302 pub(crate) const SIZE_BOUND: usize = Self {
2304 ip: IpAddr::V6(std::net::Ipv6Addr::LOCALHOST),
2305 port: u16::MAX,
2306 seq_no: VarInt::MAX,
2307 }
2308 .size();
2309
2310 pub(crate) const fn new((ip, port): (IpAddr, u16), seq_no: VarInt) -> Self {
2311 Self { ip, port, seq_no }
2312 }
2313
2314 const fn get_type(&self) -> FrameType {
2316 if self.ip.is_ipv6() {
2317 FrameType::AddIpv6Address
2318 } else {
2319 FrameType::AddIpv4Address
2320 }
2321 }
2322
2323 pub(crate) const fn size(&self) -> usize {
2325 let type_size = self.get_type().size();
2326 let seq_no_bytes = self.seq_no.size();
2327 let ip_bytes = if self.ip.is_ipv6() { 16 } else { 4 };
2328 let port_bytes = 2;
2329 type_size + seq_no_bytes + ip_bytes + port_bytes
2330 }
2331
2332 pub(crate) fn read<R: Buf>(bytes: &mut R, is_ipv6: bool) -> coding::Result<Self> {
2337 let seq_no = bytes.get()?;
2338 let ip = if is_ipv6 {
2339 IpAddr::V6(bytes.get()?)
2340 } else {
2341 IpAddr::V4(bytes.get()?)
2342 };
2343 let port = bytes.get()?;
2344 Ok(Self { seq_no, ip, port })
2345 }
2346
2347 pub(crate) fn socket_addr(&self) -> SocketAddr {
2349 self.ip_port().into()
2350 }
2351
2352 pub(crate) fn ip_port(&self) -> (IpAddr, u16) {
2353 (self.ip, self.port)
2354 }
2355}
2356
2357impl Encodable for AddAddress {
2358 fn encode<W: BufMut>(&self, buf: &mut W) {
2359 buf.write(self.get_type());
2360 buf.write(self.seq_no);
2361 match self.ip {
2362 IpAddr::V4(ipv4_addr) => {
2363 buf.write(ipv4_addr);
2364 }
2365 IpAddr::V6(ipv6_addr) => {
2366 buf.write(ipv6_addr);
2367 }
2368 }
2369 buf.write::<u16>(self.port);
2370 }
2371}
2372
2373#[derive(Debug, PartialEq, Eq, Clone, derive_more::Display)]
2377#[display("REACH_OUT round: {round} local_addr: {}", self.socket_addr())]
2378#[cfg_attr(test, derive(Arbitrary))]
2379pub(crate) struct ReachOut {
2380 pub(crate) round: VarInt,
2382 pub(crate) ip: IpAddr,
2384 pub(crate) port: u16,
2386}
2387
2388impl ReachOut {
2389 pub(crate) const fn get_type(&self) -> FrameType {
2391 if self.ip.is_ipv6() {
2392 FrameType::ReachOutAtIpv6
2393 } else {
2394 FrameType::ReachOutAtIpv4
2395 }
2396 }
2397
2398 pub(crate) const fn size(&self) -> usize {
2400 let type_size = self.get_type().size();
2401 let round_bytes = self.round.size();
2402 let ip_bytes = if self.ip.is_ipv6() { 16 } else { 4 };
2403 let port_bytes = 2;
2404 type_size + round_bytes + ip_bytes + port_bytes
2405 }
2406
2407 pub(crate) fn read<R: Buf>(bytes: &mut R, is_ipv6: bool) -> coding::Result<Self> {
2412 let round = bytes.get()?;
2413 let ip = if is_ipv6 {
2414 IpAddr::V6(bytes.get()?)
2415 } else {
2416 IpAddr::V4(bytes.get()?)
2417 };
2418 let port = bytes.get()?;
2419 Ok(Self { round, ip, port })
2420 }
2421
2422 pub(crate) fn socket_addr(&self) -> SocketAddr {
2424 (self.ip, self.port).into()
2425 }
2426}
2427
2428impl Encodable for ReachOut {
2429 fn encode<W: BufMut>(&self, buf: &mut W) {
2430 buf.write(self.get_type());
2431 buf.write(self.round);
2432 match self.ip {
2433 IpAddr::V4(ipv4_addr) => {
2434 buf.write(ipv4_addr);
2435 }
2436 IpAddr::V6(ipv6_addr) => {
2437 buf.write(ipv6_addr);
2438 }
2439 }
2440 buf.write::<u16>(self.port);
2441 }
2442}
2443
2444#[derive(Debug, PartialEq, Eq, Copy, Clone, PartialOrd, Ord, derive_more::Display)]
2446#[cfg_attr(test, derive(Arbitrary))]
2447#[display("REMOVE_ADDRESS seq_no: {seq_no}")]
2448pub(crate) struct RemoveAddress {
2449 pub(crate) seq_no: VarInt,
2451}
2452
2453#[allow(dead_code)]
2455impl RemoveAddress {
2456 pub(crate) const TYPE: FrameType = FrameType::RemoveAddress;
2458
2459 pub(crate) const SIZE_BOUND: usize = Self::new(VarInt::MAX).size();
2461
2462 pub(crate) const fn new(seq_no: VarInt) -> Self {
2463 Self { seq_no }
2464 }
2465
2466 pub(crate) const fn size(&self) -> usize {
2468 let type_size = Self::TYPE.size();
2469 let seq_no_bytes = self.seq_no.size();
2470 type_size + seq_no_bytes
2471 }
2472
2473 pub(crate) fn read<R: Buf>(bytes: &mut R) -> coding::Result<Self> {
2478 Ok(Self {
2479 seq_no: bytes.get()?,
2480 })
2481 }
2482
2483 const fn get_type(&self) -> FrameType {
2484 FrameType::RemoveAddress
2485 }
2486}
2487
2488impl Encodable for RemoveAddress {
2489 fn encode<W: BufMut>(&self, buf: &mut W) {
2490 buf.write(Self::TYPE);
2491 buf.write(self.seq_no);
2492 }
2493}
2494
2495struct DisplayOption<T: Display> {
2499 field_name: &'static str,
2500 op: Option<T>,
2501}
2502
2503impl<T: Display> DisplayOption<T> {
2504 fn new(field_name: &'static str, op: Option<T>) -> Self {
2505 Self { field_name, op }
2506 }
2507}
2508
2509impl<T: Display> Display for DisplayOption<T> {
2510 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2511 if let Some(x) = self.op.as_ref() {
2512 write!(f, "{}: {x}", self.field_name)
2513 } else {
2514 fmt::Result::Ok(())
2515 }
2516 }
2517}
2518
2519#[cfg(test)]
2520mod test {
2521 use super::*;
2522 use crate::coding::Encodable;
2523 use assert_matches::assert_matches;
2524
2525 #[test]
2526 fn frame_type() {
2527 assert_eq!(
2528 FrameType::try_from(FrameType::Padding.to_u64()),
2529 Ok(FrameType::Padding),
2530 );
2531
2532 assert_eq!(
2533 FrameType::try_from(FrameType::Datagram(DatagramInfo(0x30)).to_u64()),
2534 Ok(FrameType::Datagram(DatagramInfo(0x30))),
2535 );
2536
2537 assert_eq!(
2538 FrameType::try_from(FrameType::Stream(StreamInfo(0x08)).to_u64()),
2539 Ok(FrameType::Stream(StreamInfo(0x08))),
2540 );
2541 }
2542
2543 #[track_caller]
2544 fn frames(buf: Vec<u8>) -> Vec<Frame> {
2545 Iter::new(Bytes::from(buf))
2546 .unwrap()
2547 .collect::<Result<Vec<_>, _>>()
2548 .unwrap()
2549 }
2550
2551 #[test]
2552 fn ack_coding() {
2553 const PACKETS: &[u64] = &[1, 2, 3, 5, 10, 11, 14];
2554 let mut ranges = ArrayRangeSet::new();
2555 for &packet in PACKETS {
2556 ranges.insert(packet..packet + 1);
2557 }
2558 let mut buf = Vec::new();
2559 const ECN: EcnCounts = EcnCounts {
2560 ect0: 42,
2561 ect1: 24,
2562 ce: 12,
2563 };
2564 Ack::encoder(42, &ranges, Some(&ECN)).encode(&mut buf);
2565 let frames = frames(buf);
2566 assert_eq!(frames.len(), 1);
2567 match frames[0] {
2568 Frame::Ack(ref ack) => {
2569 let mut packets = ack.iter().flatten().collect::<Vec<_>>();
2570 packets.sort_unstable();
2571 assert_eq!(&packets[..], PACKETS);
2572 assert_eq!(ack.ecn, Some(ECN));
2573 }
2574 ref x => panic!("incorrect frame {x:?}"),
2575 }
2576 }
2577
2578 #[test]
2579 #[allow(clippy::range_plus_one)]
2580 fn path_ack_coding_with_ecn() {
2581 const PACKETS: &[u64] = &[1, 2, 3, 5, 10, 11, 14];
2582 let mut ranges = ArrayRangeSet::new();
2583 for &packet in PACKETS {
2584 ranges.insert(packet..packet + 1);
2585 }
2586 let mut buf = Vec::new();
2587 const ECN: EcnCounts = EcnCounts {
2588 ect0: 42,
2589 ect1: 24,
2590 ce: 12,
2591 };
2592 const PATH_ID: PathId = PathId::MAX;
2593 PathAck::encoder(PATH_ID, 42, &ranges, Some(&ECN)).encode(&mut buf);
2594 let frames = frames(buf);
2595 assert_eq!(frames.len(), 1);
2596 match frames[0] {
2597 Frame::PathAck(ref ack) => {
2598 assert_eq!(ack.path_id, PATH_ID);
2599 let mut packets = ack.ranges.iter().flatten().collect::<Vec<_>>();
2600 packets.sort_unstable();
2601 assert_eq!(&packets[..], PACKETS);
2602 assert_eq!(ack.ecn, Some(ECN));
2603 }
2604 ref x => panic!("incorrect frame {x:?}"),
2605 }
2606 }
2607
2608 #[test]
2609 #[allow(clippy::range_plus_one)]
2610 fn path_ack_coding_no_ecn() {
2611 const PACKETS: &[u64] = &[1, 2, 3, 5, 10, 11, 14];
2612 let mut ranges = ArrayRangeSet::new();
2613 for &packet in PACKETS {
2614 ranges.insert(packet..packet + 1);
2615 }
2616 let mut buf = Vec::new();
2617 const PATH_ID: PathId = PathId::MAX;
2618 PathAck::encoder(PATH_ID, 42, &ranges, None).encode(&mut buf);
2619 let frames = frames(buf);
2620 assert_eq!(frames.len(), 1);
2621 match frames[0] {
2622 Frame::PathAck(ref ack) => {
2623 assert_eq!(ack.path_id, PATH_ID);
2624 let mut packets = ack.ranges.iter().flatten().collect::<Vec<_>>();
2625 packets.sort_unstable();
2626 assert_eq!(&packets[..], PACKETS);
2627 assert_eq!(ack.ecn, None);
2628 }
2629 ref x => panic!("incorrect frame {x:?}"),
2630 }
2631 }
2632
2633 #[test]
2634 fn ack_frequency_coding() {
2635 let mut buf = Vec::new();
2636 let original = AckFrequency {
2637 sequence: VarInt(42),
2638 ack_eliciting_threshold: VarInt(20),
2639 request_max_ack_delay: VarInt(50_000),
2640 reordering_threshold: VarInt(1),
2641 };
2642 original.encode(&mut buf);
2643 let frames = frames(buf);
2644 assert_eq!(frames.len(), 1);
2645 match &frames[0] {
2646 Frame::AckFrequency(decoded) => assert_eq!(decoded, &original),
2647 x => panic!("incorrect frame {x:?}"),
2648 }
2649 }
2650
2651 #[test]
2652 fn immediate_ack_coding() {
2653 let mut buf = Vec::new();
2654 FrameType::ImmediateAck.encode(&mut buf);
2655 let frames = frames(buf);
2656 assert_eq!(frames.len(), 1);
2657 assert_matches!(&frames[0], Frame::ImmediateAck);
2658 }
2659
2660 #[test]
2662 fn test_observed_addr_roundrip() {
2663 let observed_addr = ObservedAddr {
2664 seq_no: VarInt(42),
2665 ip: std::net::Ipv4Addr::LOCALHOST.into(),
2666 port: 4242,
2667 };
2668 let mut buf = Vec::with_capacity(observed_addr.size());
2669 observed_addr.encode(&mut buf);
2670
2671 assert_eq!(
2672 observed_addr.size(),
2673 buf.len(),
2674 "expected written bytes and actual size differ"
2675 );
2676
2677 let mut decoded = frames(buf);
2678 assert_eq!(decoded.len(), 1);
2679 match decoded.pop().expect("non empty") {
2680 Frame::ObservedAddr(decoded) => assert_eq!(decoded, observed_addr),
2681 x => panic!("incorrect frame {x:?}"),
2682 }
2683 }
2684
2685 #[test]
2686 fn test_path_abandon_roundtrip() {
2687 let abandon = PathAbandon {
2688 path_id: PathId(42),
2689 error_code: TransportErrorCode::NO_ERROR,
2690 };
2691 let mut buf = Vec::new();
2692 abandon.encode(&mut buf);
2693
2694 let mut decoded = frames(buf);
2695 assert_eq!(decoded.len(), 1);
2696 match decoded.pop().expect("non empty") {
2697 Frame::PathAbandon(decoded) => assert_eq!(decoded, abandon),
2698 x => panic!("incorrect frame {x:?}"),
2699 }
2700 }
2701
2702 #[test]
2703 fn test_path_status_available_roundtrip() {
2704 let path_status_available = PathStatusAvailable {
2705 path_id: PathId(42),
2706 status_seq_no: VarInt(73),
2707 };
2708 let mut buf = Vec::new();
2709 path_status_available.encode(&mut buf);
2710
2711 let mut decoded = frames(buf);
2712 assert_eq!(decoded.len(), 1);
2713 match decoded.pop().expect("non empty") {
2714 Frame::PathStatusAvailable(decoded) => assert_eq!(decoded, path_status_available),
2715 x => panic!("incorrect frame {x:?}"),
2716 }
2717 }
2718
2719 #[test]
2720 fn test_path_status_backup_roundtrip() {
2721 let path_status_backup = PathStatusBackup {
2722 path_id: PathId(42),
2723 status_seq_no: VarInt(73),
2724 };
2725 let mut buf = Vec::new();
2726 path_status_backup.encode(&mut buf);
2727
2728 let mut decoded = frames(buf);
2729 assert_eq!(decoded.len(), 1);
2730 match decoded.pop().expect("non empty") {
2731 Frame::PathStatusBackup(decoded) => assert_eq!(decoded, path_status_backup),
2732 x => panic!("incorrect frame {x:?}"),
2733 }
2734 }
2735
2736 #[test]
2737 fn test_path_new_connection_id_roundtrip() {
2738 let cid = NewConnectionId {
2739 path_id: Some(PathId(22)),
2740 sequence: 31,
2741 retire_prior_to: 13,
2742 id: ConnectionId::new(&[0xAB; 8]),
2743 reset_token: ResetToken::from([0xCD; crate::RESET_TOKEN_SIZE]),
2744 };
2745 let mut buf = Vec::new();
2746 cid.encode(&mut buf);
2747
2748 let mut decoded = frames(buf);
2749 assert_eq!(decoded.len(), 1);
2750 match decoded.pop().expect("non empty") {
2751 Frame::NewConnectionId(decoded) => assert_eq!(decoded, cid),
2752 x => panic!("incorrect frame {x:?}"),
2753 }
2754 }
2755
2756 #[test]
2757 fn test_path_retire_connection_id_roundtrip() {
2758 let retire_cid = RetireConnectionId {
2759 path_id: Some(PathId(22)),
2760 sequence: 31,
2761 };
2762 let mut buf = Vec::new();
2763 retire_cid.encode(&mut buf);
2764
2765 let mut decoded = frames(buf);
2766 assert_eq!(decoded.len(), 1);
2767 match decoded.pop().expect("non empty") {
2768 Frame::RetireConnectionId(decoded) => assert_eq!(decoded, retire_cid),
2769 x => panic!("incorrect frame {x:?}"),
2770 }
2771 }
2772
2773 #[test]
2774 fn test_paths_blocked_path_cids_blocked_roundtrip() {
2775 let mut buf = Vec::new();
2776
2777 let frame0 = PathsBlocked(PathId(22));
2778 frame0.encode(&mut buf);
2779 let frame1 = PathCidsBlocked {
2780 path_id: PathId(23),
2781 next_seq: VarInt(32),
2782 };
2783 frame1.encode(&mut buf);
2784
2785 let mut decoded = frames(buf);
2786 assert_eq!(decoded.len(), 2);
2787 match decoded.pop().expect("non empty") {
2788 Frame::PathCidsBlocked(decoded) => assert_eq!(decoded, frame1),
2789 x => panic!("incorrect frame {x:?}"),
2790 }
2791 match decoded.pop().expect("non empty") {
2792 Frame::PathsBlocked(decoded) => assert_eq!(decoded, frame0),
2793 x => panic!("incorrect frame {x:?}"),
2794 }
2795 }
2796
2797 #[test]
2799 fn test_add_address_roundrip() {
2800 let add_address = AddAddress {
2801 seq_no: VarInt(42),
2802 ip: std::net::Ipv4Addr::LOCALHOST.into(),
2803 port: 4242,
2804 };
2805 let mut buf = Vec::with_capacity(add_address.size());
2806 add_address.encode(&mut buf);
2807
2808 assert_eq!(
2809 add_address.size(),
2810 buf.len(),
2811 "expected written bytes and actual size differ"
2812 );
2813
2814 let mut decoded = frames(buf);
2815 assert_eq!(decoded.len(), 1);
2816 match decoded.pop().expect("non empty") {
2817 Frame::AddAddress(decoded) => assert_eq!(decoded, add_address),
2818 x => panic!("incorrect frame {x:?}"),
2819 }
2820 }
2821
2822 #[test]
2824 fn test_reach_out_roundrip() {
2825 let reach_out = ReachOut {
2826 round: VarInt(42),
2827 ip: std::net::Ipv6Addr::LOCALHOST.into(),
2828 port: 4242,
2829 };
2830 let mut buf = Vec::with_capacity(reach_out.size());
2831 reach_out.encode(&mut buf);
2832
2833 assert_eq!(
2834 reach_out.size(),
2835 buf.len(),
2836 "expected written bytes and actual size differ"
2837 );
2838
2839 let mut decoded = frames(buf);
2840 assert_eq!(decoded.len(), 1);
2841 match decoded.pop().expect("non empty") {
2842 Frame::ReachOut(decoded) => assert_eq!(decoded, reach_out),
2843 x => panic!("incorrect frame {x:?}"),
2844 }
2845 }
2846
2847 #[test]
2849 fn test_remove_address_roundrip() {
2850 let remove_addr = RemoveAddress::new(VarInt(10));
2851 let mut buf = Vec::with_capacity(remove_addr.size());
2852 remove_addr.encode(&mut buf);
2853
2854 assert_eq!(
2855 remove_addr.size(),
2856 buf.len(),
2857 "expected written bytes and actual size differ"
2858 );
2859
2860 let mut decoded = frames(buf);
2861 assert_eq!(decoded.len(), 1);
2862 match decoded.pop().expect("non empty") {
2863 Frame::RemoveAddress(decoded) => assert_eq!(decoded, remove_addr),
2864 x => panic!("incorrect frame {x:?}"),
2865 }
2866 }
2867}