stun_rs/attributes/stun/
software.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
const SOFTWARE: u16 = 0x8022;
const MAX_ENCODED_SIZE: usize = 509;
const MAX_DECODED_SIZE: usize = 763;

crate::common::string_attribute!(
    /// The [`Software`] attribute contains a textual description of the software
    /// being used by the agent sending the message.  It is used by clients
    /// and servers.  Its value SHOULD include manufacturer and version
    /// number.  The attribute has no impact on operation of the protocol and
    /// serves only as a tool for diagnostic and debugging purposes.
    ///
    /// # Examples
    ///```rust
    /// # use std::error::Error;
    /// # use stun_rs::attributes::stun::Software;
    /// #
    /// # fn main() -> Result<(), Box<dyn Error>> {
    /// let attr = Software::new("STUN test client")?;
    /// assert_eq!(attr, "STUN test client");
    /// #
    /// #  Ok(())
    /// # }
    ///```
    Software,
    SOFTWARE,
    MAX_ENCODED_SIZE,
    MAX_DECODED_SIZE,
);

#[cfg(test)]
mod tests {
    use super::*;
    use crate::attributes::{
        AttributeDecoderContext, AttributeEncoderContext, DecodeAttributeValue,
        EncodeAttributeValue,
    };
    use crate::{StunAttribute, StunErrorType};
    use std::convert::TryFrom;

    #[test]
    fn constructor() {
        let name = String::from("Test Software v1.0");
        let attr_1 = Software::try_from(&name).expect("Can not create Software attribute");
        let attr_2 = Software::new(&name).expect("Can not create Software attribute");
        let attr_3 = Software::try_from(name.as_str()).expect("Can not create Software attribute");
        let attr_4 = Software::try_from(name.clone()).expect("Can not create Software attribute");

        assert_eq!(attr_1, name);
        assert_eq!(name, attr_1);
        assert_eq!(name, attr_3);
        assert_eq!(name, attr_4);
        assert_eq!(attr_1, "Test Software v1.0");
        assert_eq!("Test Software v1.0", attr_1);
        assert_eq!(attr_1, attr_2);

        let value: &String = attr_1.as_ref();
        assert!(name.eq(value));

        let value: &str = attr_1.as_ref();
        assert!(name.eq(value));

        let value = "x".repeat(MAX_ENCODED_SIZE);
        let _result = Software::new(value.as_str()).expect("Can not create a Sofware attribute");

        let value = "x".repeat(MAX_ENCODED_SIZE + 1);
        let result = Software::new(value);
        assert_eq!(
            result.expect_err("Error expected"),
            StunErrorType::ValueTooLong
        );
    }

    #[test]
    fn decode_software_value() {
        let dummy_msg = [];
        // Software: example.org
        let value = "example";
        let ctx = AttributeDecoderContext::new(None, &dummy_msg, value.as_bytes());

        let (software, size) = Software::decode(ctx).expect("Can not decode Software");
        assert_eq!(size, 7);
        assert_eq!(software.as_str(), "example");

        let value = "x".repeat(MAX_DECODED_SIZE);
        let ctx = AttributeDecoderContext::new(None, &dummy_msg, value.as_bytes());
        let (_nonce, size) = Software::decode(ctx).expect("Can not decode Software");
        assert_eq!(size, MAX_DECODED_SIZE);

        let value = "x".repeat(MAX_DECODED_SIZE + 1);
        let ctx = AttributeDecoderContext::new(None, &dummy_msg, value.as_bytes());
        assert_eq!(
            Software::decode(ctx).expect_err("Error expected"),
            StunErrorType::ValueTooLong
        );
    }

    #[test]
    fn encode_software_value() {
        let dummy_msg: [u8; 0] = [0x0; 0];
        let software =
            Software::try_from("test software").expect("Can not create a Sofware attribute");

        let mut buffer: [u8; 13] = [0x0; 13];
        let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
        let result = software.encode(ctx);
        assert_eq!(result, Ok(13));

        let mut buffer: [u8; MAX_ENCODED_SIZE] = [0x0; MAX_ENCODED_SIZE];
        let software = Software::try_from("x".repeat(MAX_ENCODED_SIZE))
            .expect("Can not create a Sofware attribute");
        let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
        let result = software.encode(ctx);
        assert_eq!(result, Ok(MAX_ENCODED_SIZE));

        let mut buffer: [u8; 12] = [0x0; 12];
        let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
        let result = software.encode(ctx);
        assert_eq!(
            result.expect_err("Error expected"),
            StunErrorType::SmallBuffer
        );

        let mut buffer: [u8; MAX_ENCODED_SIZE + 1] = [0x0; MAX_ENCODED_SIZE + 1];
        let software = Software("x".repeat(MAX_ENCODED_SIZE + 1));
        let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
        let result = software.encode(ctx);
        assert_eq!(
            result.expect_err("Error expected"),
            StunErrorType::ValueTooLong
        );
    }

    #[test]
    fn software_stunt_attribute() {
        let attr = StunAttribute::Software(
            Software::new("test").expect("Can not create Software attribute"),
        );
        assert!(attr.is_software());
        assert!(attr.as_software().is_ok());
        assert!(attr.as_unknown().is_err());

        assert!(!attr.attribute_type().is_comprehension_required());
        assert!(attr.attribute_type().is_comprehension_optional());

        let dbg_fmt = format!("{:?}", attr);
        assert_eq!("Software(Software(\"test\"))", dbg_fmt);
    }
}