stun_types/attribute/
realm.rs1use alloc::borrow::ToOwned;
10use alloc::string::{String, ToString};
11use core::convert::TryFrom;
12
13use crate::message::{StunParseError, StunWriteError};
14
15use super::{
16 Attribute, AttributeExt, AttributeFromRaw, AttributeStaticType, AttributeType, AttributeWrite,
17 AttributeWriteExt, RawAttribute,
18};
19
20#[derive(Debug, Clone, PartialEq, Eq)]
22pub struct Realm {
23 realm: String,
24}
25
26impl AttributeStaticType for Realm {
27 const TYPE: AttributeType = AttributeType(0x0014);
28}
29
30impl Attribute for Realm {
31 fn get_type(&self) -> AttributeType {
32 Self::TYPE
33 }
34
35 fn length(&self) -> u16 {
36 self.realm.len() as u16
37 }
38}
39
40impl AttributeWrite for Realm {
41 fn to_raw(&self) -> RawAttribute<'_> {
42 RawAttribute::new(Realm::TYPE, self.realm.as_bytes())
43 }
44 fn write_into_unchecked(&self, dest: &mut [u8]) {
45 let len = self.padded_len();
46 self.write_header_unchecked(dest);
47 let offset = 4 + self.realm.len();
48 dest[4..offset].copy_from_slice(self.realm.as_bytes());
49 if len > offset {
50 dest[offset..len].fill(0);
51 }
52 }
53}
54
55impl AttributeFromRaw<'_> for Realm {
56 fn from_raw_ref(raw: &RawAttribute) -> Result<Self, StunParseError>
57 where
58 Self: Sized,
59 {
60 Self::try_from(raw)
61 }
62}
63
64impl TryFrom<&RawAttribute<'_>> for Realm {
65 type Error = StunParseError;
66
67 fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
68 raw.check_type_and_len(Self::TYPE, ..=763)?;
69 Ok(Self {
70 realm: core::str::from_utf8(&raw.value)
71 .map_err(|_| StunParseError::InvalidAttributeData)?
72 .to_owned(),
73 })
74 }
75}
76
77impl Realm {
78 pub fn new(realm: &str) -> Result<Self, StunWriteError> {
88 if realm.len() > 763 {
89 return Err(StunWriteError::TooLarge {
90 expected: 763,
91 actual: realm.len(),
92 });
93 }
94 Ok(Self {
95 realm: realm.to_string(),
96 })
97 }
98
99 pub fn realm(&self) -> &str {
109 &self.realm
110 }
111}
112
113impl core::fmt::Display for Realm {
114 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
115 write!(f, "{}: {}", Self::TYPE, self.realm)
116 }
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122 use alloc::vec;
123 use alloc::vec::Vec;
124 use byteorder::{BigEndian, ByteOrder};
125 use tracing::trace;
126
127 #[test]
128 fn realm() {
129 let _log = crate::tests::test_init_log();
130 let attr = Realm::new("realm").unwrap();
131 trace!("{attr}");
132 assert_eq!(attr.realm(), "realm");
133 assert_eq!(attr.length() as usize, "realm".len());
134 }
135
136 #[test]
137 fn realm_raw() {
138 let _log = crate::tests::test_init_log();
139 let attr = Realm::new("realm").unwrap();
140 let raw = RawAttribute::from(&attr);
141 trace!("{raw}");
142 assert_eq!(raw.get_type(), Realm::TYPE);
143 let mapped2 = Realm::try_from(&raw).unwrap();
144 assert_eq!(mapped2.realm(), "realm");
145 }
146
147 #[test]
148 fn realm_raw_wrong_type() {
149 let _log = crate::tests::test_init_log();
150 let attr = Realm::new("realm").unwrap();
151 let raw = RawAttribute::from(&attr);
152
153 let mut data: Vec<_> = raw.into();
155 BigEndian::write_u16(&mut data[0..2], 0);
156 assert!(matches!(
157 Realm::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
158 Err(StunParseError::WrongAttributeImplementation)
159 ));
160 }
161
162 #[test]
163 fn realm_write_into() {
164 let _log = crate::tests::test_init_log();
165 let attr = Realm::new("realm").unwrap();
166 let raw = RawAttribute::from(&attr);
167
168 let mut dest = vec![0; raw.padded_len()];
169 attr.write_into(&mut dest).unwrap();
170 let raw = RawAttribute::from_bytes(&dest).unwrap();
171 let realm = Realm::try_from(&raw).unwrap();
172 assert_eq!(realm.realm(), "realm");
173 }
174
175 #[test]
176 #[should_panic(expected = "out of range")]
177 fn realm_write_into_unchecked() {
178 let _log = crate::tests::test_init_log();
179 let attr = Realm::new("realm").unwrap();
180 let raw = RawAttribute::from(&attr);
181
182 let mut dest = vec![0; raw.padded_len() - 1];
183 attr.write_into_unchecked(&mut dest);
184 }
185
186 #[test]
187 fn realm_not_utf8() {
188 let _log = crate::tests::test_init_log();
189 let attr = Realm::new("realm").unwrap();
190 let raw = RawAttribute::from(&attr);
191 let mut data = raw.to_bytes();
192 data[6] = 0x88;
193 assert!(matches!(
194 Realm::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
195 Err(StunParseError::InvalidAttributeData)
196 ));
197 }
198
199 #[test]
200 fn realme_new_too_large() {
201 let _log = crate::tests::test_init_log();
202 let mut large = String::new();
203 for _i in 0..95 {
204 large.push_str("abcdefgh");
205 }
206 large.push_str("abcd");
207 assert!(matches!(
208 Realm::new(&large),
209 Err(StunWriteError::TooLarge {
210 expected: 763,
211 actual: 764
212 })
213 ));
214 }
215}