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