diff options
| author | Linus Färnstrand <linus@mullvad.net> | 2016-12-06 10:06:04 +0100 |
|---|---|---|
| committer | Linus Färnstrand <linus@mullvad.net> | 2016-12-06 23:45:45 +0100 |
| commit | 053b969c5ed59862b68e573b65d62e1adcf9ddf1 (patch) | |
| tree | 4cae7b55237f65d1a81a77edab375dc39449209d /src | |
| parent | 876441779e8bdb64abe7822969a822db81f5c7ac (diff) | |
| download | mullvadvpn-053b969c5ed59862b68e573b65d62e1adcf9ddf1.tar.xz mullvadvpn-053b969c5ed59862b68e573b65d62e1adcf9ddf1.zip | |
Add RemoteAddr conversion impls and tests
Diffstat (limited to 'src')
| -rw-r--r-- | src/net.rs | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/src/net.rs b/src/net.rs index 0906426f7b..4715bf0b7b 100644 --- a/src/net.rs +++ b/src/net.rs @@ -1,3 +1,8 @@ +use std::error::Error; +use std::fmt; +use std::net::SocketAddr; +use std::str::FromStr; + /// Representation of a TCP or UDP endpoint. The host is represented as a String since it can be /// both a hostname/domain as well as an IP. #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -26,9 +31,67 @@ impl RemoteAddr { } } +impl From<SocketAddr> for RemoteAddr { + fn from(socket_addr: SocketAddr) -> Self { + RemoteAddr { + address: socket_addr.ip().to_string(), + port: socket_addr.port(), + } + } +} + +impl FromStr for RemoteAddr { + type Err = AddrParseError; + fn from_str(s: &str) -> Result<Self, Self::Err> { + let (address_str, port_str) = split_at_colon(s).map_err(|_| AddrParseError::InvalidPort)?; + let port = u16::from_str(port_str).map_err(|_| AddrParseError::InvalidPort)?; + if address_str.len() == 0 { + return Err(AddrParseError::InvalidAddress); + } + Ok(RemoteAddr { + address: String::from(address_str), + port: port, + }) + } +} + +fn split_at_colon(s: &str) -> Result<(&str, &str), ()> { + let mut iter = s.rsplitn(2, ":"); + let port = iter.next().unwrap(); + let address = iter.next().ok_or(())?; + Ok((address, port)) +} + +/// Representation of the errors that can happen when parsing a string into a `RemoteAddr`. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum AddrParseError { + /// When the address is malformed + InvalidAddress, + /// When no port or an invalid port + InvalidPort, +} + +impl fmt::Display for AddrParseError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write_str(self.description()) + } +} + +impl Error for AddrParseError { + fn description(&self) -> &str { + match *self { + AddrParseError::InvalidAddress => "Invalid address", + AddrParseError::InvalidPort => "Invalid port", + } + } +} + #[cfg(test)] mod tests { + use std::net::SocketAddr; + use std::str::FromStr; + use super::*; #[test] @@ -37,4 +100,57 @@ mod tests { assert_eq!("a_domain", remote_addr.address()); assert_eq!(543, remote_addr.port()); } + + #[test] + fn remote_addr_from_socket_addr() { + let socket_addr = SocketAddr::from_str("10.0.1.1:76").unwrap(); + let remote_addr: RemoteAddr = socket_addr.into(); + assert_eq!("10.0.1.1", remote_addr.address()); + assert_eq!(76, remote_addr.port()); + } + + #[test] + fn remote_addr_from_str() { + let remote_addr = RemoteAddr::from_str("example.com:3333").unwrap(); + assert_eq!("example.com", remote_addr.address()); + assert_eq!(3333, remote_addr.port()); + } + + #[test] + fn remote_addr_from_ipv6_str() { + let remote_addr = RemoteAddr::from_str("[fe80::1]:1337").unwrap(); + assert_eq!("[fe80::1]", remote_addr.address()); + assert_eq!(1337, remote_addr.port()); + } + + #[test] + fn remote_addr_from_ipv6_str_without_port() { + let remote_addr = RemoteAddr::from_str("fe80::1").unwrap(); + assert_eq!("fe80:", remote_addr.address()); + assert_eq!(1, remote_addr.port()); + } + + #[test] + fn remote_addr_from_str_no_colon() { + let err = RemoteAddr::from_str("example.com"); + assert_eq!(Err(AddrParseError::InvalidPort), err); + } + + #[test] + fn remote_addr_from_str_invalid_port_large() { + let err = RemoteAddr::from_str("example.com:99999"); + assert_eq!(Err(AddrParseError::InvalidPort), err); + } + + #[test] + fn remote_addr_from_str_empty_address() { + let err = RemoteAddr::from_str(":100"); + assert_eq!(Err(AddrParseError::InvalidAddress), err); + } + + #[test] + fn remote_addr_from_str_empty_port() { + let err = RemoteAddr::from_str("example.com:"); + assert_eq!(Err(AddrParseError::InvalidPort), err); + } } |
