Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion src/ifaddrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
use cfg_if::cfg_if;
#[cfg(apple_targets)]
use std::convert::TryFrom;
use std::ffi;
use std::iter::Iterator;
use std::mem;
use std::net::{SocketAddr, ToSocketAddrs};
use std::option::Option;
use std::{ffi, option};

use crate::net::if_::*;
use crate::sys::socket::{SockaddrLike, SockaddrStorage};
Expand Down Expand Up @@ -144,6 +145,18 @@ impl Iterator for InterfaceAddressIterator {
}
}

impl ToSocketAddrs for InterfaceAddress {
type Iter = option::IntoIter<SocketAddr>;

fn to_socket_addrs(&self) -> std::io::Result<Self::Iter> {
let opt = match self.address {
Some(sas) => sas.to_socket_addrs()?,
None => None.into_iter(),
};
Ok(opt)
}
}

/// Get interface addresses using libc's `getifaddrs`
///
/// Note that the underlying implementation differs between OSes. Only the
Expand Down Expand Up @@ -183,6 +196,8 @@ pub fn getifaddrs() -> Result<InterfaceAddressIterator> {

#[cfg(test)]
mod tests {
use std::net::Ipv4Addr;

use super::*;

// Only checks if `getifaddrs` can be invoked without panicking.
Expand Down Expand Up @@ -214,4 +229,15 @@ mod tests {
}
panic!("No address?");
}

#[test]
fn test_tosockaddrs() -> Result<()> {
let with_addrs = getifaddrs()?
.filter_map(|ifaddr| ifaddr.to_socket_addrs().unwrap().next())
.filter(|sa| sa.ip() == Ipv4Addr::LOCALHOST)
.collect::<Vec<SocketAddr>>();
// Assumes a modern *nix must have v4 loopback to work.
assert_eq!(1, with_addrs.len());
Ok(())
}
}
125 changes: 123 additions & 2 deletions src/sys/socket/addr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ use memoffset::offset_of;
use std::convert::TryInto;
use std::ffi::OsStr;
use std::hash::{Hash, Hasher};
use std::net::{Ipv4Addr, Ipv6Addr};
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV6, ToSocketAddrs};
use std::os::unix::ffi::OsStrExt;
use std::path::Path;
use std::{fmt, mem, net, ptr, slice};
use std::{fmt, mem, net, option, ptr, slice, vec};

/// Convert a std::net::Ipv4Addr into the libc form.
#[cfg(feature = "net")]
Expand Down Expand Up @@ -952,6 +952,16 @@ impl std::str::FromStr for SockaddrIn {
}
}

#[cfg(feature = "net")]
impl ToSocketAddrs for SockaddrIn {
type Iter = vec::IntoIter<SocketAddr>;

fn to_socket_addrs(&self) -> std::io::Result<Self::Iter> {
let sa = SocketAddr::new(self.ip().into(), self.port());
Ok(vec![sa].into_iter())
}
}

/// An IPv6 socket address
#[cfg(feature = "net")]
#[repr(transparent)]
Expand Down Expand Up @@ -1102,6 +1112,21 @@ impl std::str::FromStr for SockaddrIn6 {
}
}

#[cfg(feature = "net")]
impl ToSocketAddrs for SockaddrIn6 {
type Iter = vec::IntoIter<SocketAddr>;

fn to_socket_addrs(&self) -> std::io::Result<Self::Iter> {
let sa6 = SocketAddrV6::new(self.ip(),
self.port(),
self.flowinfo(),
self.scope_id())
.into();
Ok(vec![sa6].into_iter())

}
}

/// A container for any sockaddr type
///
/// Just like C's `sockaddr_storage`, this type is large enough to hold any type
Expand Down Expand Up @@ -1517,6 +1542,25 @@ impl PartialEq for SockaddrStorage {
}
}

#[cfg(feature = "net")]
impl ToSocketAddrs for SockaddrStorage {
type Iter = option::IntoIter<SocketAddr>;

fn to_socket_addrs(&self) -> std::io::Result<Self::Iter> {
let opt = if let Some(sai) = self.as_sockaddr_in() {
sai.to_socket_addrs()?.next()

} else if let Some(sai6) = self.as_sockaddr_in6() {
sai6.to_socket_addrs()?.next()

} else {
None
};

Ok(opt.into_iter())
}
}

pub(super) mod private {
pub trait SockaddrLikePriv {
/// Returns a mutable raw pointer to the inner structure.
Expand Down Expand Up @@ -2343,6 +2387,15 @@ mod tests {
let ip = SockaddrIn::from_str(s).unwrap().ip();
assert_eq!("127.0.0.1", format!("{ip}"));
}

#[test]
fn tosockaddr() {
let s = "127.0.0.1:8082";
let ip = SockaddrIn::from_str(s).unwrap();
let sa = ip.to_socket_addrs().unwrap()
.next().unwrap();
assert_eq!(s, format!("{sa}"));
}
}

mod sockaddr_in6 {
Expand Down Expand Up @@ -2382,10 +2435,31 @@ mod tests {
let std_sin6: std::net::SocketAddrV6 = nix_sin6.into();
assert_eq!(nix_sin6, std_sin6.into());
}

#[test]
fn tosockaddr() {
let s = "[1234:5678:90ab:cdef::1111:2222]:8080";
let mut nix_sin6 = SockaddrIn6::from_str(s).unwrap();
nix_sin6.0.sin6_flowinfo = 0x12345678;
nix_sin6.0.sin6_scope_id = 0x9abcdef0;

let sa = nix_sin6.to_socket_addrs().unwrap()
.next().unwrap();

if let SocketAddr::V6(v6) = sa {
assert_eq!(nix_sin6.ip(), *v6.ip());
assert_eq!(nix_sin6.port(), v6.port());
assert_eq!(nix_sin6.flowinfo(), v6.flowinfo());
assert_eq!(nix_sin6.scope_id(), v6.scope_id());
} else {
panic!("Unexpected sockaddr type");
};
}
}

mod sockaddr_storage {
use super::*;
use std::str::FromStr;

#[test]
fn from_sockaddr_un_named() {
Expand Down Expand Up @@ -2416,6 +2490,53 @@ mod tests {
.unwrap();
assert_eq!(ss.len(), ua.len());
}

#[test]
fn tosockaddr_v6() {
let s = "[1234:5678:90ab:cdef::1111:2222]:8080";
let mut sai6 = SockaddrIn6::from_str(s).unwrap();
sai6.0.sin6_flowinfo = 0x12345678;
sai6.0.sin6_scope_id = 0x9abcdef0;

let ptr = sai6.as_ptr().cast();
let sas = unsafe { SockaddrStorage::from_raw(ptr, None).unwrap() };

let sa = sas.to_socket_addrs().unwrap()
.next().unwrap();

if let SocketAddr::V6(v6) = sa {
assert_eq!(sai6.ip(), *v6.ip());
assert_eq!(sai6.port(), v6.port());
assert_eq!(sai6.flowinfo(), v6.flowinfo());
assert_eq!(sai6.scope_id(), v6.scope_id());
} else {
panic!("Unexpected sockaddr type");
};
}

#[test]
fn tosockaddr_v4() {
let s = "127.0.0.1:8082";
let ip4 = SockaddrIn::from_str(s).unwrap();

let ptr = ip4.as_ptr().cast();
let sas = unsafe { SockaddrStorage::from_raw(ptr, None).unwrap() };

let sa = sas.to_socket_addrs().unwrap()
.next().unwrap();
assert_eq!(s, format!("{sa}"));
}

#[test]
fn from_sockaddr_unix() {
let ua = UnixAddr::new("/var/run/mysock").unwrap();
let ptr = ua.as_ptr().cast();
let ss = unsafe { SockaddrStorage::from_raw(ptr, Some(ua.len())) }
.unwrap();

let sa = ss.to_socket_addrs().unwrap();
assert_eq!(0, sa.len());
}
}

mod unixaddr {
Expand Down