muxado/
frame.rs

1/// This module contains the definitions for muxado frames.
2///
3/// The [`codec`] module is responsible converting between their struct and wire
4/// format.
5use std::{
6    cmp,
7    fmt,
8    ops::{
9        Deref,
10        RangeInclusive,
11    },
12};
13
14use bitflags::bitflags;
15use bytes::Bytes;
16
17use crate::{
18    constrained::*,
19    errors::{
20        Error,
21        InvalidHeader,
22    },
23};
24
25pub const WNDINC_MAX: u32 = 0x7FFFFFFF;
26pub const STREAMID_MAX: u32 = 0x7FFFFFFF;
27pub const LENGTH_MAX: u32 = 0x00FFFFFF;
28pub const ERROR_MAX: u32 = u32::MAX;
29
30constrained_num!(StreamID, u32, 0..=STREAMID_MAX, clamp, mask);
31constrained_num!(WndInc, u32, 0..=WNDINC_MAX, clamp, mask);
32constrained_num!(Length, u32, 0..=LENGTH_MAX, clamp);
33constrained_num!(ErrorCode, u32, 0..=ERROR_MAX);
34
35bitflags! {
36    #[derive(Default)]
37    pub struct Flags: u8 {
38        const FIN = 0b0001;
39        const SYN = 0b0010;
40    }
41}
42
43#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
44pub struct Header {
45    pub length: Length,
46    pub typ: HeaderType,
47    pub flags: Flags,
48    pub stream_id: StreamID,
49}
50
51#[derive(Debug, Eq, PartialEq, Clone)]
52pub struct Frame {
53    pub header: Header,
54    pub body: Body,
55}
56
57impl From<Body> for Frame {
58    fn from(mut other: Body) -> Self {
59        let typ = other.header_type();
60        other.clamp_len();
61        let length = Length::clamp(other.len() as u32);
62        Frame {
63            header: Header {
64                length,
65                typ,
66                ..Default::default()
67            },
68            body: other,
69        }
70    }
71}
72
73impl Frame {
74    pub fn is_fin(&self) -> bool {
75        self.header.flags.contains(Flags::FIN)
76    }
77    pub fn is_syn(&self) -> bool {
78        self.header.flags.contains(Flags::SYN)
79    }
80    pub fn fin(mut self) -> Frame {
81        self.header.flags.set(Flags::FIN, true);
82        self
83    }
84    pub fn syn(mut self) -> Frame {
85        self.header.flags.set(Flags::SYN, true);
86        self
87    }
88    pub fn stream_id(mut self, id: StreamID) -> Frame {
89        self.header.stream_id = id;
90        self
91    }
92
93    pub fn rst(stream_id: StreamID, error: Error) -> Frame {
94        let length = Length::clamp(4);
95        Frame {
96            header: Header {
97                length,
98                stream_id,
99                typ: HeaderType::Rst,
100                ..Default::default()
101            },
102            body: Body::Rst(error),
103        }
104    }
105    pub fn goaway(last_stream_id: StreamID, error: Error, mut message: Bytes) -> Frame {
106        let length = Length::clamp(message.len() as u32);
107        message = message.slice(..*length as usize);
108        Frame {
109            header: Header {
110                length,
111                typ: HeaderType::GoAway,
112                ..Default::default()
113            },
114            body: Body::GoAway {
115                last_stream_id,
116                error,
117                message,
118            },
119        }
120    }
121}
122
123#[derive(Clone, Copy, Debug, PartialEq, Eq)]
124pub enum HeaderType {
125    Rst,
126    Data,
127    WndInc,
128    GoAway,
129    Invalid(u8),
130}
131
132impl Default for HeaderType {
133    fn default() -> Self {
134        HeaderType::Invalid(255)
135    }
136}
137
138impl From<u8> for HeaderType {
139    fn from(other: u8) -> HeaderType {
140        match other {
141            0 => HeaderType::Rst,
142            1 => HeaderType::Data,
143            2 => HeaderType::WndInc,
144            3 => HeaderType::GoAway,
145            t => HeaderType::Invalid(t),
146        }
147    }
148}
149
150impl From<HeaderType> for u8 {
151    fn from(other: HeaderType) -> u8 {
152        match other {
153            HeaderType::Rst => 0,
154            HeaderType::Data => 1,
155            HeaderType::WndInc => 2,
156            HeaderType::GoAway => 3,
157            HeaderType::Invalid(t) => t,
158        }
159    }
160}
161
162#[derive(Debug, Clone, Eq, PartialEq)]
163pub enum Body {
164    Rst(Error),
165    Data(Bytes),
166    WndInc(WndInc),
167    GoAway {
168        last_stream_id: StreamID,
169        error: Error,
170        message: Bytes,
171    },
172    Invalid {
173        error: InvalidHeader,
174        body: Bytes,
175    },
176}
177
178impl Default for Body {
179    fn default() -> Self {
180        Body::Data(Default::default())
181    }
182}
183
184impl Body {
185    pub fn header_type(&self) -> HeaderType {
186        match self {
187            Body::Data(_) => HeaderType::Data,
188            Body::GoAway { .. } => HeaderType::GoAway,
189            Body::WndInc(_) => HeaderType::WndInc,
190            Body::Rst(_) => HeaderType::Rst,
191            Body::Invalid { .. } => HeaderType::Invalid(0xff),
192        }
193    }
194
195    pub fn len(&self) -> usize {
196        match self {
197            Body::Data(bs) => bs.len(),
198            Body::GoAway { .. } => 8,
199            Body::WndInc(_) => 4,
200            Body::Rst(_) => 4,
201            Body::Invalid { body, .. } => body.len(),
202        }
203    }
204
205    pub fn clamp_len(&mut self) {
206        match self {
207            Body::Data(bs) => *bs = bs.slice(0..cmp::min(LENGTH_MAX as usize, bs.len())),
208            Body::Invalid { body, .. } => {
209                *body = body.slice(0..cmp::min(LENGTH_MAX as usize, body.len()))
210            }
211            _ => {}
212        }
213    }
214}