Skip to main content

stun_types/attribute/
mod.rs

1// Copyright (C) 2020 Matthew Waters <matthew@centricular.com>
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8//
9// SPDX-License-Identifier: MIT OR Apache-2.0
10
11//! STUN Attributes
12//!
13//! Provides implementations for generating, parsing and manipulating STUN attributes as specified
14//! in one of [RFC8489], [RFC5389], or [RFC3489].
15//!
16//! There are two levels of attribute implementations:
17//! 1. A generic [`RawAttribute`] which contains the [`AttributeHeader`] (type and length) and the
18//!    byte sequence of data (either borrowed or owned). Parsing a
19//!    [`Message`](crate::message::Message) will only perform zerocopy parsing to this level. Any
20//!    attribute-specific restrictions on the actual contents of the data should be performed by
21//!    concrete attribute implementations.
22//! 2. Concrete implementations based on implementing [`Attribute`], and [`AttributeStaticType`].
23//!    These concrete attribute implementations have much more ergonomic API specific to their
24//!    particular needs. A concrete attribute implementation may have restrictions on what data is
25//!    allowed to be parsed from a [`RawAttribute`] that should return errors when calling
26//!    [`AttributeFromRaw::from_raw_ref`].
27//!
28//! [RFC8489]: https://tools.ietf.org/html/rfc8489
29//! [RFC5389]: https://tools.ietf.org/html/rfc5389
30//! [RFC3489]: https://tools.ietf.org/html/rfc3489
31//!
32//! # Examples
33//!
34//! ### Parse and write an already defined [`Attribute`]
35//!
36//! ```
37//! # use stun_types::prelude::*;
38//! use stun_types::attribute::{RawAttribute, Software};
39//! let software_name = "stun-types";
40//! let software = Software::new(software_name).unwrap();
41//! assert_eq!(software.software(), software_name);
42//!
43//! let attribute_data = [
44//!     0x80, 0x22, 0x00, 0x0a, // Attribute type (0x8022: Software) and length (0x000a)
45//!     0x73, 0x74, 0x75, 0x6E, // s t u n
46//!     0x2D, 0x74, 0x79, 0x70, // - t y p
47//!     0x65, 0x73, 0x00, 0x00  // e s
48//! ];
49//!
50//! let raw = RawAttribute::from(&software);
51//! assert_eq!(raw.to_bytes(), attribute_data);
52//!
53//! // Can also parse data into a typed attribute as needed
54//! let software = Software::from_raw(raw).unwrap();
55//! assert_eq!(software.software(), software_name);
56//! ```
57//!
58//! ### Defining your own [`Attribute`]
59//!
60//! ```
61//! # use stun_types::prelude::*;
62//! use byteorder::{BigEndian, ByteOrder};
63//! use stun_types::attribute::{AttributeType, RawAttribute};
64//! use stun_types::message::StunParseError;
65//! #[derive(Debug)]
66//! struct MyAttribute {
67//!    value: u32,
68//! }
69//! impl AttributeStaticType for MyAttribute {
70//!    const TYPE: AttributeType = AttributeType::new(0x8851);
71//! }
72//! impl Attribute for MyAttribute {
73//!    fn get_type(&self) -> AttributeType {
74//!        Self::TYPE
75//!    }
76//!
77//!    fn length(&self) -> u16 {
78//!        4
79//!    }
80//! }
81//! impl AttributeWrite for MyAttribute {
82//!     fn to_raw(&self) -> RawAttribute<'_> {
83//!         let mut ret = [0; 4];
84//!         BigEndian::write_u32(&mut ret, self.value);
85//!         RawAttribute::new(MyAttribute::TYPE, &ret).into_owned()
86//!     }
87//!     fn write_into_unchecked(&self, dest: &mut [u8]) {
88//!         self.write_header_unchecked(dest);
89//!         BigEndian::write_u32(&mut dest[4..], self.value);
90//!     }
91//! }
92//! impl AttributeFromRaw<'_> for MyAttribute {
93//!     fn from_raw_ref(raw: &RawAttribute) -> Result<Self, StunParseError>
94//!     where
95//!         Self: Sized,
96//!     {
97//!         raw.check_type_and_len(Self::TYPE, 4..=4)?;
98//!         let value = BigEndian::read_u32(&raw.value);
99//!         Ok(Self {
100//!             value,
101//!         })
102//!     }
103//! }
104//!
105//! // Optional: if you want this attribute to be displayed nicely when the corresponding
106//! // `RawAttribute` (based on `AttributeType`) is formatted using `RawAttribute`'s `Display`
107//! // implementation.
108//! impl core::fmt::Display for MyAttribute {
109//!     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
110//!         write!(f, "MyAttribute: {}", self.value)
111//!     }
112//! }
113//! # #[cfg(feature = "std")]
114//! stun_types::attribute_display!(MyAttribute);
115//! # #[cfg(feature = "std")]
116//! MyAttribute::TYPE.add_name("MY-ATTRIBUTE");
117//!
118//! let my_attr = MyAttribute { value: 0x4729 };
119//! let raw = RawAttribute::from(&my_attr);
120//!
121//! let attribute_data = [
122//!     0x88, 0x51, 0x00, 0x04,
123//!     0x00, 0x00, 0x47, 0x29,
124//! ];
125//! assert_eq!(raw.to_bytes(), attribute_data);
126//!
127//! let my_attr = MyAttribute::from_raw(raw).unwrap();
128//! assert_eq!(my_attr.value, 0x4729);
129//! ```
130
131macro_rules! bytewise_xor {
132    ($size:literal, $a:expr, $b:expr, $default:literal) => {{
133        let mut arr = [$default; $size];
134        for (i, item) in arr.iter_mut().enumerate() {
135            *item = $a[i] ^ $b[i];
136        }
137        arr
138    }};
139}
140
141mod address;
142pub use address::{MappedSocketAddr, XorSocketAddr};
143mod alternate;
144pub use alternate::{AlternateDomain, AlternateServer};
145mod error;
146pub use error::{ErrorCode, UnknownAttributes};
147mod integrity;
148pub use integrity::{MessageIntegrity, MessageIntegritySha256};
149mod fingerprint;
150pub use fingerprint::Fingerprint;
151mod nonce;
152pub use nonce::Nonce;
153mod password_algorithm;
154pub use password_algorithm::{PasswordAlgorithm, PasswordAlgorithmValue, PasswordAlgorithms};
155mod realm;
156pub use realm::Realm;
157mod user;
158pub use user::{Userhash, Username};
159mod software;
160pub use software::Software;
161mod xor_addr;
162pub use xor_addr::XorMappedAddress;
163
164use crate::data::Data;
165use crate::message::{StunParseError, StunWriteError};
166use alloc::boxed::Box;
167use alloc::vec::Vec;
168
169use byteorder::{BigEndian, ByteOrder};
170
171#[cfg(feature = "std")]
172use alloc::collections::BTreeMap;
173#[cfg(feature = "std")]
174use std::sync::{Mutex, OnceLock};
175
176/// A closure definition for an externally provided `Display` implementation for a [`RawAttribute`].
177///
178/// Typically, a concrete [`Attribute`] implements `Display` and
179/// [`attribute_display`](crate::attribute_display) can be used
180/// to generate and install this closure.
181///
182/// See the module level documentation for an example.
183pub type AttributeDisplay =
184    fn(&RawAttribute<'_>, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result;
185#[cfg(feature = "std")]
186static ATTRIBUTE_EXTERNAL_DISPLAY_IMPL: OnceLock<Mutex<BTreeMap<AttributeType, AttributeDisplay>>> =
187    OnceLock::new();
188
189/// Adds an externally provided Display implementation for a particular [`AttributeType`].  Any
190/// previous implementation is overidden.
191#[cfg(feature = "std")]
192pub fn add_display_impl(atype: AttributeType, imp: AttributeDisplay) {
193    let mut display_impls = ATTRIBUTE_EXTERNAL_DISPLAY_IMPL
194        .get_or_init(Default::default)
195        .lock()
196        .unwrap();
197    display_impls.insert(atype, imp);
198}
199
200/// Implement an [`AttributeDisplay`] closure for an [`Attribute`] from a [`RawAttribute`] and calls
201/// [`add_display_impl`] with the generated closure.
202///
203/// # Examples
204/// ```
205/// use stun_types::attribute::{AttributeType, Attribute, AttributeStaticType, AttributeFromRaw};
206/// use stun_types::attribute::RawAttribute;
207/// use stun_types::message::StunParseError;
208/// #[derive(Debug)]
209/// struct MyAttribute {}
210/// impl AttributeStaticType for MyAttribute {
211///    const TYPE: AttributeType = AttributeType::new(0x8852);
212/// }
213/// impl Attribute for MyAttribute {
214///    fn get_type(&self) -> AttributeType {
215///        Self::TYPE
216///    }
217///    fn length(&self) -> u16 {
218///        0
219///    }
220/// }
221/// impl AttributeFromRaw<'_> for MyAttribute {
222///     fn from_raw_ref(raw: &RawAttribute) -> Result<Self, StunParseError>
223///     where
224///         Self: Sized,
225///     {
226///         raw.check_type_and_len(Self::TYPE, 0..=0)?;
227///         Ok(Self {})
228///    }
229/// }
230/// // An Attribute would also implement AttributeWrite but that has been omitted for brevity.
231/// impl core::fmt::Display for MyAttribute {
232///     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
233///         write!(f, "MyAttribute")
234///     }
235/// }
236/// # #[cfg(feature = "std")]
237/// # {
238/// stun_types::attribute_display!(MyAttribute);
239/// let attr = RawAttribute::new(MyAttribute::TYPE, &[]);
240/// let display_str = format!("{attr}");
241/// assert_eq!(display_str, "MyAttribute");
242/// # }
243/// ```
244#[macro_export]
245macro_rules! attribute_display {
246    ($typ:ty) => {{
247        let imp = |attr: &$crate::attribute::RawAttribute<'_>,
248                   f: &mut core::fmt::Formatter<'_>|
249         -> core::fmt::Result {
250            if let Ok(attr) = <$typ>::from_raw_ref(attr) {
251                write!(f, "{}", attr)
252            } else {
253                write!(
254                    f,
255                    "{}(Malformed): len: {}, data: {:?})",
256                    attr.get_type(),
257                    attr.header.length(),
258                    attr.value
259                )
260            }
261        };
262
263        $crate::attribute::add_display_impl(<$typ>::TYPE, imp);
264    }};
265}
266
267#[cfg(feature = "std")]
268static ATTRIBUTE_TYPE_NAME_MAP: OnceLock<Mutex<BTreeMap<AttributeType, &'static str>>> =
269    OnceLock::new();
270
271/// The type of an [`Attribute`] in a STUN [`Message`](crate::message::Message)
272#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
273pub struct AttributeType(u16);
274
275impl core::fmt::Display for AttributeType {
276    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
277        write!(f, "{}({:#x}: {})", self.0, self.0, self.name())
278    }
279}
280
281impl AttributeType {
282    /// Add the name for a particular [`AttributeType`] for formatting purposes.
283    #[cfg(feature = "std")]
284    pub fn add_name(self, name: &'static str) {
285        let mut anames = ATTRIBUTE_TYPE_NAME_MAP
286            .get_or_init(Default::default)
287            .lock()
288            .unwrap();
289        anames.insert(self, name);
290    }
291
292    /// Create a new AttributeType from an existing value
293    ///
294    /// Note: the value passed in is not encoded as in a stun message
295    ///
296    /// # Examples
297    /// ```
298    /// # use stun_types::attribute::AttributeType;
299    /// assert_eq!(AttributeType::new(0x123).value(), 0x123);
300    /// ```
301    pub const fn new(val: u16) -> Self {
302        Self(val)
303    }
304
305    /// Return the integer value of this AttributeType
306    ///
307    /// Note: the value returned is not encoded as in a stun message
308    ///
309    /// # Examples
310    /// ```
311    /// # use stun_types::attribute::AttributeType;
312    /// assert_eq!(AttributeType::new(0x123).value(), 0x123);
313    /// ```
314    pub fn value(&self) -> u16 {
315        self.0
316    }
317
318    /// Returns a human readable name of this `AttributeType` or "unknown"
319    ///
320    /// # Examples
321    /// ```
322    /// # use stun_types::attribute::*;
323    /// assert_eq!(XorMappedAddress::TYPE.name(), "XOR-MAPPED-ADDRESS");
324    /// ```
325    pub fn name(self) -> &'static str {
326        match self {
327            AttributeType(0x0001) => "MAPPED-ADDRESS",
328            Username::TYPE => "USERNAME",
329            MessageIntegrity::TYPE => "MESSAGE-INTEGRITY",
330            ErrorCode::TYPE => "ERROR-CODE",
331            UnknownAttributes::TYPE => "UNKNOWN-ATTRIBUTES",
332            Realm::TYPE => "REALM",
333            Nonce::TYPE => "NONCE",
334            MessageIntegritySha256::TYPE => "MESSAGE-INTEGRITY-SHA256",
335            PasswordAlgorithm::TYPE => "PASSWORD-ALGORITHM",
336            Userhash::TYPE => "USERHASH",
337            XorMappedAddress::TYPE => "XOR-MAPPED-ADDRESS",
338            PasswordAlgorithms::TYPE => "PASSWORD_ALGORITHMS",
339            AlternateDomain::TYPE => "ALTERNATE-DOMAIN",
340            Software::TYPE => "SOFTWARE",
341            AlternateServer::TYPE => "ALTERNATE-SERVER",
342            Fingerprint::TYPE => "FINGERPRINT",
343            _ => {
344                #[cfg(feature = "std")]
345                {
346                    let anames = ATTRIBUTE_TYPE_NAME_MAP
347                        .get_or_init(Default::default)
348                        .lock()
349                        .unwrap();
350                    if let Some(name) = anames.get(&self) {
351                        return name;
352                    }
353                }
354                "unknown"
355            }
356        }
357    }
358
359    /// Check if comprehension is required for an `AttributeType`.  All attribute
360    /// values < 0x8000 require comprehension.
361    ///
362    /// # Examples
363    ///
364    /// ```
365    /// # use stun_types::attribute::AttributeType;
366    /// assert_eq!(AttributeType::new(0x0).comprehension_required(), true);
367    /// assert_eq!(AttributeType::new(0x8000).comprehension_required(), false);
368    /// ```
369    pub fn comprehension_required(self) -> bool {
370        self.0 < 0x8000
371    }
372}
373impl From<u16> for AttributeType {
374    fn from(f: u16) -> Self {
375        Self::new(f)
376    }
377}
378impl From<AttributeType> for u16 {
379    fn from(f: AttributeType) -> Self {
380        f.0
381    }
382}
383
384/// Structure for holding the header of a STUN attribute.  Contains the type and the length
385#[derive(Debug, Copy, Clone, PartialEq, Eq)]
386pub struct AttributeHeader {
387    atype: AttributeType,
388    length: u16,
389}
390
391impl AttributeHeader {
392    fn parse(data: &[u8]) -> Result<Self, StunParseError> {
393        if data.len() < 4 {
394            return Err(StunParseError::Truncated {
395                expected: 4,
396                actual: data.len(),
397            });
398        }
399        let ret = Self {
400            atype: BigEndian::read_u16(&data[0..2]).into(),
401            length: BigEndian::read_u16(&data[2..4]),
402        };
403        Ok(ret)
404    }
405
406    fn to_bytes(self) -> [u8; 4] {
407        let mut ret = [0; 4];
408        self.write_into(&mut ret);
409        ret
410    }
411
412    fn write_into(&self, ret: &mut [u8]) {
413        BigEndian::write_u16(&mut ret[0..2], self.atype.into());
414        BigEndian::write_u16(&mut ret[2..4], self.length);
415    }
416
417    /// Returns the type of the attribute
418    pub fn get_type(&self) -> AttributeType {
419        self.atype
420    }
421
422    /// Returns the length of the attribute
423    pub fn length(&self) -> u16 {
424        self.length
425    }
426}
427impl From<AttributeHeader> for [u8; 4] {
428    fn from(f: AttributeHeader) -> Self {
429        f.to_bytes()
430    }
431}
432impl TryFrom<&[u8]> for AttributeHeader {
433    type Error = StunParseError;
434
435    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
436        AttributeHeader::parse(value)
437    }
438}
439
440/// A static type for an [`Attribute`]
441pub trait AttributeStaticType {
442    /// The [`AttributeType`]
443    const TYPE: AttributeType;
444}
445
446/// A STUN attribute for use in [`Message`](crate::message::Message)s
447pub trait Attribute: core::fmt::Debug + core::marker::Sync + core::marker::Send {
448    /// Retrieve the type of an `Attribute`.
449    fn get_type(&self) -> AttributeType;
450
451    /// Retrieve the length of an `Attribute`.  This is not the padded length as stored in a
452    /// `Message` and does not include the size of the attribute header.
453    fn length(&self) -> u16;
454}
455
456/// A trait for converting from a [`RawAttribute`] to a concrete [`Attribute`].
457pub trait AttributeFromRaw<'a>: Attribute {
458    /// Produce an `Attribute` from a `RawAttribute`
459    fn from_raw_ref(raw: &RawAttribute) -> Result<Self, StunParseError>
460    where
461        Self: Sized;
462
463    /// Produce an `Attribute` from a `RawAttribute`
464    fn from_raw(raw: RawAttribute<'a>) -> Result<Self, StunParseError>
465    where
466        Self: Sized,
467    {
468        Self::from_raw_ref(&raw)
469    }
470}
471
472/// Computes the padded length of an attribute value to a multiple of 4 bytes.
473pub fn pad_attribute_len(len: usize) -> usize {
474    if len % 4 == 0 {
475        len
476    } else {
477        len + 4 - len % 4
478    }
479}
480
481/// Automatically implemented trait providing some helper functions for [`Attribute`]s.
482pub trait AttributeExt {
483    /// The length in bytes of an [`Attribute`] as stored in a [`Message`](crate::message::Message)
484    /// including any padding and the attribute header.
485    fn padded_len(&self) -> usize;
486}
487
488impl<A: Attribute + ?Sized> AttributeExt for A {
489    fn padded_len(&self) -> usize {
490        4 + pad_attribute_len(self.length() as usize)
491    }
492}
493
494/// Trait required when implementing writing an [`Attribute`] to a sequence of bytes
495pub trait AttributeWrite: Attribute {
496    /// Write attribute to the provided destination buffer.
497    ///
498    /// Panics if the destination buffer is not large enough
499    fn write_into_unchecked(&self, dest: &mut [u8]);
500    /// Produce a [`RawAttribute`] from this [`Attribute`]
501    fn to_raw(&self) -> RawAttribute<'_>;
502}
503
504/// Automatically implemented trait providing helper functionality for writing an [`Attribute`] to
505/// a sequence of bytes.
506pub trait AttributeWriteExt: AttributeWrite {
507    /// Write the 4 byte attribute header into the provided destination buffer returning the
508    /// number of bytes written.
509    ///
510    /// Panics if the destination cannot hold at least 4 bytes of data.
511    fn write_header_unchecked(&self, dest: &mut [u8]) -> usize;
512    /// Write the 4 byte attribute header into the provided destination buffer returning the
513    /// number of bytes written, or an error.
514    fn write_header(&self, dest: &mut [u8]) -> Result<usize, StunWriteError>;
515    /// Write this attribute into the provided destination buffer returning the number of bytes
516    /// written, or an error.
517    fn write_into(&self, dest: &mut [u8]) -> Result<usize, StunWriteError>;
518}
519
520impl<A: AttributeWrite + ?Sized> AttributeWriteExt for A {
521    fn write_header(&self, dest: &mut [u8]) -> Result<usize, StunWriteError> {
522        if dest.len() < 4 {
523            return Err(StunWriteError::TooSmall {
524                expected: 4,
525                actual: dest.len(),
526            });
527        }
528        self.write_header_unchecked(dest);
529        Ok(4)
530    }
531    fn write_header_unchecked(&self, dest: &mut [u8]) -> usize {
532        AttributeHeader {
533            atype: self.get_type(),
534            length: self.length(),
535        }
536        .write_into(dest);
537        4
538    }
539
540    fn write_into(&self, dest: &mut [u8]) -> Result<usize, StunWriteError> {
541        let len = self.padded_len();
542        if len > dest.len() {
543            return Err(StunWriteError::TooSmall {
544                expected: len,
545                actual: dest.len(),
546            });
547        }
548        self.write_into_unchecked(dest);
549        Ok(len)
550    }
551}
552
553/// The header and raw bytes of an unparsed [`Attribute`]
554#[derive(Debug, Clone, PartialEq, Eq)]
555pub struct RawAttribute<'a> {
556    /// The [`AttributeHeader`] of this [`RawAttribute`]
557    pub header: AttributeHeader,
558    /// The raw bytes of this [`RawAttribute`]
559    pub value: Data<'a>,
560}
561
562macro_rules! display_attr {
563    ($this:ident, $f:ident, $CamelType:ty) => {{
564        if let Ok(attr) = <$CamelType>::from_raw_ref($this) {
565            write!($f, "{}", attr)
566        } else {
567            write!(
568                $f,
569                "{}(Malformed): len: {}, data: {:?})",
570                $this.get_type(),
571                $this.header.length(),
572                $this.value
573            )
574        }
575    }};
576}
577
578impl core::fmt::Display for RawAttribute<'_> {
579    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
580        // try to get a more specialised display
581        match self.get_type() {
582            Username::TYPE => display_attr!(self, f, Username),
583            MessageIntegrity::TYPE => display_attr!(self, f, MessageIntegrity),
584            ErrorCode::TYPE => display_attr!(self, f, ErrorCode),
585            UnknownAttributes::TYPE => display_attr!(self, f, UnknownAttributes),
586            Realm::TYPE => display_attr!(self, f, Realm),
587            Nonce::TYPE => display_attr!(self, f, Nonce),
588            MessageIntegritySha256::TYPE => {
589                display_attr!(self, f, MessageIntegritySha256)
590            }
591            PasswordAlgorithm::TYPE => display_attr!(self, f, PasswordAlgorithm),
592            Userhash::TYPE => display_attr!(self, f, Userhash),
593            XorMappedAddress::TYPE => display_attr!(self, f, XorMappedAddress),
594            PasswordAlgorithms::TYPE => display_attr!(self, f, PasswordAlgorithms),
595            AlternateDomain::TYPE => display_attr!(self, f, AlternateDomain),
596            Software::TYPE => display_attr!(self, f, Software),
597            AlternateServer::TYPE => display_attr!(self, f, AlternateServer),
598            Fingerprint::TYPE => display_attr!(self, f, Fingerprint),
599            _ => {
600                #[cfg(feature = "std")]
601                {
602                    let mut display_impls = ATTRIBUTE_EXTERNAL_DISPLAY_IMPL
603                        .get_or_init(|| Default::default())
604                        .lock()
605                        .unwrap();
606                    if let Some(imp) = display_impls.get_mut(&self.get_type()) {
607                        return imp(self, f);
608                    }
609                }
610                write!(
611                    f,
612                    "RawAttribute (type: {:?}, len: {}, data: {:?})",
613                    self.header.get_type(),
614                    self.header.length(),
615                    &self.value
616                )
617            }
618        }
619    }
620}
621
622impl<'a> RawAttribute<'a> {
623    /// Create a new [`RawAttribute`]
624    pub fn new(atype: AttributeType, data: &'a [u8]) -> Self {
625        Self {
626            header: AttributeHeader {
627                atype,
628                length: data.len() as u16,
629            },
630            value: data.into(),
631        }
632    }
633
634    /// Create a new owned [`RawAttribute`]
635    pub fn new_owned(atype: AttributeType, data: Box<[u8]>) -> Self {
636        Self {
637            header: AttributeHeader {
638                atype,
639                length: data.len() as u16,
640            },
641            value: data.into(),
642        }
643    }
644
645    /// Deserialize a `RawAttribute` from bytes.
646    ///
647    /// # Examples
648    ///
649    /// ```
650    /// # use stun_types::attribute::{RawAttribute, Attribute, AttributeType};
651    /// let data = &[0, 1, 0, 2, 5, 6, 0, 0];
652    /// let attr = RawAttribute::from_bytes(data).unwrap();
653    /// assert_eq!(attr.get_type(), AttributeType::new(1));
654    /// assert_eq!(attr.length(), 2);
655    /// ```
656    pub fn from_bytes(data: &'a [u8]) -> Result<Self, StunParseError> {
657        let header = AttributeHeader::parse(data)?;
658        // the advertised length is larger than actual data -> error
659        if header.length() > (data.len() - 4) as u16 {
660            return Err(StunParseError::Truncated {
661                expected: header.length() as usize,
662                actual: data.len() - 4,
663            });
664        }
665        Ok(Self {
666            header,
667            value: Data::Borrowed(data[4..header.length() as usize + 4].into()),
668        })
669    }
670
671    /// Serialize a `RawAttribute` to bytes.
672    ///
673    /// # Examples
674    ///
675    /// ```
676    /// # use stun_types::attribute::{RawAttribute, Attribute, AttributeType};
677    /// let attr = RawAttribute::new(AttributeType::new(1), &[5, 6]);
678    /// assert_eq!(attr.to_bytes(), &[0, 1, 0, 2, 5, 6, 0, 0]);
679    /// ```
680    pub fn to_bytes(&self) -> Vec<u8> {
681        let mut vec = Vec::with_capacity(self.padded_len());
682        let mut header_bytes = [0; 4];
683        self.header.write_into(&mut header_bytes);
684        vec.extend(&header_bytes);
685        vec.extend(&*self.value);
686        let len = vec.len();
687        if len % 4 != 0 {
688            // pad to 4 bytes
689            vec.resize(len + 4 - (len % 4), 0);
690        }
691        vec
692    }
693
694    /// Helper for checking that a raw attribute is of a particular type and has a data length
695    /// within a certain range.
696    pub fn check_type_and_len(
697        &self,
698        atype: AttributeType,
699        allowed_range: impl core::ops::RangeBounds<usize>,
700    ) -> Result<(), StunParseError> {
701        if self.header.get_type() != atype {
702            return Err(StunParseError::WrongAttributeImplementation);
703        }
704        check_len(self.value.len(), allowed_range)
705    }
706
707    /// Consume this [`RawAttribute`] and return a new owned [`RawAttribute`]
708    pub fn into_owned<'b>(self) -> RawAttribute<'b> {
709        RawAttribute {
710            header: self.header,
711            value: self.value.into_owned(),
712        }
713    }
714}
715
716impl Attribute for RawAttribute<'_> {
717    /// Returns the [`AttributeType`] of this [`RawAttribute`]
718    fn get_type(&self) -> AttributeType {
719        self.header.get_type()
720    }
721
722    /// Returns the length of this [`RawAttribute`]
723    fn length(&self) -> u16 {
724        self.value.len() as u16
725    }
726}
727
728impl AttributeWrite for RawAttribute<'_> {
729    /// Write this [`RawAttribute`] into a byte slice.  Returns the number of bytes written.
730    fn write_into_unchecked(&self, dest: &mut [u8]) {
731        let len = self.padded_len();
732        self.header.write_into(dest);
733        let mut offset = 4;
734        dest[offset..offset + self.value.len()].copy_from_slice(&self.value);
735        offset += self.value.len();
736        if len - offset > 0 {
737            dest[offset..len].fill(0);
738        }
739    }
740
741    fn to_raw(&self) -> RawAttribute<'_> {
742        self.clone()
743    }
744}
745
746impl<'a, A: AttributeWrite> From<&'a A> for RawAttribute<'a> {
747    fn from(value: &'a A) -> Self {
748        value.to_raw()
749    }
750}
751
752fn check_len(
753    len: usize,
754    allowed_range: impl core::ops::RangeBounds<usize>,
755) -> Result<(), StunParseError> {
756    match allowed_range.start_bound() {
757        core::ops::Bound::Unbounded => (),
758        core::ops::Bound::Included(start) => {
759            if len < *start {
760                return Err(StunParseError::Truncated {
761                    expected: *start,
762                    actual: len,
763                });
764            }
765        }
766        core::ops::Bound::Excluded(start) => {
767            if len <= *start {
768                return Err(StunParseError::Truncated {
769                    expected: start + 1,
770                    actual: len,
771                });
772            }
773        }
774    }
775    match allowed_range.end_bound() {
776        core::ops::Bound::Unbounded => (),
777        core::ops::Bound::Included(end) => {
778            if len > *end {
779                return Err(StunParseError::TooLarge {
780                    expected: *end,
781                    actual: len,
782                });
783            }
784        }
785        core::ops::Bound::Excluded(end) => {
786            if len >= *end {
787                return Err(StunParseError::TooLarge {
788                    expected: *end - 1,
789                    actual: len,
790                });
791            }
792        }
793    }
794    Ok(())
795}
796
797impl From<RawAttribute<'_>> for Vec<u8> {
798    fn from(f: RawAttribute) -> Self {
799        f.to_bytes()
800    }
801}
802
803#[cfg(test)]
804mod tests {
805    use super::*;
806
807    #[test]
808    fn attribute_type() {
809        let _log = crate::tests::test_init_log();
810        let atype = ErrorCode::TYPE;
811        let anum: u16 = atype.into();
812        assert_eq!(atype, anum.into());
813    }
814
815    #[test]
816    fn short_attribute_header() {
817        let _log = crate::tests::test_init_log();
818        let data = [0; 1];
819        // not enough data to parse the header
820        let res: Result<AttributeHeader, _> = data.as_ref().try_into();
821        assert!(res.is_err());
822    }
823
824    #[test]
825    fn raw_attribute_construct() {
826        let _log = crate::tests::test_init_log();
827        let a = RawAttribute::new(1.into(), &[80, 160]);
828        assert_eq!(a.get_type(), 1.into());
829        let bytes: Vec<_> = a.into();
830        assert_eq!(bytes, &[0, 1, 0, 2, 80, 160, 0, 0]);
831        let b = RawAttribute::from_bytes(bytes.as_ref()).unwrap();
832        assert_eq!(b.get_type(), 1.into());
833    }
834
835    #[test]
836    fn raw_attribute_encoding() {
837        let mut out = [0; 8];
838        let mut out2 = [0; 8];
839        let _log = crate::tests::test_init_log();
840        let orig = RawAttribute::new(1.into(), &[80, 160]);
841        assert_eq!(orig.get_type(), 1.into());
842        orig.write_into(&mut out).unwrap();
843        orig.write_into_unchecked(&mut out2);
844        assert_eq!(out, out2);
845        let mut data: Vec<_> = orig.into();
846        let len = data.len();
847        // one byte too big vs data size
848        BigEndian::write_u16(&mut data[2..4], len as u16 - 4 + 1);
849        assert!(matches!(
850            RawAttribute::from_bytes(data.as_ref()),
851            Err(StunParseError::Truncated {
852                expected: 5,
853                actual: 4
854            })
855        ));
856    }
857
858    #[test]
859    fn raw_attribute_header() {
860        let mut out = [0; 4];
861        let mut out2 = [0; 4];
862        let _log = crate::tests::test_init_log();
863        let orig = RawAttribute::new(1.into(), &[80, 160]);
864        assert!(matches!(orig.write_header(&mut out), Ok(4)));
865        assert_eq!(orig.write_header_unchecked(&mut out2), 4);
866        assert_eq!(out, out2);
867        assert_eq!(orig.header.to_bytes(), out);
868        assert_eq!(&orig.to_bytes()[..4], out);
869        let bytes: [_; 4] = orig.header.into();
870        assert_eq!(bytes, out);
871    }
872
873    #[test]
874    fn test_check_len() {
875        let _log = crate::tests::test_init_log();
876        assert!(check_len(4, ..).is_ok());
877        assert!(check_len(4, 0..).is_ok());
878        assert!(check_len(4, 0..8).is_ok());
879        assert!(check_len(4, 0..=8).is_ok());
880        assert!(check_len(4, ..=8).is_ok());
881        assert!(matches!(
882            check_len(4, ..4),
883            Err(StunParseError::TooLarge {
884                expected: 3,
885                actual: 4
886            })
887        ));
888        assert!(matches!(
889            check_len(4, 5..),
890            Err(StunParseError::Truncated {
891                expected: 5,
892                actual: 4
893            })
894        ));
895        assert!(matches!(
896            check_len(4, ..=3),
897            Err(StunParseError::TooLarge {
898                expected: 3,
899                actual: 4
900            })
901        ));
902        assert!(matches!(
903            check_len(
904                4,
905                (core::ops::Bound::Excluded(4), core::ops::Bound::Unbounded)
906            ),
907            Err(StunParseError::Truncated {
908                expected: 5,
909                actual: 4
910            })
911        ));
912    }
913
914    #[test]
915    #[cfg(feature = "std")]
916    fn test_external_display_impl() {
917        let _log = crate::tests::test_init_log();
918        let atype = AttributeType::new(0xFFFF);
919        let imp = |attr: &RawAttribute<'_>,
920                   f: &mut core::fmt::Formatter<'_>|
921         -> core::fmt::Result { write!(f, "Custom {}", attr.value[0]) };
922        add_display_impl(atype, imp);
923        let data = [4, 0];
924        let attr = RawAttribute::new(atype, &data);
925        let display_str = alloc::format!("{}", attr);
926        assert_eq!(display_str, "Custom 4");
927
928        atype.add_name("SOME-NAME");
929        assert_eq!(atype.name(), "SOME-NAME");
930
931        attribute_display!(Fingerprint);
932    }
933}