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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use byteorder::{NetworkEndian, ReadBytesExt, WriteBytesExt};
use num_traits::FromPrimitive;
use std::io::{Cursor, Read, Write};
mod errors;
mod message_class;
mod message_method;
use crate::definitions::{StunTransactionId, STUN_MAGIC_COOKIE_U32};
use crate::utils::generate_transaction_id;
pub use errors::{HeaderDecodeError, HeaderEncodeError};
pub use message_class::StunMessageClass;
pub use message_method::StunMessageMethod;
#[derive(Debug, Copy, Clone)]
pub struct StunHeader {
pub message_class: StunMessageClass,
pub message_method: StunMessageMethod,
pub transaction_id: StunTransactionId,
pub message_len: u16,
}
impl StunHeader {
pub(crate) fn new(
message_method: StunMessageMethod,
message_class: StunMessageClass,
transaction_id: Option<StunTransactionId>,
) -> Self {
let transaction_id = match transaction_id {
Some(id) => id,
None => generate_transaction_id(),
};
Self {
message_method,
message_class,
transaction_id,
message_len: 0,
}
}
pub(crate) fn decode(cursor: &mut Cursor<&[u8]>) -> Result<Self, HeaderDecodeError> {
let stun_type_field = cursor.read_u16::<NetworkEndian>()?;
let msg_len = cursor.read_u16::<NetworkEndian>()?;
let magic_cookie = cursor.read_u32::<NetworkEndian>()?;
if magic_cookie != STUN_MAGIC_COOKIE_U32 {
return Err(HeaderDecodeError::MagicCookieMismatch());
}
let mut transaction_id = [0; 12];
cursor.read_exact(&mut transaction_id)?;
let stun_class = stun_type_field & 0b0000_0001_0001_0000;
let stun_method = stun_type_field & 0b1111_1110_1110_1111;
let message_method: StunMessageMethod = FromPrimitive::from_u16(stun_method)
.ok_or(HeaderDecodeError::UnrecognizedMessageMethod(stun_method))?;
let message_class: StunMessageClass = FromPrimitive::from_u16(stun_class)
.ok_or(HeaderDecodeError::UnrecognizedMessageClass(stun_class))?;
Ok(Self {
message_method,
message_class,
message_len: msg_len,
transaction_id,
})
}
pub(crate) fn encode(&self) -> Result<Vec<u8>, HeaderEncodeError> {
let bytes = Vec::new();
let mut cursor = Cursor::new(bytes);
let stun_type_field = self.message_class as u16 | self.message_method as u16;
cursor.write_u16::<NetworkEndian>(stun_type_field)?;
cursor.write_u16::<NetworkEndian>(self.message_len)?;
cursor.write_u32::<NetworkEndian>(STUN_MAGIC_COOKIE_U32)?;
cursor.write_all(&self.transaction_id)?;
Ok(cursor.get_ref().to_vec())
}
}