1use std::net::SocketAddr;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8#[non_exhaustive]
9pub struct StunMessage {
10 pub class: StunClass,
12 pub method: u16,
15 pub transaction_id: [u8; 12],
17 pub mapped_address: Option<SocketAddr>,
21 pub username: Option<String>,
23 pub software: Option<String>,
25}
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
29#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
30#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
31#[non_exhaustive]
32pub enum StunClass {
33 Request,
34 Indication,
35 SuccessResponse,
36 ErrorResponse,
37}
38
39impl StunClass {
40 pub fn from_type_bits(type_word: u16) -> Self {
43 let c0 = (type_word >> 4) & 0x01;
45 let c1 = (type_word >> 8) & 0x01;
46 match (c1, c0) {
47 (0, 0) => Self::Request,
48 (0, 1) => Self::Indication,
49 (1, 0) => Self::SuccessResponse,
50 (1, 1) => Self::ErrorResponse,
51 _ => unreachable!(),
52 }
53 }
54
55 pub fn as_str(&self) -> &'static str {
57 match self {
58 Self::Request => "request",
59 Self::Indication => "indication",
60 Self::SuccessResponse => "success_response",
61 Self::ErrorResponse => "error_response",
62 }
63 }
64}
65
66pub(crate) fn extract_method(type_word: u16) -> u16 {
68 let m0 = type_word & 0x000f;
71 let m4 = (type_word >> 5) & 0x0007; let m7 = (type_word >> 9) & 0x001f; (m7 << 7) | (m4 << 4) | m0
74}