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::Vec;
123 use byteorder::{BigEndian, ByteOrder};
124 use tracing::trace;
125
126 #[test]
127 fn realm() {
128 let _log = crate::tests::test_init_log();
129 let attr = Realm::new("realm").unwrap();
130 trace!("{attr}");
131 assert_eq!(attr.realm(), "realm");
132 assert_eq!(attr.length() as usize, "realm".len());
133 let raw = RawAttribute::from(&attr);
134 trace!("{raw}");
135 assert_eq!(raw.get_type(), Realm::TYPE);
136 let mapped2 = Realm::try_from(&raw).unwrap();
137 assert_eq!(mapped2.realm(), "realm");
138 let mut data: Vec<_> = raw.into();
140 BigEndian::write_u16(&mut data[0..2], 0);
141 assert!(matches!(
142 Realm::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
143 Err(StunParseError::WrongAttributeImplementation)
144 ));
145 }
146
147 #[test]
148 fn realm_not_utf8() {
149 let _log = crate::tests::test_init_log();
150 let attr = Realm::new("realm").unwrap();
151 let raw = RawAttribute::from(&attr);
152 let mut data = raw.to_bytes();
153 data[6] = 0x88;
154 assert!(matches!(
155 Realm::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
156 Err(StunParseError::InvalidAttributeData)
157 ));
158 }
159
160 #[test]
161 fn realme_new_too_large() {
162 let _log = crate::tests::test_init_log();
163 let mut large = String::new();
164 for _i in 0..95 {
165 large.push_str("abcdefgh");
166 }
167 large.push_str("abcd");
168 assert!(matches!(
169 Realm::new(&large),
170 Err(StunWriteError::TooLarge {
171 expected: 763,
172 actual: 764
173 })
174 ));
175 }
176}