From 25f85300cd1578466e2ef56fc88829e8ce343945 Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Sat, 31 Jan 2026 11:56:17 +1100 Subject: [PATCH 1/6] Add ToSocketAddrs impls for SockaddrIn & SockaddrIn6, and implement SockaddStorage with them. --- src/sys/socket/addr.rs | 46 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 09be1d68b5..7d52103751 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -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")] @@ -952,6 +952,15 @@ impl std::str::FromStr for SockaddrIn { } } +impl ToSocketAddrs for SockaddrIn { + type Iter = vec::IntoIter; + + fn to_socket_addrs(&self) -> std::io::Result { + let sa = SocketAddr::new(self.ip().into(), self.port()); + Ok(vec![sa].into_iter()) + } +} + /// An IPv6 socket address #[cfg(feature = "net")] #[repr(transparent)] @@ -1102,6 +1111,21 @@ impl std::str::FromStr for SockaddrIn6 { } } +impl ToSocketAddrs for SockaddrIn6 { + type Iter = vec::IntoIter; + + fn to_socket_addrs(&self) -> std::io::Result { + let sa6 = SocketAddrV6::new(self.ip().into(), + 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 @@ -1517,6 +1541,24 @@ impl PartialEq for SockaddrStorage { } } +impl ToSocketAddrs for SockaddrStorage { + type Iter = option::IntoIter; + + fn to_socket_addrs(&self) -> std::io::Result { + 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. From 2743c2980eb10a3aacb76b8cb16e7d81a962b3d1 Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Sat, 31 Jan 2026 12:30:17 +1100 Subject: [PATCH 2/6] Add tests for ToSocketAddrs impls. --- src/sys/socket/addr.rs | 78 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 7d52103751..a98dfe81e4 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -1125,7 +1125,6 @@ impl ToSocketAddrs for SockaddrIn6 { } } - /// A container for any sockaddr type /// /// Just like C's `sockaddr_storage`, this type is large enough to hold any type @@ -2385,6 +2384,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 { @@ -2424,10 +2432,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() { @@ -2458,6 +2487,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 { From 2f86c071700dda85299919a032eb20324205e1cc Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Sat, 31 Jan 2026 12:46:02 +1100 Subject: [PATCH 3/6] Remove redundant conversion --- src/sys/socket/addr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index a98dfe81e4..b492b99acf 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -1115,7 +1115,7 @@ impl ToSocketAddrs for SockaddrIn6 { type Iter = vec::IntoIter; fn to_socket_addrs(&self) -> std::io::Result { - let sa6 = SocketAddrV6::new(self.ip().into(), + let sa6 = SocketAddrV6::new(self.ip(), self.port(), self.flowinfo(), self.scope_id()) From fa578a90711bcaa38483e07114998c0a5804295d Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Sat, 31 Jan 2026 13:00:22 +1100 Subject: [PATCH 4/6] Add missing feature conditionals for ToSocketAddr --- src/sys/socket/addr.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index b492b99acf..5cfb3e695f 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -952,6 +952,7 @@ impl std::str::FromStr for SockaddrIn { } } +#[cfg(feature = "net")] impl ToSocketAddrs for SockaddrIn { type Iter = vec::IntoIter; @@ -1111,6 +1112,7 @@ impl std::str::FromStr for SockaddrIn6 { } } +#[cfg(feature = "net")] impl ToSocketAddrs for SockaddrIn6 { type Iter = vec::IntoIter; @@ -1540,6 +1542,7 @@ impl PartialEq for SockaddrStorage { } } +#[cfg(feature = "net")] impl ToSocketAddrs for SockaddrStorage { type Iter = option::IntoIter; From 3ae9176a0cb6164c99e52fdc2d99d117e4a24b99 Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Sun, 1 Feb 2026 11:10:37 +1100 Subject: [PATCH 5/6] Add ToSocketAddrs to InterfaceAddress --- src/ifaddrs.rs | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/ifaddrs.rs b/src/ifaddrs.rs index 9441141f84..0630256585 100644 --- a/src/ifaddrs.rs +++ b/src/ifaddrs.rs @@ -6,9 +6,10 @@ use cfg_if::cfg_if; #[cfg(apple_targets)] use std::convert::TryFrom; -use std::ffi; +use std::{ffi, option}; use std::iter::Iterator; use std::mem; +use std::net::{SocketAddr, ToSocketAddrs}; use std::option::Option; use crate::net::if_::*; @@ -144,6 +145,19 @@ impl Iterator for InterfaceAddressIterator { } } +impl ToSocketAddrs for InterfaceAddress { + type Iter = option::IntoIter; + + fn to_socket_addrs(&self) -> std::io::Result { + 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 @@ -183,6 +197,8 @@ pub fn getifaddrs() -> Result { #[cfg(test)] mod tests { + use std::net::Ipv4Addr; + use super::*; // Only checks if `getifaddrs` can be invoked without panicking. @@ -214,4 +230,18 @@ 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::>(); + // Assumes a modern *nix must have v4 loopback to work. + assert_eq!(1, with_addrs.len()); + Ok(()) + } + + } From 01d5fa83ff505cbef75b8b0a7998c05719d1dd44 Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Sun, 1 Feb 2026 11:15:08 +1100 Subject: [PATCH 6/6] Fix formatting. --- src/ifaddrs.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/ifaddrs.rs b/src/ifaddrs.rs index 0630256585..ae3a863fe5 100644 --- a/src/ifaddrs.rs +++ b/src/ifaddrs.rs @@ -6,11 +6,11 @@ use cfg_if::cfg_if; #[cfg(apple_targets)] use std::convert::TryFrom; -use std::{ffi, option}; 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}; @@ -157,7 +157,6 @@ impl ToSocketAddrs for InterfaceAddress { } } - /// Get interface addresses using libc's `getifaddrs` /// /// Note that the underlying implementation differs between OSes. Only the @@ -234,14 +233,11 @@ mod tests { #[test] fn test_tosockaddrs() -> Result<()> { let with_addrs = getifaddrs()? - .filter_map(|ifaddr| ifaddr.to_socket_addrs().unwrap() - .next()) + .filter_map(|ifaddr| ifaddr.to_socket_addrs().unwrap().next()) .filter(|sa| sa.ip() == Ipv4Addr::LOCALHOST) .collect::>(); // Assumes a modern *nix must have v4 loopback to work. assert_eq!(1, with_addrs.len()); Ok(()) } - - }