Coverage Report

Created: 2024-05-16 12:16

/__w/smoldot/smoldot/repo/lib/src/libp2p/connection/yamux/header.rs
Line
Count
Source (jump to first uncovered line)
1
// Smoldot
2
// Copyright (C) 2019-2022  Parity Technologies (UK) Ltd.
3
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
4
5
// This program is free software: you can redistribute it and/or modify
6
// it under the terms of the GNU General Public License as published by
7
// the Free Software Foundation, either version 3 of the License, or
8
// (at your option) any later version.
9
10
// This program is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
// GNU General Public License for more details.
14
15
// You should have received a copy of the GNU General Public License
16
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18
//! Decodes Yamux headers.
19
//!
20
//! See <https://github.com/hashicorp/yamux/blob/master/spec.md>
21
22
use core::num::NonZeroU32;
23
24
/// A Yamux header in its decoded form.
25
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
26
pub enum DecodedYamuxHeader {
27
    Data {
28
        /// Value of the SYN flag.
29
        syn: bool,
30
        /// Value of the ACK flag.
31
        ack: bool,
32
        /// Value of the FIN flag.
33
        fin: bool,
34
        /// Value of the RST flag.
35
        rst: bool,
36
        stream_id: NonZeroU32,
37
        length: u32,
38
    },
39
    Window {
40
        /// Value of the SYN flag.
41
        syn: bool,
42
        /// Value of the ACK flag.
43
        ack: bool,
44
        /// Value of the FIN flag.
45
        fin: bool,
46
        /// Value of the RST flag.
47
        rst: bool,
48
        stream_id: NonZeroU32,
49
        length: u32,
50
    },
51
    PingRequest {
52
        opaque_value: u32,
53
    },
54
    PingResponse {
55
        opaque_value: u32,
56
    },
57
    GoAway {
58
        error_code: GoAwayErrorCode,
59
    },
60
}
61
62
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
63
pub enum GoAwayErrorCode {
64
    NormalTermination = 0x0,
65
    ProtocolError = 0x1,
66
    InternalError = 0x2,
67
}
68
69
/// Encodes a Yamux header.
70
1.07k
pub fn encode(header: &DecodedYamuxHeader) -> [u8; 12] {
71
1.07k
    match header {
72
        DecodedYamuxHeader::Data {
73
569
            syn,
74
569
            ack,
75
569
            fin,
76
569
            rst,
77
569
            stream_id,
78
569
            length,
79
        }
80
        | DecodedYamuxHeader::Window {
81
500
            syn,
82
500
            ack,
83
500
            fin,
84
500
            rst,
85
500
            stream_id,
86
500
            length,
87
        } => {
88
1.06k
            let ty = match header {
89
569
                DecodedYamuxHeader::Data { .. } => 0,
90
500
                DecodedYamuxHeader::Window { .. } => 1,
91
0
                _ => unreachable!(),
92
            };
93
94
1.06k
            let mut flags: u8 = 0;
95
1.06k
            if *syn {
96
511
                flags |= 0x1;
97
558
            }
98
1.06k
            if *ack {
99
533
                flags |= 0x2;
100
536
            }
101
1.06k
            if *fin {
102
517
                flags |= 0x4;
103
552
            }
104
1.06k
            if *rst {
105
484
                flags |= 0x8;
106
585
            }
107
108
1.06k
            let stream_id = stream_id.get().to_be_bytes();
109
1.06k
            let length = length.to_be_bytes();
110
1.06k
111
1.06k
            [
112
1.06k
                0,
113
1.06k
                ty,
114
1.06k
                0,
115
1.06k
                flags,
116
1.06k
                stream_id[0],
117
1.06k
                stream_id[1],
118
1.06k
                stream_id[2],
119
1.06k
                stream_id[3],
120
1.06k
                length[0],
121
1.06k
                length[1],
122
1.06k
                length[2],
123
1.06k
                length[3],
124
1.06k
            ]
125
        }
126
1
        DecodedYamuxHeader::PingRequest { opaque_value }
127
1
        | DecodedYamuxHeader::PingResponse { opaque_value } => {
128
2
            let flags = match header {
129
1
                DecodedYamuxHeader::PingRequest { .. } => 1,
130
1
                DecodedYamuxHeader::PingResponse { .. } => 2,
131
0
                _ => unreachable!(),
132
            };
133
134
2
            let opaque_value = opaque_value.to_be_bytes();
135
2
136
2
            [
137
2
                0,
138
2
                2,
139
2
                0,
140
2
                flags,
141
2
                0,
142
2
                0,
143
2
                0,
144
2
                0,
145
2
                opaque_value[0],
146
2
                opaque_value[1],
147
2
                opaque_value[2],
148
2
                opaque_value[3],
149
2
            ]
150
        }
151
3
        DecodedYamuxHeader::GoAway { error_code } => {
152
3
            let code = match error_code {
153
1
                GoAwayErrorCode::NormalTermination => 0,
154
1
                GoAwayErrorCode::ProtocolError => 1,
155
1
                GoAwayErrorCode::InternalError => 2,
156
            };
157
158
3
            [0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, code]
159
        }
160
    }
161
1.07k
}
_RNvNtNtNtNtCsN16ciHI6Qf_7smoldot6libp2p10connection5yamux6header6encode
Line
Count
Source
70
1.07k
pub fn encode(header: &DecodedYamuxHeader) -> [u8; 12] {
71
1.07k
    match header {
72
        DecodedYamuxHeader::Data {
73
569
            syn,
74
569
            ack,
75
569
            fin,
76
569
            rst,
77
569
            stream_id,
78
569
            length,
79
        }
80
        | DecodedYamuxHeader::Window {
81
500
            syn,
82
500
            ack,
83
500
            fin,
84
500
            rst,
85
500
            stream_id,
86
500
            length,
87
        } => {
88
1.06k
            let ty = match header {
89
569
                DecodedYamuxHeader::Data { .. } => 0,
90
500
                DecodedYamuxHeader::Window { .. } => 1,
91
0
                _ => unreachable!(),
92
            };
93
94
1.06k
            let mut flags: u8 = 0;
95
1.06k
            if *syn {
96
511
                flags |= 0x1;
97
558
            }
98
1.06k
            if *ack {
99
533
                flags |= 0x2;
100
536
            }
101
1.06k
            if *fin {
102
517
                flags |= 0x4;
103
552
            }
104
1.06k
            if *rst {
105
484
                flags |= 0x8;
106
585
            }
107
108
1.06k
            let stream_id = stream_id.get().to_be_bytes();
109
1.06k
            let length = length.to_be_bytes();
110
1.06k
111
1.06k
            [
112
1.06k
                0,
113
1.06k
                ty,
114
1.06k
                0,
115
1.06k
                flags,
116
1.06k
                stream_id[0],
117
1.06k
                stream_id[1],
118
1.06k
                stream_id[2],
119
1.06k
                stream_id[3],
120
1.06k
                length[0],
121
1.06k
                length[1],
122
1.06k
                length[2],
123
1.06k
                length[3],
124
1.06k
            ]
125
        }
126
1
        DecodedYamuxHeader::PingRequest { opaque_value }
127
1
        | DecodedYamuxHeader::PingResponse { opaque_value } => {
128
2
            let flags = match header {
129
1
                DecodedYamuxHeader::PingRequest { .. } => 1,
130
1
                DecodedYamuxHeader::PingResponse { .. } => 2,
131
0
                _ => unreachable!(),
132
            };
133
134
2
            let opaque_value = opaque_value.to_be_bytes();
135
2
136
2
            [
137
2
                0,
138
2
                2,
139
2
                0,
140
2
                flags,
141
2
                0,
142
2
                0,
143
2
                0,
144
2
                0,
145
2
                opaque_value[0],
146
2
                opaque_value[1],
147
2
                opaque_value[2],
148
2
                opaque_value[3],
149
2
            ]
150
        }
151
3
        DecodedYamuxHeader::GoAway { error_code } => {
152
3
            let code = match error_code {
153
1
                GoAwayErrorCode::NormalTermination => 0,
154
1
                GoAwayErrorCode::ProtocolError => 1,
155
1
                GoAwayErrorCode::InternalError => 2,
156
            };
157
158
3
            [0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, code]
159
        }
160
    }
161
1.07k
}
Unexecuted instantiation: _RNvNtNtNtNtCseuYC0Zibziv_7smoldot6libp2p10connection5yamux6header6encode
162
163
/// Decodes a Yamux header.
164
1.09k
pub fn decode_yamux_header(bytes: &[u8; 12]) -> Result<DecodedYamuxHeader, YamuxHeaderDecodeError> {
165
1.09k
    match nom::combinator::all_consuming(nom::combinator::complete(decode))(bytes) {
166
1.08k
        Ok((_, h)) => Ok(h),
167
0
        Err(nom::Err::Incomplete(_)) => unreachable!(),
168
15
        Err(nom::Err::Failure(
err0
) | nom::Err::Error(err)) => Err(YamuxHeaderDecodeError {
169
15
            offset: err.input.as_ptr() as usize - bytes.as_ptr() as usize,
170
15
        }),
171
    }
172
1.09k
}
_RNvNtNtNtNtCsN16ciHI6Qf_7smoldot6libp2p10connection5yamux6header19decode_yamux_header
Line
Count
Source
164
1.09k
pub fn decode_yamux_header(bytes: &[u8; 12]) -> Result<DecodedYamuxHeader, YamuxHeaderDecodeError> {
165
1.09k
    match nom::combinator::all_consuming(nom::combinator::complete(decode))(bytes) {
166
1.08k
        Ok((_, h)) => Ok(h),
167
0
        Err(nom::Err::Incomplete(_)) => unreachable!(),
168
15
        Err(nom::Err::Failure(
err0
) | nom::Err::Error(err)) => Err(YamuxHeaderDecodeError {
169
15
            offset: err.input.as_ptr() as usize - bytes.as_ptr() as usize,
170
15
        }),
171
    }
172
1.09k
}
Unexecuted instantiation: _RNvNtNtNtNtCseuYC0Zibziv_7smoldot6libp2p10connection5yamux6header19decode_yamux_header
173
174
/// Error while decoding a Yamux header.
175
0
#[derive(Debug, derive_more::Display)]
Unexecuted instantiation: _RNvXsb_NtNtNtNtCsN16ciHI6Qf_7smoldot6libp2p10connection5yamux6headerNtB5_22YamuxHeaderDecodeErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXsb_NtNtNtNtCseuYC0Zibziv_7smoldot6libp2p10connection5yamux6headerNtB5_22YamuxHeaderDecodeErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
176
#[display(fmt = "Error at offset {offset}")]
177
pub struct YamuxHeaderDecodeError {
178
    offset: usize,
179
}
180
181
1.09k
fn decode(bytes: &'_ [u8]) -> nom::IResult<&'_ [u8], DecodedYamuxHeader> {
182
1.09k
    nom::sequence::preceded(
183
1.09k
        nom::bytes::streaming::tag(&[0]),
184
1.09k
        nom::branch::alt((
185
1.09k
            nom::combinator::map(
186
1.09k
                nom::sequence::tuple((
187
1.09k
                    nom::bytes::streaming::tag(&[0]),
188
1.09k
                    flags,
189
1.09k
                    nom::combinator::map_opt(nom::number::streaming::be_u32, NonZeroU32::new),
190
1.09k
                    nom::number::streaming::be_u32,
191
1.09k
                )),
192
1.09k
                |(_, (syn, ack, fin, rst), stream_id, length)| DecodedYamuxHeader::Data {
193
569
                    syn,
194
569
                    ack,
195
569
                    fin,
196
569
                    rst,
197
569
                    stream_id,
198
569
                    length,
199
1.09k
                },
_RNCNvNtNtNtNtCsN16ciHI6Qf_7smoldot6libp2p10connection5yamux6header6decode0Bb_
Line
Count
Source
192
569
                |(_, (syn, ack, fin, rst), stream_id, length)| DecodedYamuxHeader::Data {
193
569
                    syn,
194
569
                    ack,
195
569
                    fin,
196
569
                    rst,
197
569
                    stream_id,
198
569
                    length,
199
569
                },
Unexecuted instantiation: _RNCNvNtNtNtNtCseuYC0Zibziv_7smoldot6libp2p10connection5yamux6header6decode0Bb_
200
1.09k
            ),
201
1.09k
            nom::combinator::map(
202
1.09k
                nom::sequence::tuple((
203
1.09k
                    nom::bytes::streaming::tag(&[1]),
204
1.09k
                    flags,
205
1.09k
                    nom::combinator::map_opt(nom::number::streaming::be_u32, NonZeroU32::new),
206
1.09k
                    nom::number::streaming::be_u32,
207
1.09k
                )),
208
1.09k
                |(_, (syn, ack, fin, rst), stream_id, length)| DecodedYamuxHeader::Window {
209
500
                    syn,
210
500
                    ack,
211
500
                    fin,
212
500
                    rst,
213
500
                    stream_id,
214
500
                    length,
215
1.09k
                },
_RNCNvNtNtNtNtCsN16ciHI6Qf_7smoldot6libp2p10connection5yamux6header6decodes_0Bb_
Line
Count
Source
208
500
                |(_, (syn, ack, fin, rst), stream_id, length)| DecodedYamuxHeader::Window {
209
500
                    syn,
210
500
                    ack,
211
500
                    fin,
212
500
                    rst,
213
500
                    stream_id,
214
500
                    length,
215
500
                },
Unexecuted instantiation: _RNCNvNtNtNtNtCseuYC0Zibziv_7smoldot6libp2p10connection5yamux6header6decodes_0Bb_
216
1.09k
            ),
217
1.09k
            nom::combinator::map(
218
1.09k
                nom::sequence::tuple((
219
1.09k
                    nom::bytes::streaming::tag(&[2]),
220
1.09k
                    nom::bytes::streaming::tag(&[0x0, 0x1]),
221
1.09k
                    nom::bytes::streaming::tag(&[0, 0, 0, 0]),
222
1.09k
                    nom::number::streaming::be_u32,
223
1.09k
                )),
224
1.09k
                |(_, _, _, opaque_value)| 
DecodedYamuxHeader::PingRequest { opaque_value }3
,
_RNCNvNtNtNtNtCsN16ciHI6Qf_7smoldot6libp2p10connection5yamux6header6decodes0_0Bb_
Line
Count
Source
224
3
                |(_, _, _, opaque_value)| DecodedYamuxHeader::PingRequest { opaque_value },
Unexecuted instantiation: _RNCNvNtNtNtNtCseuYC0Zibziv_7smoldot6libp2p10connection5yamux6header6decodes0_0Bb_
225
1.09k
            ),
226
1.09k
            nom::combinator::map(
227
1.09k
                nom::sequence::tuple((
228
1.09k
                    nom::bytes::streaming::tag(&[2]),
229
1.09k
                    nom::bytes::streaming::tag(&[0x0, 0x2]),
230
1.09k
                    nom::bytes::streaming::tag(&[0, 0, 0, 0]),
231
1.09k
                    nom::number::streaming::be_u32,
232
1.09k
                )),
233
1.09k
                |(_, _, _, opaque_value)| 
DecodedYamuxHeader::PingResponse { opaque_value }3
,
_RNCNvNtNtNtNtCsN16ciHI6Qf_7smoldot6libp2p10connection5yamux6header6decodes1_0Bb_
Line
Count
Source
233
3
                |(_, _, _, opaque_value)| DecodedYamuxHeader::PingResponse { opaque_value },
Unexecuted instantiation: _RNCNvNtNtNtNtCseuYC0Zibziv_7smoldot6libp2p10connection5yamux6header6decodes1_0Bb_
234
1.09k
            ),
235
1.09k
            nom::combinator::map(
236
1.09k
                nom::sequence::tuple((
237
1.09k
                    nom::bytes::streaming::tag(&[3]),
238
1.09k
                    nom::bytes::streaming::tag(&[0, 0]),
239
1.09k
                    nom::bytes::streaming::tag(&[0, 0, 0, 0]),
240
1.09k
                    nom::branch::alt((
241
1.09k
                        nom::combinator::map(
242
1.09k
                            nom::bytes::streaming::tag(0u32.to_be_bytes()),
243
1.09k
                            |_| 
GoAwayErrorCode::NormalTermination2
,
_RNCNvNtNtNtNtCsN16ciHI6Qf_7smoldot6libp2p10connection5yamux6header6decodes2_0Bb_
Line
Count
Source
243
2
                            |_| GoAwayErrorCode::NormalTermination,
Unexecuted instantiation: _RNCNvNtNtNtNtCseuYC0Zibziv_7smoldot6libp2p10connection5yamux6header6decodes2_0Bb_
244
1.09k
                        ),
245
1.09k
                        nom::combinator::map(
246
1.09k
                            nom::bytes::streaming::tag(1u32.to_be_bytes()),
247
1.09k
                            |_| 
GoAwayErrorCode::ProtocolError2
,
_RNCNvNtNtNtNtCsN16ciHI6Qf_7smoldot6libp2p10connection5yamux6header6decodes3_0Bb_
Line
Count
Source
247
2
                            |_| GoAwayErrorCode::ProtocolError,
Unexecuted instantiation: _RNCNvNtNtNtNtCseuYC0Zibziv_7smoldot6libp2p10connection5yamux6header6decodes3_0Bb_
248
1.09k
                        ),
249
1.09k
                        nom::combinator::map(
250
1.09k
                            nom::bytes::streaming::tag(2u32.to_be_bytes()),
251
1.09k
                            |_| 
GoAwayErrorCode::InternalError2
,
_RNCNvNtNtNtNtCsN16ciHI6Qf_7smoldot6libp2p10connection5yamux6header6decodes4_0Bb_
Line
Count
Source
251
2
                            |_| GoAwayErrorCode::InternalError,
Unexecuted instantiation: _RNCNvNtNtNtNtCseuYC0Zibziv_7smoldot6libp2p10connection5yamux6header6decodes4_0Bb_
252
1.09k
                        ),
253
1.09k
                    )),
254
1.09k
                )),
255
1.09k
                |(_, _, _, error_code)| 
DecodedYamuxHeader::GoAway { error_code }6
,
_RNCNvNtNtNtNtCsN16ciHI6Qf_7smoldot6libp2p10connection5yamux6header6decodes5_0Bb_
Line
Count
Source
255
6
                |(_, _, _, error_code)| DecodedYamuxHeader::GoAway { error_code },
Unexecuted instantiation: _RNCNvNtNtNtNtCseuYC0Zibziv_7smoldot6libp2p10connection5yamux6header6decodes5_0Bb_
256
1.09k
            ),
257
1.09k
        )),
258
1.09k
    )(bytes)
259
1.09k
}
_RNvNtNtNtNtCsN16ciHI6Qf_7smoldot6libp2p10connection5yamux6header6decode
Line
Count
Source
181
1.09k
fn decode(bytes: &'_ [u8]) -> nom::IResult<&'_ [u8], DecodedYamuxHeader> {
182
1.09k
    nom::sequence::preceded(
183
1.09k
        nom::bytes::streaming::tag(&[0]),
184
1.09k
        nom::branch::alt((
185
1.09k
            nom::combinator::map(
186
1.09k
                nom::sequence::tuple((
187
1.09k
                    nom::bytes::streaming::tag(&[0]),
188
1.09k
                    flags,
189
1.09k
                    nom::combinator::map_opt(nom::number::streaming::be_u32, NonZeroU32::new),
190
1.09k
                    nom::number::streaming::be_u32,
191
1.09k
                )),
192
1.09k
                |(_, (syn, ack, fin, rst), stream_id, length)| DecodedYamuxHeader::Data {
193
                    syn,
194
                    ack,
195
                    fin,
196
                    rst,
197
                    stream_id,
198
                    length,
199
1.09k
                },
200
1.09k
            ),
201
1.09k
            nom::combinator::map(
202
1.09k
                nom::sequence::tuple((
203
1.09k
                    nom::bytes::streaming::tag(&[1]),
204
1.09k
                    flags,
205
1.09k
                    nom::combinator::map_opt(nom::number::streaming::be_u32, NonZeroU32::new),
206
1.09k
                    nom::number::streaming::be_u32,
207
1.09k
                )),
208
1.09k
                |(_, (syn, ack, fin, rst), stream_id, length)| DecodedYamuxHeader::Window {
209
                    syn,
210
                    ack,
211
                    fin,
212
                    rst,
213
                    stream_id,
214
                    length,
215
1.09k
                },
216
1.09k
            ),
217
1.09k
            nom::combinator::map(
218
1.09k
                nom::sequence::tuple((
219
1.09k
                    nom::bytes::streaming::tag(&[2]),
220
1.09k
                    nom::bytes::streaming::tag(&[0x0, 0x1]),
221
1.09k
                    nom::bytes::streaming::tag(&[0, 0, 0, 0]),
222
1.09k
                    nom::number::streaming::be_u32,
223
1.09k
                )),
224
1.09k
                |(_, _, _, opaque_value)| DecodedYamuxHeader::PingRequest { opaque_value },
225
1.09k
            ),
226
1.09k
            nom::combinator::map(
227
1.09k
                nom::sequence::tuple((
228
1.09k
                    nom::bytes::streaming::tag(&[2]),
229
1.09k
                    nom::bytes::streaming::tag(&[0x0, 0x2]),
230
1.09k
                    nom::bytes::streaming::tag(&[0, 0, 0, 0]),
231
1.09k
                    nom::number::streaming::be_u32,
232
1.09k
                )),
233
1.09k
                |(_, _, _, opaque_value)| DecodedYamuxHeader::PingResponse { opaque_value },
234
1.09k
            ),
235
1.09k
            nom::combinator::map(
236
1.09k
                nom::sequence::tuple((
237
1.09k
                    nom::bytes::streaming::tag(&[3]),
238
1.09k
                    nom::bytes::streaming::tag(&[0, 0]),
239
1.09k
                    nom::bytes::streaming::tag(&[0, 0, 0, 0]),
240
1.09k
                    nom::branch::alt((
241
1.09k
                        nom::combinator::map(
242
1.09k
                            nom::bytes::streaming::tag(0u32.to_be_bytes()),
243
1.09k
                            |_| GoAwayErrorCode::NormalTermination,
244
1.09k
                        ),
245
1.09k
                        nom::combinator::map(
246
1.09k
                            nom::bytes::streaming::tag(1u32.to_be_bytes()),
247
1.09k
                            |_| GoAwayErrorCode::ProtocolError,
248
1.09k
                        ),
249
1.09k
                        nom::combinator::map(
250
1.09k
                            nom::bytes::streaming::tag(2u32.to_be_bytes()),
251
1.09k
                            |_| GoAwayErrorCode::InternalError,
252
1.09k
                        ),
253
1.09k
                    )),
254
1.09k
                )),
255
1.09k
                |(_, _, _, error_code)| DecodedYamuxHeader::GoAway { error_code },
256
1.09k
            ),
257
1.09k
        )),
258
1.09k
    )(bytes)
259
1.09k
}
Unexecuted instantiation: _RNvNtNtNtNtCseuYC0Zibziv_7smoldot6libp2p10connection5yamux6header6decode
260
261
1.06k
fn flags(bytes: &'_ [u8]) -> nom::IResult<&'_ [u8], (bool, bool, bool, bool)> {
262
1.06k
    nom::combinator::map_opt(nom::number::streaming::be_u16, |flags| {
263
1.06k
        let syn = (flags & 0x1) != 0;
264
1.06k
        let ack = (flags & 0x2) != 0;
265
1.06k
        let fin = (flags & 0x4) != 0;
266
1.06k
        let rst = (flags & 0x8) != 0;
267
1.06k
        if (flags & !0b1111) != 0 {
268
0
            return None;
269
1.06k
        }
270
1.06k
        Some((syn, ack, fin, rst))
271
1.06k
    })(bytes)
_RNCNvNtNtNtNtCsN16ciHI6Qf_7smoldot6libp2p10connection5yamux6header5flags0Bb_
Line
Count
Source
262
1.06k
    nom::combinator::map_opt(nom::number::streaming::be_u16, |flags| {
263
1.06k
        let syn = (flags & 0x1) != 0;
264
1.06k
        let ack = (flags & 0x2) != 0;
265
1.06k
        let fin = (flags & 0x4) != 0;
266
1.06k
        let rst = (flags & 0x8) != 0;
267
1.06k
        if (flags & !0b1111) != 0 {
268
0
            return None;
269
1.06k
        }
270
1.06k
        Some((syn, ack, fin, rst))
271
1.06k
    })(bytes)
Unexecuted instantiation: _RNCNvNtNtNtNtCseuYC0Zibziv_7smoldot6libp2p10connection5yamux6header5flags0Bb_
272
1.06k
}
_RNvNtNtNtNtCsN16ciHI6Qf_7smoldot6libp2p10connection5yamux6header5flags
Line
Count
Source
261
1.06k
fn flags(bytes: &'_ [u8]) -> nom::IResult<&'_ [u8], (bool, bool, bool, bool)> {
262
1.06k
    nom::combinator::map_opt(nom::number::streaming::be_u16, |flags| {
263
        let syn = (flags & 0x1) != 0;
264
        let ack = (flags & 0x2) != 0;
265
        let fin = (flags & 0x4) != 0;
266
        let rst = (flags & 0x8) != 0;
267
        if (flags & !0b1111) != 0 {
268
            return None;
269
        }
270
        Some((syn, ack, fin, rst))
271
1.06k
    })(bytes)
272
1.06k
}
Unexecuted instantiation: _RNvNtNtNtNtCseuYC0Zibziv_7smoldot6libp2p10connection5yamux6header5flags
273
274
#[cfg(test)]
275
mod tests {
276
    use core::num::NonZeroU32;
277
278
    #[test]
279
1
    fn decode_data_frame() {
280
1
        assert_eq!(
281
1
            super::decode_yamux_header(&[0, 0, 0, 1, 0, 0, 0, 15, 0, 0, 2, 65]).unwrap(),
282
1
            super::DecodedYamuxHeader::Data {
283
1
                syn: true,
284
1
                ack: false,
285
1
                fin: false,
286
1
                rst: false,
287
1
                stream_id: NonZeroU32::new(15).unwrap(),
288
1
                length: 577
289
1
            }
290
1
        );
291
1
    }
292
293
    #[test]
294
1
    fn decode_ping_frame() {
295
1
        assert_eq!(
296
1
            super::decode_yamux_header(&[0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 1, 12]).unwrap(),
297
1
            super::DecodedYamuxHeader::PingRequest { opaque_value: 268 }
298
1
        );
299
300
1
        assert_eq!(
301
1
            super::decode_yamux_header(&[0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 1, 12]).unwrap(),
302
1
            super::DecodedYamuxHeader::PingResponse { opaque_value: 268 }
303
1
        );
304
305
1
        assert!(super::decode_yamux_header(&[0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).is_err());
306
307
1
        assert!(super::decode_yamux_header(&[0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]).is_ok());
308
1
        assert!(super::decode_yamux_header(&[0, 2, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0]).is_err());
309
310
1
        assert!(super::decode_yamux_header(&[0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0]).is_ok());
311
1
        assert!(super::decode_yamux_header(&[0, 2, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0]).is_err());
312
313
1
        assert!(super::decode_yamux_header(&[0, 2, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0]).is_err());
314
1
        assert!(super::decode_yamux_header(&[0, 2, 0, 5, 0, 0, 0, 1, 0, 0, 0, 0]).is_err());
315
1
        assert!(super::decode_yamux_header(&[0, 2, 0, 9, 0, 0, 0, 1, 0, 0, 0, 0]).is_err());
316
1
        assert!(super::decode_yamux_header(&[0, 2, 0, 17, 0, 0, 0, 1, 0, 0, 0, 0]).is_err());
317
1
    }
318
319
    #[test]
320
1
    fn decode_goaway() {
321
1
        assert_eq!(
322
1
            super::decode_yamux_header(&[0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).unwrap(),
323
1
            super::DecodedYamuxHeader::GoAway {
324
1
                error_code: super::GoAwayErrorCode::NormalTermination,
325
1
            }
326
1
        );
327
328
1
        assert_eq!(
329
1
            super::decode_yamux_header(&[0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]).unwrap(),
330
1
            super::DecodedYamuxHeader::GoAway {
331
1
                error_code: super::GoAwayErrorCode::ProtocolError,
332
1
            }
333
1
        );
334
335
1
        assert_eq!(
336
1
            super::decode_yamux_header(&[0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]).unwrap(),
337
1
            super::DecodedYamuxHeader::GoAway {
338
1
                error_code: super::GoAwayErrorCode::InternalError,
339
1
            }
340
1
        );
341
342
1
        assert!(super::decode_yamux_header(&[0, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]).is_err());
343
1
        assert!(super::decode_yamux_header(&[0, 3, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0]).is_err());
344
1
        assert!(super::decode_yamux_header(&[0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]).is_err());
345
1
        assert!(super::decode_yamux_header(&[0, 3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0]).is_err());
346
1
        assert!(super::decode_yamux_header(&[0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]).is_err());
347
1
        assert!(super::decode_yamux_header(&[0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3]).is_err());
348
1
        assert!(super::decode_yamux_header(&[0, 3, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0]).is_err());
349
1
    }
350
351
    #[test]
352
1
    fn version_check() {
353
1
        assert!(super::decode_yamux_header(&[0, 0, 0, 1, 0, 0, 0, 15, 0, 0, 2, 65]).is_ok());
354
1
        assert!(super::decode_yamux_header(&[2, 0, 0, 1, 0, 0, 0, 15, 0, 0, 2, 65]).is_err());
355
1
    }
356
357
    macro_rules! check_encode_redecodes {
358
        ($payload:expr) => {{
359
            let payload = $payload;
360
            assert_eq!(
361
                super::decode_yamux_header(&super::encode(&payload)).unwrap(),
362
                payload
363
            );
364
        }};
365
    }
366
367
    #[test]
368
1
    fn encode_data() {
369
501
        for _ in 0..500 {
370
500
            check_encode_redecodes!(super::DecodedYamuxHeader::Data {
371
500
                syn: rand::random(),
372
500
                ack: rand::random(),
373
500
                fin: rand::random(),
374
500
                rst: rand::random(),
375
500
                stream_id: rand::random(),
376
500
                length: rand::random()
377
500
            });
378
        }
379
1
    }
380
381
    #[test]
382
1
    fn encode_window() {
383
501
        for _ in 0..500 {
384
500
            check_encode_redecodes!(super::DecodedYamuxHeader::Window {
385
500
                syn: rand::random(),
386
500
                ack: rand::random(),
387
500
                fin: rand::random(),
388
500
                rst: rand::random(),
389
500
                stream_id: rand::random(),
390
500
                length: rand::random()
391
500
            });
392
        }
393
1
    }
394
395
    #[test]
396
1
    fn encode_ping() {
397
1
        check_encode_redecodes!(super::DecodedYamuxHeader::PingRequest {
398
1
            opaque_value: rand::random(),
399
1
        });
400
401
1
        check_encode_redecodes!(super::DecodedYamuxHeader::PingResponse {
402
1
            opaque_value: rand::random(),
403
1
        });
404
1
    }
405
406
    #[test]
407
1
    fn encode_goaway() {
408
1
        check_encode_redecodes!(super::DecodedYamuxHeader::GoAway {
409
1
            error_code: super::GoAwayErrorCode::NormalTermination,
410
1
        });
411
412
1
        check_encode_redecodes!(super::DecodedYamuxHeader::GoAway {
413
1
            error_code: super::GoAwayErrorCode::ProtocolError,
414
1
        });
415
416
1
        check_encode_redecodes!(super::DecodedYamuxHeader::GoAway {
417
1
            error_code: super::GoAwayErrorCode::InternalError,
418
1
        });
419
1
    }
420
}