srt_protocol/options/
address.rs

1use std::{
2    borrow::Cow,
3    convert::{TryFrom, TryInto},
4    net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
5    num::ParseIntError,
6    str::FromStr,
7};
8
9use thiserror::Error;
10use url::Host;
11
12// A simple wrapper for SocketAddr. This is used to support scenarios where using ToSocketAddrs in
13// function parameters is undesirable or impossible, yet still support similar use of ergonomic
14// static string configuration for addresses when desired.
15#[derive(Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
16pub struct SocketAddress {
17    pub host: SocketHost,
18    pub port: u16,
19}
20
21impl<'a> TryFrom<Cow<'a, str>> for SocketAddress {
22    type Error = SocketAddressParseError;
23
24    fn try_from(value: Cow<'a, str>) -> Result<Self, Self::Error> {
25        TryFrom::try_from(value.as_ref())
26    }
27}
28
29impl TryFrom<String> for SocketAddress {
30    type Error = SocketAddressParseError;
31
32    fn try_from(value: String) -> Result<Self, Self::Error> {
33        TryFrom::try_from(value.as_ref())
34    }
35}
36
37impl TryFrom<&str> for SocketAddress {
38    type Error = SocketAddressParseError;
39
40    fn try_from(address: &str) -> Result<Self, Self::Error> {
41        let mut split = address.split(':');
42        match (split.next(), split.next(), split.next()) {
43            (Some(""), Some(port), None) => Ok(Self {
44                host: SocketHost::Ipv4(Ipv4Addr::UNSPECIFIED),
45                port: u16::from_str(port)?,
46            }),
47            (Some(host), port, None) => Ok(Self {
48                host: match url::Host::parse(host)? {
49                    Host::Domain(domain) => SocketHost::Domain(domain),
50                    Host::Ipv4(ipv4) => SocketHost::Ipv4(ipv4),
51                    Host::Ipv6(ipv6) => SocketHost::Ipv6(ipv6),
52                },
53                port: port.map(u16::from_str).unwrap_or(Ok(0))?,
54            }),
55            _ => Err(SocketAddressParseError::Invalid(address.to_string())),
56        }
57    }
58}
59
60impl From<u16> for SocketAddress {
61    fn from(port: u16) -> Self {
62        Self {
63            host: SocketHost::Ipv4(Ipv4Addr::UNSPECIFIED),
64            port,
65        }
66    }
67}
68
69impl From<SocketAddr> for SocketAddress {
70    fn from(addr: SocketAddr) -> Self {
71        Self {
72            host: addr.ip().into(),
73            port: addr.port(),
74        }
75    }
76}
77
78impl TryInto<SocketAddr> for SocketAddress {
79    type Error = ();
80
81    fn try_into(self) -> Result<SocketAddr, Self::Error> {
82        Ok(SocketAddr::new(self.host.try_into()?, self.port))
83    }
84}
85
86#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
87pub enum SocketHost {
88    /// A DNS domain name, as '.' dot-separated labels.
89    Domain(String),
90
91    /// An IPv4 address.
92    Ipv4(Ipv4Addr),
93
94    /// An IPv6 address.
95    Ipv6(Ipv6Addr),
96}
97
98impl From<IpAddr> for SocketHost {
99    fn from(addr: IpAddr) -> Self {
100        use SocketHost::*;
101        match addr {
102            IpAddr::V4(v4) => Ipv4(v4),
103            IpAddr::V6(v6) => Ipv6(v6),
104        }
105    }
106}
107
108impl TryInto<IpAddr> for SocketHost {
109    type Error = ();
110
111    fn try_into(self) -> Result<IpAddr, Self::Error> {
112        use SocketHost::*;
113        match self {
114            Ipv4(ipv4) => Ok(ipv4.into()),
115            Ipv6(ipv6) => Ok(ipv6.into()),
116            _ => Err(()),
117        }
118    }
119}
120
121impl From<Ipv4Addr> for SocketHost {
122    fn from(ipv4: Ipv4Addr) -> SocketHost {
123        SocketHost::Ipv4(ipv4)
124    }
125}
126
127impl From<Ipv6Addr> for SocketHost {
128    fn from(ipv6: Ipv6Addr) -> SocketHost {
129        SocketHost::Ipv6(ipv6)
130    }
131}
132
133impl Default for SocketHost {
134    fn default() -> Self {
135        SocketHost::Ipv4(Ipv4Addr::UNSPECIFIED)
136    }
137}
138
139#[derive(Error, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
140pub enum SocketAddressParseError {
141    #[error("Invalid address: {0}")]
142    Invalid(String),
143    #[error("Invalid host: {0}")]
144    InvalidHost(String),
145    #[error("Invalid port: {0}")]
146    InvalidPort(String),
147}
148
149impl From<ParseIntError> for SocketAddressParseError {
150    fn from(error: ParseIntError) -> Self {
151        SocketAddressParseError::InvalidPort(error.to_string())
152    }
153}
154
155impl From<url::ParseError> for SocketAddressParseError {
156    fn from(error: url::ParseError) -> Self {
157        SocketAddressParseError::InvalidHost(error.to_string())
158    }
159}