turn_types/attribute/
icmp.rs1use byteorder::{BigEndian, ByteOrder};
10use stun_types::{attribute::*, message::StunParseError};
11
12#[derive(Debug, Clone)]
18pub struct Icmp {
19 typ: u8,
20 code: u8,
21 data: u32,
22}
23
24impl AttributeStaticType for Icmp {
25 const TYPE: AttributeType = AttributeType::new(0x8004);
26}
27
28impl Attribute for Icmp {
29 fn get_type(&self) -> AttributeType {
30 Self::TYPE
31 }
32
33 fn length(&self) -> u16 {
34 8
35 }
36}
37
38impl AttributeWrite for Icmp {
39 fn to_raw(&self) -> RawAttribute<'_> {
40 let mut data = [0; 8];
41 data[2] = self.typ;
42 data[3] = self.code;
43 BigEndian::write_u32(&mut data[4..8], self.data);
44 RawAttribute::new(Self::TYPE, &data).into_owned()
45 }
46 fn write_into_unchecked(&self, dest: &mut [u8]) {
47 self.write_header_unchecked(dest);
48 dest[6] = self.typ;
49 dest[7] = self.code;
50 BigEndian::write_u32(&mut dest[8..12], self.data);
51 }
52}
53
54impl AttributeFromRaw<'_> for Icmp {
55 fn from_raw_ref(raw: &RawAttribute) -> Result<Self, StunParseError>
56 where
57 Self: Sized,
58 {
59 Self::try_from(raw)
60 }
61}
62
63impl TryFrom<&RawAttribute<'_>> for Icmp {
64 type Error = StunParseError;
65 fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
66 raw.check_type_and_len(Self::TYPE, 8..=8)?;
67 let typ = raw.value[2];
68 let code = raw.value[3];
69 let data = BigEndian::read_u32(&raw.value[4..8]);
70 Ok(Self { typ, code, data })
71 }
72}
73
74impl Icmp {
75 pub fn new(typ: u8, code: u8, data: u32) -> Self {
87 Self { typ, code, data }
88 }
89
90 pub fn icmp_type(&self) -> u8 {
92 self.typ
93 }
94
95 pub fn code(&self) -> u8 {
97 self.code
98 }
99
100 pub fn data(&self) -> u32 {
102 self.data
103 }
104}
105
106impl core::fmt::Display for Icmp {
107 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
108 write!(
109 f,
110 "{}: type:{}, code:{}, data:{}",
111 self.get_type(),
112 self.typ,
113 self.code,
114 self.data
115 )
116 }
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122 use alloc::vec::Vec;
123 use std::println;
124
125 #[test]
126 fn icmp() {
127 let _log = crate::tests::test_init_log();
128 let mapped = Icmp::new(2, 4, 8);
129 assert_eq!(mapped.get_type(), Icmp::TYPE);
130 assert_eq!(mapped.icmp_type(), 2);
131 assert_eq!(mapped.code(), 4);
132 assert_eq!(mapped.data(), 8);
133 let raw: RawAttribute = mapped.to_raw();
134 println!("{}", raw);
135 assert_eq!(raw.get_type(), Icmp::TYPE);
136 let mapped2 = Icmp::try_from(&raw).unwrap();
137 assert_eq!(mapped2.get_type(), Icmp::TYPE);
138 assert_eq!(mapped2.icmp_type(), 2);
139 assert_eq!(mapped2.code(), 4);
140 assert_eq!(mapped2.data(), 8);
141 let mut data: Vec<_> = raw.clone().into();
143 let len = data.len();
144 BigEndian::write_u16(&mut data[2..4], len as u16 - 4 - 1);
145 println!(
146 "{:?}",
147 Icmp::try_from(&RawAttribute::from_bytes(data[..len - 1].as_ref()).unwrap())
148 );
149 assert!(matches!(
150 Icmp::try_from(&RawAttribute::from_bytes(data[..len - 1].as_ref()).unwrap()),
151 Err(StunParseError::Truncated {
152 expected: _,
153 actual: _,
154 })
155 ));
156 let mut data: Vec<_> = raw.clone().into();
158 BigEndian::write_u16(&mut data[0..2], 0);
159 assert!(matches!(
160 Icmp::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
161 Err(StunParseError::WrongAttributeImplementation)
162 ));
163 }
164}