-
-
Notifications
You must be signed in to change notification settings - Fork 5
/
initiation_message.rs
96 lines (85 loc) · 2.73 KB
/
initiation_message.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use crate::parser::bmp::error::ParserBmpError;
use crate::parser::ReadUtils;
use bytes::{Buf, Bytes};
use num_enum::{IntoPrimitive, TryFromPrimitive};
use std::convert::TryFrom;
#[derive(Debug, Clone, PartialEq)]
pub struct InitiationMessage {
pub tlvs: Vec<InitiationTlv>,
}
#[derive(Debug, PartialEq, Clone)]
pub struct InitiationTlv {
pub info_type: InitiationTlvType,
pub info_len: u16,
pub info: String,
}
///Type-Length-Value Type
///
/// https://www.iana.org/assignments/bmp-parameters/bmp-parameters.xhtml#initiation-peer-up-tlvs
#[derive(Debug, TryFromPrimitive, IntoPrimitive, PartialEq, Clone, Copy)]
#[repr(u16)]
pub enum InitiationTlvType {
String = 0,
SysDescr = 1,
SysName = 2,
VrTableName = 3,
AdminLabel = 4,
}
/// Parse BMP initiation message
///
/// <https://www.rfc-editor.org/rfc/rfc7854#section-4.3>
pub fn parse_initiation_message(data: &mut Bytes) -> Result<InitiationMessage, ParserBmpError> {
let mut tlvs = vec![];
while data.remaining() > 4 {
let info_type: InitiationTlvType = InitiationTlvType::try_from(data.get_u16())?;
let info_len = data.get_u16();
if data.remaining() < info_len as usize {
// not enough bytes to read
break;
}
let info = data.read_n_bytes_to_string(info_len as usize)?;
tlvs.push(InitiationTlv {
info_type,
info_len,
info,
});
}
Ok(InitiationMessage { tlvs })
}
#[cfg(test)]
mod tests {
use super::*;
use bytes::{BufMut, BytesMut};
#[test]
fn test_parse_initiation_message() {
let mut buffer = BytesMut::new();
buffer.put_u16(1); // InitiationTlvType::SysDescr
buffer.put_u16(5); // Length of following info
buffer.put_slice(b"Test1"); // Info
let mut bytes = buffer.freeze();
match parse_initiation_message(&mut bytes) {
Ok(initiation_message) => {
for tlv in initiation_message.tlvs {
assert_eq!(tlv.info_type, InitiationTlvType::SysDescr);
assert_eq!(tlv.info_len, 5);
assert_eq!(tlv.info, "Test1".to_string());
}
}
Err(_) => panic!("Failed to parse initiation message"),
}
}
#[test]
fn test_debug() {
let initiation_message = InitiationMessage {
tlvs: vec![InitiationTlv {
info_type: InitiationTlvType::SysDescr,
info_len: 5,
info: "Test1".to_string(),
}],
};
assert_eq!(
format!("{:?}", initiation_message),
"InitiationMessage { tlvs: [InitiationTlv { info_type: SysDescr, info_len: 5, info: \"Test1\" }] }"
);
}
}