stun_types/attribute/
realm.rs1use std::convert::TryFrom;
10
11use crate::message::{StunParseError, StunWriteError};
12
13use super::{
14 Attribute, AttributeExt, AttributeStaticType, AttributeType, AttributeWrite, AttributeWriteExt,
15 RawAttribute,
16};
17
18#[derive(Debug, Clone, PartialEq, Eq)]
20pub struct Realm {
21 realm: String,
22}
23
24impl AttributeStaticType for Realm {
25 const TYPE: AttributeType = AttributeType(0x0014);
26}
27impl Attribute for Realm {
28 fn get_type(&self) -> AttributeType {
29 Self::TYPE
30 }
31
32 fn length(&self) -> u16 {
33 self.realm.len() as u16
34 }
35}
36impl AttributeWrite for Realm {
37 fn to_raw(&self) -> RawAttribute {
38 RawAttribute::new(Realm::TYPE, self.realm.as_bytes())
39 }
40 fn write_into_unchecked(&self, dest: &mut [u8]) {
41 let len = self.padded_len();
42 self.write_header_unchecked(dest);
43 let offset = 4 + self.realm.len();
44 dest[4..offset].copy_from_slice(self.realm.as_bytes());
45 if len > offset {
46 dest[offset..len].fill(0);
47 }
48 }
49}
50impl<'a> TryFrom<&RawAttribute<'a>> for Realm {
51 type Error = StunParseError;
52
53 fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
54 raw.check_type_and_len(Self::TYPE, ..=763)?;
55 Ok(Self {
56 realm: std::str::from_utf8(&raw.value)
57 .map_err(|_| StunParseError::InvalidAttributeData)?
58 .to_owned(),
59 })
60 }
61}
62impl Realm {
63 pub fn new(realm: &str) -> Result<Self, StunWriteError> {
73 if realm.len() > 763 {
74 return Err(StunWriteError::TooLarge {
75 expected: 763,
76 actual: realm.len(),
77 });
78 }
79 Ok(Self {
80 realm: realm.to_string(),
81 })
82 }
83
84 pub fn realm(&self) -> &str {
94 &self.realm
95 }
96}
97
98impl std::fmt::Display for Realm {
99 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100 write!(f, "{}: {}", Self::TYPE, self.realm)
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107 use byteorder::{BigEndian, ByteOrder};
108 use tracing::trace;
109
110 #[test]
111 fn realm() {
112 let _log = crate::tests::test_init_log();
113 let attr = Realm::new("realm").unwrap();
114 trace!("{attr}");
115 assert_eq!(attr.realm(), "realm");
116 assert_eq!(attr.length() as usize, "realm".len());
117 let raw = RawAttribute::from(&attr);
118 trace!("{raw}");
119 assert_eq!(raw.get_type(), Realm::TYPE);
120 let mapped2 = Realm::try_from(&raw).unwrap();
121 assert_eq!(mapped2.realm(), "realm");
122 let mut data: Vec<_> = raw.into();
124 BigEndian::write_u16(&mut data[0..2], 0);
125 assert!(matches!(
126 Realm::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
127 Err(StunParseError::WrongAttributeImplementation)
128 ));
129 }
130
131 #[test]
132 fn realm_not_utf8() {
133 let _log = crate::tests::test_init_log();
134 let attr = Realm::new("realm").unwrap();
135 let raw = RawAttribute::from(&attr);
136 let mut data = raw.to_bytes();
137 data[6] = 0x88;
138 assert!(matches!(
139 Realm::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
140 Err(StunParseError::InvalidAttributeData)
141 ));
142 }
143
144 #[test]
145 fn realme_new_too_large() {
146 let _log = crate::tests::test_init_log();
147 let mut large = String::new();
148 for _i in 0..95 {
149 large.push_str("abcdefgh");
150 }
151 large.push_str("abcd");
152 assert!(matches!(
153 Realm::new(&large),
154 Err(StunWriteError::TooLarge {
155 expected: 763,
156 actual: 764
157 })
158 ));
159 }
160}