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