stun_types/attribute/
realm.rs1use std::convert::TryFrom;
10
11use crate::message::{StunParseError, StunWriteError};
12
13use super::{
14 Attribute, AttributeExt, AttributeFromRaw, AttributeStaticType, AttributeType, AttributeWrite,
15 AttributeWriteExt, 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}
27
28impl Attribute for Realm {
29 fn get_type(&self) -> AttributeType {
30 Self::TYPE
31 }
32
33 fn length(&self) -> u16 {
34 self.realm.len() as u16
35 }
36}
37
38impl AttributeWrite for Realm {
39 fn to_raw(&self) -> RawAttribute<'_> {
40 RawAttribute::new(Realm::TYPE, self.realm.as_bytes())
41 }
42 fn write_into_unchecked(&self, dest: &mut [u8]) {
43 let len = self.padded_len();
44 self.write_header_unchecked(dest);
45 let offset = 4 + self.realm.len();
46 dest[4..offset].copy_from_slice(self.realm.as_bytes());
47 if len > offset {
48 dest[offset..len].fill(0);
49 }
50 }
51}
52
53impl AttributeFromRaw<'_> for Realm {
54 fn from_raw_ref(raw: &RawAttribute) -> Result<Self, StunParseError>
55 where
56 Self: Sized,
57 {
58 Self::try_from(raw)
59 }
60}
61
62impl TryFrom<&RawAttribute<'_>> for Realm {
63 type Error = StunParseError;
64
65 fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
66 raw.check_type_and_len(Self::TYPE, ..=763)?;
67 Ok(Self {
68 realm: std::str::from_utf8(&raw.value)
69 .map_err(|_| StunParseError::InvalidAttributeData)?
70 .to_owned(),
71 })
72 }
73}
74
75impl Realm {
76 pub fn new(realm: &str) -> Result<Self, StunWriteError> {
86 if realm.len() > 763 {
87 return Err(StunWriteError::TooLarge {
88 expected: 763,
89 actual: realm.len(),
90 });
91 }
92 Ok(Self {
93 realm: realm.to_string(),
94 })
95 }
96
97 pub fn realm(&self) -> &str {
107 &self.realm
108 }
109}
110
111impl std::fmt::Display for Realm {
112 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113 write!(f, "{}: {}", Self::TYPE, self.realm)
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use super::*;
120 use byteorder::{BigEndian, ByteOrder};
121 use tracing::trace;
122
123 #[test]
124 fn realm() {
125 let _log = crate::tests::test_init_log();
126 let attr = Realm::new("realm").unwrap();
127 trace!("{attr}");
128 assert_eq!(attr.realm(), "realm");
129 assert_eq!(attr.length() as usize, "realm".len());
130 let raw = RawAttribute::from(&attr);
131 trace!("{raw}");
132 assert_eq!(raw.get_type(), Realm::TYPE);
133 let mapped2 = Realm::try_from(&raw).unwrap();
134 assert_eq!(mapped2.realm(), "realm");
135 let mut data: Vec<_> = raw.into();
137 BigEndian::write_u16(&mut data[0..2], 0);
138 assert!(matches!(
139 Realm::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
140 Err(StunParseError::WrongAttributeImplementation)
141 ));
142 }
143
144 #[test]
145 fn realm_not_utf8() {
146 let _log = crate::tests::test_init_log();
147 let attr = Realm::new("realm").unwrap();
148 let raw = RawAttribute::from(&attr);
149 let mut data = raw.to_bytes();
150 data[6] = 0x88;
151 assert!(matches!(
152 Realm::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
153 Err(StunParseError::InvalidAttributeData)
154 ));
155 }
156
157 #[test]
158 fn realme_new_too_large() {
159 let _log = crate::tests::test_init_log();
160 let mut large = String::new();
161 for _i in 0..95 {
162 large.push_str("abcdefgh");
163 }
164 large.push_str("abcd");
165 assert!(matches!(
166 Realm::new(&large),
167 Err(StunWriteError::TooLarge {
168 expected: 763,
169 actual: 764
170 })
171 ));
172 }
173}