1#![deny(missing_debug_implementations)]
12#![deny(missing_docs)]
13#![cfg_attr(docsrs, feature(doc_cfg))]
14
15#![no_std]
64
65use core::{
66 net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
67 str::FromStr,
68};
69
70use crate::message::StunParseError;
71
72pub mod attribute;
73pub mod data;
74pub mod message;
75
76extern crate alloc;
77
78#[cfg(any(feature = "std", test))]
79extern crate std;
80
81#[derive(Debug, Clone, Copy, PartialEq, Eq)]
83#[repr(u32)]
84pub enum TransportType {
85 Udp,
87 Tcp,
89}
90
91#[derive(Debug, thiserror::Error)]
93pub enum ParseTransportTypeError {
94 #[error("Unknown transport value was provided")]
96 UnknownTransport,
97}
98
99impl FromStr for TransportType {
100 type Err = ParseTransportTypeError;
101
102 fn from_str(s: &str) -> Result<Self, Self::Err> {
103 if s.eq_ignore_ascii_case("UDP") {
104 Ok(TransportType::Udp)
105 } else if s.eq_ignore_ascii_case("TCP") {
106 Ok(TransportType::Tcp)
107 } else {
108 Err(ParseTransportTypeError::UnknownTransport)
109 }
110 }
111}
112
113impl core::fmt::Display for TransportType {
114 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
115 match &self {
116 TransportType::Udp => f.pad("UDP"),
117 TransportType::Tcp => f.pad("TCP"),
118 }
119 }
120}
121
122#[derive(Debug, Clone, Copy, PartialEq, Eq)]
124pub enum AddressFamily {
125 IPV4,
127 IPV6,
129}
130
131impl AddressFamily {
132 pub(crate) fn to_byte(self) -> u8 {
133 match self {
134 AddressFamily::IPV4 => 0x1,
135 AddressFamily::IPV6 => 0x2,
136 }
137 }
138
139 pub(crate) fn from_byte(byte: u8) -> Result<AddressFamily, StunParseError> {
140 match byte {
141 0x1 => Ok(AddressFamily::IPV4),
142 0x2 => Ok(AddressFamily::IPV6),
143 _ => Err(StunParseError::InvalidAttributeData),
144 }
145 }
146}
147
148impl From<&SocketAddr> for AddressFamily {
149 fn from(value: &SocketAddr) -> Self {
150 match value {
151 SocketAddr::V4(_) => Self::IPV4,
152 SocketAddr::V6(_) => Self::IPV6,
153 }
154 }
155}
156
157impl From<&SocketAddrV4> for AddressFamily {
158 fn from(_value: &SocketAddrV4) -> Self {
159 Self::IPV4
160 }
161}
162
163impl From<&SocketAddrV6> for AddressFamily {
164 fn from(_value: &SocketAddrV6) -> Self {
165 Self::IPV6
166 }
167}
168
169impl From<&IpAddr> for AddressFamily {
170 fn from(value: &IpAddr) -> Self {
171 match value {
172 IpAddr::V4(_) => Self::IPV4,
173 IpAddr::V6(_) => Self::IPV6,
174 }
175 }
176}
177
178impl From<&Ipv4Addr> for AddressFamily {
179 fn from(_value: &Ipv4Addr) -> Self {
180 Self::IPV4
181 }
182}
183
184impl From<&Ipv6Addr> for AddressFamily {
185 fn from(_value: &Ipv6Addr) -> Self {
186 Self::IPV6
187 }
188}
189
190impl core::fmt::Display for AddressFamily {
191 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
192 match self {
193 AddressFamily::IPV4 => write!(f, "IPV4"),
194 AddressFamily::IPV6 => write!(f, "IPV6"),
195 }
196 }
197}
198
199pub mod prelude {
201 pub use crate::attribute::{
202 Attribute, AttributeExt, AttributeFromRaw, AttributeStaticType, AttributeWrite,
203 AttributeWriteExt,
204 };
205 pub use crate::message::{MessageWrite, MessageWriteExt};
206}
207
208#[cfg(test)]
209pub(crate) mod tests {
210 use alloc::borrow::ToOwned;
211 use alloc::format;
212 use alloc::string::{String, ToString};
213 use tracing::subscriber::DefaultGuard;
214 use tracing_subscriber::layer::SubscriberExt;
215 use tracing_subscriber::Layer;
216
217 use super::*;
218
219 pub fn test_init_log() -> DefaultGuard {
220 let level_filter = std::env::var("STUN_LOG")
221 .or(std::env::var("RUST_LOG"))
222 .ok()
223 .and_then(|var| var.parse::<tracing_subscriber::filter::Targets>().ok())
224 .unwrap_or(
225 tracing_subscriber::filter::Targets::new().with_default(tracing::Level::TRACE),
226 );
227 let registry = tracing_subscriber::registry().with(
228 tracing_subscriber::fmt::layer()
229 .with_file(true)
230 .with_line_number(true)
231 .with_level(true)
232 .with_target(false)
233 .with_test_writer()
234 .with_filter(level_filter),
235 );
236 tracing::subscriber::set_default(registry)
237 }
238
239 #[test]
240 fn parse_transport_type() {
241 assert!(matches!("UDP".parse(), Ok(TransportType::Udp)));
242 assert!(matches!("TCP".parse(), Ok(TransportType::Tcp)));
243 assert!(matches!("udp".parse(), Ok(TransportType::Udp)));
244 assert!(matches!("tcp".parse(), Ok(TransportType::Tcp)));
245 assert!(matches!(
246 TransportType::from_str("Random"),
247 Err(ParseTransportTypeError::UnknownTransport)
248 ));
249 }
250
251 #[test]
252 fn transport_type_str() {
253 assert_eq!(TransportType::Udp.to_string(), String::from("UDP"));
254 assert_eq!(TransportType::Tcp.to_string(), String::from("TCP"));
255 }
256
257 #[test]
258 fn address_family() {
259 assert_eq!(AddressFamily::IPV4.to_byte(), 1);
260 assert_eq!(AddressFamily::from_byte(1).unwrap(), AddressFamily::IPV4);
261 assert_eq!(format!("{}", AddressFamily::IPV4), "IPV4".to_owned());
262 assert_eq!(AddressFamily::IPV6.to_byte(), 2);
263 assert_eq!(AddressFamily::from_byte(2).unwrap(), AddressFamily::IPV6);
264 assert_eq!(format!("{}", AddressFamily::IPV6), "IPV6".to_owned());
265 assert!(matches!(
266 AddressFamily::from_byte(3),
267 Err(StunParseError::InvalidAttributeData)
268 ));
269 let ipv4_addr: SocketAddr = "127.0.0.1:1".parse().unwrap();
270 assert_eq!(AddressFamily::from(&ipv4_addr), AddressFamily::IPV4);
271 assert_eq!(AddressFamily::from(&ipv4_addr.ip()), AddressFamily::IPV4);
272 let SocketAddr::V4(ipv4_addr) = ipv4_addr else {
273 unreachable!();
274 };
275 assert_eq!(AddressFamily::from(&ipv4_addr), AddressFamily::IPV4);
276 assert_eq!(AddressFamily::from(ipv4_addr.ip()), AddressFamily::IPV4);
277 let ipv6_addr: SocketAddr = "[::1]:1".parse().unwrap();
278 assert_eq!(AddressFamily::from(&ipv6_addr), AddressFamily::IPV6);
279 assert_eq!(AddressFamily::from(&ipv6_addr.ip()), AddressFamily::IPV6);
280 let SocketAddr::V6(ipv6_addr) = ipv6_addr else {
281 unreachable!();
282 };
283 assert_eq!(AddressFamily::from(&ipv6_addr), AddressFamily::IPV6);
284 assert_eq!(AddressFamily::from(ipv6_addr.ip()), AddressFamily::IPV6);
285 }
286}