stun_types/
lib.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#![deny(missing_debug_implementations)]
10#![deny(missing_docs)]
11
12//! # stun-types
13//!
14//! An implementation of parsing and writing STUN messages and attributes based on trait
15//! implementations.
16//!
17//! This is based on the following standards:
18//! - [RFC8489] - 'Session Traversal Utilities for NAT (STUN)'
19//! - [RFC5389] - 'Session Traversal Utilities for NAT (STUN)'
20//! - [RFC3489] - 'STUN - Simple Traversal of User Datagram Protocol (UDP)
21//!   Through Network Address Translators (NATs)'
22//!
23//! ## [Message](crate::message::Message)
24//!
25//! ### Message Parsing
26//!
27//! Message parsing is zerocopy by default through the [`RawAttribute`](crate::attribute::RawAttribute)
28//! struct. Converting to a concrete attribute implementation (such as
29//! [`Software`](crate::attribute::Software)) may incur a copy depending on the attribute
30//! implementation.
31//!
32//! ### Message writing
33//!
34//! The destination for a written Message is completely customizable through the
35//! [`MessageWrite`](crate::message::MessageWrite) trait. It is therefore possible to write directly
36//! into network provided buffers for increased performance and throughput.
37//!
38//! [`MessageWriteVec`](crate::message::MessageWriteVec) provides a simple implementation of
39//! message writing that will write into a newly allocated `Vec<u8>`.
40//!
41//! ## [Attribute](crate::attribute::Attribute)
42//!
43//! An [`Attribute`](crate::attribute::Attribute) implementation can be implemented entirely
44//! outside of this crate and used exactly the same as an Attribute implemented within this crate.
45//! Look at [`attribute`] module level documentation for an example of defining your own
46//! [`Attribute`](crate::attribute::Attribute).
47//!
48//! For TURN-related attributes, have a look at the [turn-types] crate which uses this crate to
49//! implement STUN attributes for TURN.
50//!
51//! [RFC8489]: https://tools.ietf.org/html/rfc8489
52//! [RFC5389]: https://tools.ietf.org/html/rfc5389
53//! [RFC3489]: https://tools.ietf.org/html/rfc3489
54//! [turn-types]: https://docs.rs/turn-types/latest/turn_types/
55//!
56//! ## Examples
57//!
58//! See the [`message`] and [`attribute`] module documentation for examples of use.
59
60use std::str::FromStr;
61
62pub mod attribute;
63pub mod data;
64pub mod message;
65
66/// The transport family
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
68#[repr(u32)]
69pub enum TransportType {
70    /// The UDP transport
71    Udp,
72    /// The TCP transport
73    Tcp,
74}
75
76/// Errors when parsing a [`TransportType`]
77#[derive(Debug, thiserror::Error)]
78pub enum ParseTransportTypeError {
79    /// An unknown transport value was provided
80    #[error("Unknown transport value was provided")]
81    UnknownTransport,
82}
83
84impl FromStr for TransportType {
85    type Err = ParseTransportTypeError;
86
87    fn from_str(s: &str) -> Result<Self, Self::Err> {
88        match s {
89            "UDP" => Ok(TransportType::Udp),
90            "TCP" => Ok(TransportType::Tcp),
91            _ => Err(ParseTransportTypeError::UnknownTransport),
92        }
93    }
94}
95
96impl std::fmt::Display for TransportType {
97    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98        match &self {
99            TransportType::Udp => f.pad("UDP"),
100            TransportType::Tcp => f.pad("TCP"),
101        }
102    }
103}
104
105/// Prelude module for traits
106pub mod prelude {
107    pub use crate::attribute::{
108        Attribute, AttributeExt, AttributeFromRaw, AttributeStaticType, AttributeWrite,
109        AttributeWriteExt,
110    };
111    pub use crate::message::{MessageWrite, MessageWriteExt};
112}
113
114#[cfg(test)]
115pub(crate) mod tests {
116    use tracing::subscriber::DefaultGuard;
117    use tracing_subscriber::layer::SubscriberExt;
118    use tracing_subscriber::Layer;
119
120    use super::*;
121
122    pub fn test_init_log() -> DefaultGuard {
123        let level_filter = std::env::var("STUN_LOG")
124            .or(std::env::var("RUST_LOG"))
125            .ok()
126            .and_then(|var| var.parse::<tracing_subscriber::filter::Targets>().ok())
127            .unwrap_or(
128                tracing_subscriber::filter::Targets::new().with_default(tracing::Level::TRACE),
129            );
130        let registry = tracing_subscriber::registry().with(
131            tracing_subscriber::fmt::layer()
132                .with_file(true)
133                .with_line_number(true)
134                .with_level(true)
135                .with_target(false)
136                .with_test_writer()
137                .with_filter(level_filter),
138        );
139        tracing::subscriber::set_default(registry)
140    }
141
142    #[test]
143    fn parse_transport_type() {
144        assert!(matches!("UDP".parse(), Ok(TransportType::Udp)));
145        assert!(matches!("TCP".parse(), Ok(TransportType::Tcp)));
146        assert!(matches!(
147            TransportType::from_str("Random"),
148            Err(ParseTransportTypeError::UnknownTransport)
149        ));
150    }
151
152    #[test]
153    fn transport_type_str() {
154        assert_eq!(TransportType::Udp.to_string(), String::from("UDP"));
155        assert_eq!(TransportType::Tcp.to_string(), String::from("TCP"));
156    }
157}