1use byteorder::{NetworkEndian, ReadBytesExt, WriteBytesExt};
2use num_traits::FromPrimitive;
3use std::io::{Cursor, Read, Write};
4
5mod errors;
6mod message_class;
7mod message_method;
8
9use crate::definitions::{StunTransactionId, STUN_MAGIC_COOKIE_U32};
10use crate::utils::generate_transaction_id;
11pub use errors::{HeaderDecodeError, HeaderEncodeError};
12pub use message_class::StunMessageClass;
13pub use message_method::StunMessageMethod;
14
15#[derive(Debug, Copy, Clone)]
16pub struct StunHeader {
36 pub message_class: StunMessageClass,
38 pub message_method: StunMessageMethod,
40 pub transaction_id: StunTransactionId,
42 pub message_len: u16,
45}
46
47impl StunHeader {
48 pub(crate) fn new(
53 message_method: StunMessageMethod,
54 message_class: StunMessageClass,
55 transaction_id: Option<StunTransactionId>,
56 ) -> Self {
57 let transaction_id = match transaction_id {
59 Some(id) => id,
60 None => generate_transaction_id(),
61 };
62
63 Self {
64 message_method,
65 message_class,
66 transaction_id,
67 message_len: 0, }
69 }
70
71 pub(crate) fn decode(cursor: &mut Cursor<&[u8]>) -> Result<Self, HeaderDecodeError> {
73 let stun_type_field = cursor.read_u16::<NetworkEndian>()?;
74 let msg_len = cursor.read_u16::<NetworkEndian>()?;
75 let magic_cookie = cursor.read_u32::<NetworkEndian>()?;
76
77 if magic_cookie != STUN_MAGIC_COOKIE_U32 {
78 return Err(HeaderDecodeError::MagicCookieMismatch());
79 }
80
81 let mut transaction_id = [0; 12];
82 cursor.read_exact(&mut transaction_id)?;
83
84 let stun_class = stun_type_field & 0b0000_0001_0001_0000;
85 let stun_method = stun_type_field & 0b1111_1110_1110_1111;
86
87 let message_method: StunMessageMethod = FromPrimitive::from_u16(stun_method)
88 .ok_or(HeaderDecodeError::UnrecognizedMessageMethod(stun_method))?;
89 let message_class: StunMessageClass = FromPrimitive::from_u16(stun_class)
90 .ok_or(HeaderDecodeError::UnrecognizedMessageClass(stun_class))?;
91
92 Ok(Self {
93 message_method,
94 message_class,
95 message_len: msg_len,
96 transaction_id,
97 })
98 }
99
100 pub(crate) fn encode(&self) -> Result<Vec<u8>, HeaderEncodeError> {
102 let bytes = Vec::new();
103 let mut cursor = Cursor::new(bytes);
104
105 let stun_type_field = self.message_class as u16 | self.message_method as u16;
106
107 cursor.write_u16::<NetworkEndian>(stun_type_field)?;
108 cursor.write_u16::<NetworkEndian>(self.message_len)?;
109 cursor.write_u32::<NetworkEndian>(STUN_MAGIC_COOKIE_U32)?;
110 cursor.write_all(&self.transaction_id)?;
111
112 Ok(cursor.get_ref().to_vec())
113 }
114}