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}