diff options
-rw-r--r-- | CHANGELOG.md | 3 | ||||
-rw-r--r-- | src/ifaddrs.rs | 24 | ||||
-rw-r--r-- | src/lib.rs | 1 | ||||
-rw-r--r-- | src/sys/socket/addr.rs | 1238 | ||||
-rw-r--r-- | src/sys/socket/mod.rs | 197 | ||||
-rw-r--r-- | test/sys/test_socket.rs | 320 | ||||
-rw-r--r-- | test/sys/test_sockopt.rs | 9 |
7 files changed, 1402 insertions, 390 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index e54639b7..737148af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,6 +74,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Changed `getrlimit` and `setrlimit` to use `rlim_t` directly instead of `Option<rlim_t>`. (#[1668](https://github.com/nix-rust/nix/pull/1668)) +- Deprecated `InetAddr` and `SockAddr` in favor of `SockaddrIn`, `SockaddrIn6`, + and `SockaddrStorage`. + (#[1684](https://github.com/nix-rust/nix/pull/1684)) ### Fixed diff --git a/src/ifaddrs.rs b/src/ifaddrs.rs index ed6328f3..f834d307 100644 --- a/src/ifaddrs.rs +++ b/src/ifaddrs.rs @@ -10,7 +10,7 @@ use std::mem; use std::option::Option; use crate::{Result, Errno}; -use crate::sys::socket::SockAddr; +use crate::sys::socket::{SockaddrLike, SockaddrStorage}; use crate::net::if_::*; /// Describes a single address for an interface as returned by `getifaddrs`. @@ -21,13 +21,13 @@ pub struct InterfaceAddress { /// Flags as from `SIOCGIFFLAGS` ioctl pub flags: InterfaceFlags, /// Network address of this interface - pub address: Option<SockAddr>, + pub address: Option<SockaddrStorage>, /// Netmask of this interface - pub netmask: Option<SockAddr>, + pub netmask: Option<SockaddrStorage>, /// Broadcast address of this interface, if applicable - pub broadcast: Option<SockAddr>, + pub broadcast: Option<SockaddrStorage>, /// Point-to-point destination address - pub destination: Option<SockAddr>, + pub destination: Option<SockaddrStorage>, } cfg_if! { @@ -46,8 +46,8 @@ impl InterfaceAddress { /// Create an `InterfaceAddress` from the libc struct. fn from_libc_ifaddrs(info: &libc::ifaddrs) -> InterfaceAddress { let ifname = unsafe { ffi::CStr::from_ptr(info.ifa_name) }; - let address = unsafe { SockAddr::from_libc_sockaddr(info.ifa_addr) }; - let netmask = unsafe { SockAddr::from_libc_sockaddr(info.ifa_netmask) }; + let address = unsafe { SockaddrStorage::from_raw(info.ifa_addr, None) }; + let netmask = unsafe { SockaddrStorage::from_raw(info.ifa_netmask, None) }; let mut addr = InterfaceAddress { interface_name: ifname.to_string_lossy().to_string(), flags: InterfaceFlags::from_bits_truncate(info.ifa_flags as i32), @@ -59,9 +59,9 @@ impl InterfaceAddress { let ifu = get_ifu_from_sockaddr(info); if addr.flags.contains(InterfaceFlags::IFF_POINTOPOINT) { - addr.destination = unsafe { SockAddr::from_libc_sockaddr(ifu) }; + addr.destination = unsafe { SockaddrStorage::from_raw(ifu, None) }; } else if addr.flags.contains(InterfaceFlags::IFF_BROADCAST) { - addr.broadcast = unsafe { SockAddr::from_libc_sockaddr(ifu) }; + addr.broadcast = unsafe { SockaddrStorage::from_raw(ifu, None) }; } addr @@ -103,9 +103,9 @@ impl Iterator for InterfaceAddressIterator { /// Note that the underlying implementation differs between OSes. Only the /// most common address families are supported by the nix crate (due to /// lack of time and complexity of testing). The address family is encoded -/// in the specific variant of `SockAddr` returned for the fields `address`, -/// `netmask`, `broadcast`, and `destination`. For any entry not supported, -/// the returned list will contain a `None` entry. +/// in the specific variant of `SockaddrStorage` returned for the fields +/// `address`, `netmask`, `broadcast`, and `destination`. For any entry not +/// supported, the returned list will contain a `None` entry. /// /// # Example /// ``` @@ -31,6 +31,7 @@ //! * `reboot` - Reboot the system //! * `resource` - Process resource limits //! * `sched` - Manipulate process's scheduling +//! * `socket` - Sockets, whether for networking or local use //! * `signal` - Send and receive signals to processes //! * `term` - Terminal control APIs //! * `time` - Query the operating system's clocks diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 7803ec76..9d22beea 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -34,6 +34,11 @@ pub use self::vsock::VsockAddr; /// These constants specify the protocol family to be used /// in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html) +/// +/// # References +/// +/// [address_families(7)](https://man7.org/linux/man-pages/man7/address_families.7.html) +// Should this be u8? #[repr(i32)] #[non_exhaustive] #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] @@ -68,9 +73,15 @@ pub enum AddressFamily { Ipx = libc::AF_IPX, /// AppleTalk AppleTalk = libc::AF_APPLETALK, + /// AX.25 packet layer protocol. + /// (see [netrom(4)](https://www.unix.com/man-page/linux/4/netrom/)) #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] NetRom = libc::AF_NETROM, + /// Can't be used for creating sockets; mostly used for bridge + /// links in + /// [rtnetlink(7)](https://man7.org/linux/man-pages/man7/rtnetlink.7.html) + /// protocol commands. #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Bridge = libc::AF_BRIDGE, @@ -82,77 +93,108 @@ pub enum AddressFamily { #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] X25 = libc::AF_X25, + /// RATS (Radio Amateur Telecommunications Society) Open + /// Systems environment (ROSE) AX.25 packet layer protocol. + /// (see [netrom(4)](https://www.unix.com/man-page/linux/4/netrom/)) #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Rose = libc::AF_ROSE, + /// DECet protocol sockets. Decnet = libc::AF_DECnet, + /// Reserved for "802.2LLC project"; never used. #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] NetBeui = libc::AF_NETBEUI, + /// This was a short-lived (between Linux 2.1.30 and + /// 2.1.99pre2) protocol family for firewall upcalls. #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Security = libc::AF_SECURITY, + /// Key management protocol. #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Key = libc::AF_KEY, + #[allow(missing_docs)] // Not documented anywhere that I can find #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Ash = libc::AF_ASH, + /// Acorn Econet protocol #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Econet = libc::AF_ECONET, + /// Access to ATM Switched Virtual Circuits #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] AtmSvc = libc::AF_ATMSVC, + /// Reliable Datagram Sockets (RDS) protocol #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Rds = libc::AF_RDS, + /// IBM SNA Sna = libc::AF_SNA, + /// Socket interface over IrDA #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Irda = libc::AF_IRDA, + /// Generic PPP transport layer, for setting up L2 tunnels (L2TP and PPPoE) #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Pppox = libc::AF_PPPOX, + /// Legacy protocol for wide area network (WAN) connectivity that was used + /// by Sangoma WAN cards #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Wanpipe = libc::AF_WANPIPE, + /// Logical link control (IEEE 802.2 LLC) protocol #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Llc = libc::AF_LLC, + /// InfiniBand native addressing #[cfg(all(target_os = "linux", not(target_env = "uclibc")))] #[cfg_attr(docsrs, doc(cfg(all())))] Ib = libc::AF_IB, + /// Multiprotocol Label Switching #[cfg(all(target_os = "linux", not(target_env = "uclibc")))] #[cfg_attr(docsrs, doc(cfg(all())))] Mpls = libc::AF_MPLS, + /// Controller Area Network automotive bus protocol #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Can = libc::AF_CAN, + /// TIPC, "cluster domain sockets" protocol #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Tipc = libc::AF_TIPC, + /// Bluetooth low-level socket protocol #[cfg(not(any(target_os = "illumos", target_os = "ios", target_os = "macos", target_os = "solaris")))] #[cfg_attr(docsrs, doc(cfg(all())))] Bluetooth = libc::AF_BLUETOOTH, + /// IUCV (inter-user communication vehicle) z/VM protocol for + /// hypervisor-guest interaction #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Iucv = libc::AF_IUCV, + /// Rx, Andrew File System remote procedure call protocol #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] RxRpc = libc::AF_RXRPC, + /// New "modular ISDN" driver interface protocol #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] #[cfg_attr(docsrs, doc(cfg(all())))] Isdn = libc::AF_ISDN, + /// Nokia cellular modem IPC/RPC interface #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Phonet = libc::AF_PHONET, + /// IEEE 802.15.4 WPAN (wireless personal area network) raw packet protocol #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Ieee802154 = libc::AF_IEEE802154, + /// Ericsson's Communication CPU to Application CPU interface (CAIF) + /// protocol. #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Caif = libc::AF_CAIF, @@ -160,12 +202,15 @@ pub enum AddressFamily { #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Alg = libc::AF_ALG, + /// Near field communication #[cfg(target_os = "linux")] #[cfg_attr(docsrs, doc(cfg(all())))] Nfc = libc::AF_NFC, + /// VMWare VSockets protocol for hypervisor-guest interaction. #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] Vsock = libc::AF_VSOCK, + /// ARPANet IMP addresses #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -174,6 +219,7 @@ pub enum AddressFamily { target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] ImpLink = libc::AF_IMPLINK, + /// PUP protocols, e.g. BSP #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -182,6 +228,7 @@ pub enum AddressFamily { target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] Pup = libc::AF_PUP, + /// MIT CHAOS protocols #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -190,12 +237,14 @@ pub enum AddressFamily { target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] Chaos = libc::AF_CHAOS, + /// Novell and Xerox protocol #[cfg(any(target_os = "ios", target_os = "macos", target_os = "netbsd", target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] Ns = libc::AF_NS, + #[allow(missing_docs)] // Not documented anywhere that I can find #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -204,6 +253,7 @@ pub enum AddressFamily { target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] Iso = libc::AF_ISO, + /// Bell Labs virtual circuit switch ? #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -212,6 +262,7 @@ pub enum AddressFamily { target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] Datakit = libc::AF_DATAKIT, + /// CCITT protocols, X.25 etc #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -220,6 +271,7 @@ pub enum AddressFamily { target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] Ccitt = libc::AF_CCITT, + /// DEC Direct data link interface #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -228,6 +280,7 @@ pub enum AddressFamily { target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] Dli = libc::AF_DLI, + #[allow(missing_docs)] // Not documented anywhere that I can find #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -236,6 +289,7 @@ pub enum AddressFamily { target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] Lat = libc::AF_LAT, + /// NSC Hyperchannel #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -244,6 +298,7 @@ pub enum AddressFamily { target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] Hylink = libc::AF_HYLINK, + /// Link layer interface #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -253,6 +308,7 @@ pub enum AddressFamily { target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] Link = libc::AF_LINK, + /// connection-oriented IP, aka ST II #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -261,6 +317,7 @@ pub enum AddressFamily { target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] Coip = libc::AF_COIP, + /// Computer Network Technology #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -269,6 +326,7 @@ pub enum AddressFamily { target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] Cnt = libc::AF_CNT, + /// Native ATM access #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", @@ -318,12 +376,19 @@ impl AddressFamily { feature! { #![feature = "net"] +#[deprecated( + since = "0.24.0", + note = "use SockaddrIn, SockaddrIn6, or SockaddrStorage instead" +)] +#[allow(missing_docs)] // Since they're all deprecated anyway #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum InetAddr { V4(libc::sockaddr_in), V6(libc::sockaddr_in6), } +#[allow(missing_docs)] // It's deprecated anyway +#[allow(deprecated)] impl InetAddr { #[allow(clippy::needless_update)] // It isn't needless on all OSes pub fn from_std(std: &net::SocketAddr) -> InetAddr { @@ -417,6 +482,7 @@ impl InetAddr { } } +#[allow(deprecated)] impl fmt::Display for InetAddr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { @@ -431,12 +497,14 @@ impl fmt::Display for InetAddr { * ===== IpAddr ===== * */ +#[allow(missing_docs)] // https://github.com/nix-rust/nix/issues/1681 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum IpAddr { V4(Ipv4Addr), V6(Ipv6Addr), } +#[allow(missing_docs)] // https://github.com/nix-rust/nix/issues/1681 impl IpAddr { /// Create a new IpAddr that contains an IPv4 address. /// @@ -484,10 +552,12 @@ impl fmt::Display for IpAddr { * */ +#[allow(missing_docs)] // https://github.com/nix-rust/nix/issues/1681 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[repr(transparent)] pub struct Ipv4Addr(pub libc::in_addr); +#[allow(missing_docs)] // https://github.com/nix-rust/nix/issues/1681 impl Ipv4Addr { #[allow(clippy::identity_op)] // More readable this way pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { @@ -534,6 +604,7 @@ impl fmt::Display for Ipv4Addr { * */ +#[allow(missing_docs)] // https://github.com/nix-rust/nix/issues/1681 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[repr(transparent)] pub struct Ipv6Addr(pub libc::in6_addr); @@ -554,6 +625,7 @@ macro_rules! to_u16_array { } } +#[allow(missing_docs)] // https://github.com/nix-rust/nix/issues/1681 impl Ipv6Addr { #[allow(clippy::many_single_char_names)] #[allow(clippy::too_many_arguments)] @@ -586,6 +658,7 @@ impl fmt::Display for Ipv6Addr { /// A wrapper around `sockaddr_un`. #[derive(Clone, Copy, Debug)] +#[repr(C)] pub struct UnixAddr { // INVARIANT: sun & sun_len are valid as defined by docs for from_raw_parts sun: libc::sockaddr_un, @@ -799,6 +872,56 @@ impl UnixAddr { } } +impl private::SockaddrLikePriv for UnixAddr {} +impl SockaddrLike for UnixAddr { + #[cfg(any(target_os = "android", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux" + ))] + fn len(&self) -> libc::socklen_t { + self.sun_len.into() + } + + unsafe fn from_raw(addr: *const libc::sockaddr, len: Option<libc::socklen_t>) + -> Option<Self> where Self: Sized + { + if let Some(l) = len { + if (l as usize) < offset_of!(libc::sockaddr_un, sun_path) || + l > u8::MAX as libc::socklen_t + { + return None; + } + } + if (*addr).sa_family as i32 != libc::AF_UNIX as i32 { + return None; + } + let mut su: libc::sockaddr_un = mem::zeroed(); + let sup = &mut su as *mut libc::sockaddr_un as *mut u8; + cfg_if!{ + if #[cfg(any(target_os = "android", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux" + ))] { + let su_len = len.unwrap_or( + mem::size_of::<libc::sockaddr_un>() as libc::socklen_t + ); + } else { + let su_len = len.unwrap_or((*addr).sa_len as libc::socklen_t); + } + }; + ptr::copy(addr as *const u8, sup, su_len as usize); + Some(Self::from_raw_parts(su, su_len as u8)) + } +} + +impl AsRef<libc::sockaddr_un> for UnixAddr { + fn as_ref(&self) -> &libc::sockaddr_un { + &self.sun + } +} + #[cfg(any(target_os = "android", target_os = "linux"))] fn fmt_abstract(abs: &[u8], f: &mut fmt::Formatter) -> fmt::Result { use fmt::Write; @@ -836,8 +959,699 @@ impl Hash for UnixAddr { } } +/// Anything that, in C, can be cast back and forth to `sockaddr`. +/// +/// Most implementors also implement `AsRef<libc::XXX>` to access their +/// inner type read-only. +#[allow(clippy::len_without_is_empty)] +pub trait SockaddrLike: private::SockaddrLikePriv { + /// Returns a raw pointer to the inner structure. Useful for FFI. + fn as_ptr(&self) -> *const libc::sockaddr { + self as *const Self as *const libc::sockaddr + } + + /// Unsafe constructor from a variable length source + /// + /// Some C APIs from provide `len`, and others do not. If it's provided it + /// will be validated. If not, it will be guessed based on the family. + /// + /// # Safety + /// + /// `addr` must be valid for the specific type of sockaddr. `len`, if + /// present, must be the length of valid data in `addr`. + unsafe fn from_raw(addr: *const libc::sockaddr, len: Option<libc::socklen_t>) + -> Option<Self> where Self: Sized; + + /// Return the address family of this socket + /// + /// # Examples + /// One common use is to match on the family of a union type, like this: + /// ``` + /// # use nix::sys::socket::*; + /// let fd = socket(AddressFamily::Inet, SockType::Stream, + /// SockFlag::empty(), None).unwrap(); + /// let ss: SockaddrStorage = getsockname(fd).unwrap(); + /// match ss.family().unwrap() { + /// AddressFamily::Inet => println!("{}", ss.as_sockaddr_in().unwrap()), + /// AddressFamily::Inet6 => println!("{}", ss.as_sockaddr_in6().unwrap()), + /// _ => println!("Unexpected address family") + /// } + /// ``` + fn family(&self) -> Option<AddressFamily> { + // Safe since all implementors have a sa_family field at the same + // address, and they're all repr(C) + AddressFamily::from_i32( + unsafe { + (*(self as *const Self as *const libc::sockaddr)).sa_family as i32 + } + ) + } + + cfg_if! { + if #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] { + /// Return the length of valid data in the sockaddr structure. + /// + /// For fixed-size sockaddrs, this should be the size of the + /// structure. But for variable-sized types like [`UnixAddr`] it + /// may be less. + fn len(&self) -> libc::socklen_t { + // Safe since all implementors have a sa_len field at the same + // address, and they're all repr(transparent). + // Robust for all implementors. + unsafe { + (*(self as *const Self as *const libc::sockaddr)).sa_len + }.into() + } + } else { + /// Return the length of valid data in the sockaddr structure. + /// + /// For fixed-size sockaddrs, this should be the size of the + /// structure. But for variable-sized types like [`UnixAddr`] it + /// may be less. + fn len(&self) -> libc::socklen_t { + // No robust default implementation is possible without an + // sa_len field. Implementors with a variable size must + // override this method. + mem::size_of_val(self) as libc::socklen_t + } + } + } + + /// Return the available space in the structure + fn size() -> libc::socklen_t where Self: Sized { + mem::size_of::<Self>() as libc::socklen_t + } +} + +impl private::SockaddrLikePriv for () { + fn as_mut_ptr(&mut self) -> *mut libc::sockaddr { + ptr::null_mut() + } +} + +/// `()` can be used in place of a real Sockaddr when no address is expected, +/// for example for a field of `Option<S> where S: SockaddrLike`. +// If this RFC ever stabilizes, then ! will be a better choice. +// https://github.com/rust-lang/rust/issues/35121 +impl SockaddrLike for () { + fn as_ptr(&self) -> *const libc::sockaddr { + ptr::null() + } + + unsafe fn from_raw(_: *const libc::sockaddr, _: Option<libc::socklen_t>) + -> Option<Self> where Self: Sized + { + None + } + + fn family(&self) -> Option<AddressFamily> { + None + } + + fn len(&self) -> libc::socklen_t { + 0 + } +} + +/// An IPv4 socket address +// This is identical to net::SocketAddrV4. But the standard library +// doesn't allow direct access to the libc fields, which we need. So we +// reimplement it here. +#[cfg(feature = "net")] +#[repr(transparent)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct SockaddrIn(libc::sockaddr_in); + +#[cfg(feature = "net")] +impl SockaddrIn { + /// Returns the IP address associated with this socket address, in native + /// endian. + pub const fn ip(&self) -> libc::in_addr_t { + u32::from_be(self.0.sin_addr.s_addr) + } + + /// Creates a new socket address from IPv4 octets and a port number. + pub fn new(a: u8, b: u8, c: u8, d: u8, port: u16) -> Self { + Self(libc::sockaddr_in { + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + sin_len: Self::size() as u8, + sin_family: AddressFamily::Inet as sa_family_t, + sin_port: u16::to_be(port), + sin_addr: libc::in_addr { + s_addr: u32::from_ne_bytes([a, b, c, d]) + }, + sin_zero: unsafe{mem::zeroed()} + }) + } + + /// Returns the port number associated with this socket address, in native + /// endian. + pub const fn port(&self) -> u16 { + u16::from_be(self.0.sin_port) + } +} + +#[cfg(feature = "net")] +impl private::SockaddrLikePriv for SockaddrIn {} +#[cfg(feature = "net")] +impl SockaddrLike for SockaddrIn { + unsafe fn from_raw(addr: *const libc::sockaddr, len: Option<libc::socklen_t>) + -> Option<Self> where Self: Sized + { + if let Some(l) = len { + if l != mem::size_of::<libc::sockaddr_in>() as libc::socklen_t { + return None; + } + } + if (*addr).sa_family as i32 != libc::AF_INET as i32 { + return None; + } + Some(SockaddrIn(*(addr as *const libc::sockaddr_in))) + } +} + +#[cfg(feature = "net")] +impl AsRef<libc::sockaddr_in> for SockaddrIn { + fn as_ref(&self) -> &libc::sockaddr_in { + &self.0 + } +} + +#[cfg(feature = "net")] +impl fmt::Display for SockaddrIn { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let ne = u32::from_be(self.0.sin_addr.s_addr); + let port = u16::from_be(self.0.sin_port); + write!(f, "{}.{}.{}.{}:{}", + ne >> 24, + (ne >> 16) & 0xFF, + (ne >> 8) & 0xFF, + ne & 0xFF, + port) + } +} + +#[cfg(feature = "net")] +impl From<net::SocketAddrV4> for SockaddrIn { + fn from(addr: net::SocketAddrV4) -> Self { + Self(libc::sockaddr_in{ + #[cfg(any(target_os = "dragonfly", target_os = "freebsd", + target_os = "haiku", target_os = "hermit", + target_os = "ios", target_os = "macos", + target_os = "netbsd", target_os = "openbsd"))] + sin_len: mem::size_of::<libc::sockaddr_in>() as u8, + sin_family: AddressFamily::Inet as sa_family_t, + sin_port: addr.port().to_be(), // network byte order + sin_addr: Ipv4Addr::from_std(addr.ip()).0, + .. unsafe { mem::zeroed() } + }) + } +} + +#[cfg(feature = "net")] +impl std::str::FromStr for SockaddrIn { + type Err = net::AddrParseError; + + fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { + net::SocketAddrV4::from_str(s).map(SockaddrIn::from) + } +} + +/// An IPv6 socket address +#[cfg(feature = "net")] +#[repr(transparent)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct SockaddrIn6(libc::sockaddr_in6); + +#[cfg(feature = "net")] +impl SockaddrIn6 { + /// Returns the flow information associated with this address. + pub const fn flowinfo(&self) -> u32 { + self.0.sin6_flowinfo + } + + /// Returns the IP address associated with this socket address. + pub fn ip(&self) -> net::Ipv6Addr { + net::Ipv6Addr::from(self.0.sin6_addr.s6_addr) + } + + /// Returns the port number associated with this socket address, in native + /// endian. + pub const fn port(&self) -> u16 { + u16::from_be(self.0.sin6_port) + } + + /// Returns the scope ID associated with this address. + pub const fn scope_id(&self) -> u32 { + self.0.sin6_scope_id + } +} + +#[cfg(feature = "net")] +impl private::SockaddrLikePriv for SockaddrIn6 {} +#[cfg(feature = "net")] +impl SockaddrLike for SockaddrIn6 { + unsafe fn from_raw(addr: *const libc::sockaddr, len: Option<libc::socklen_t>) + -> Option<Self> where Self: Sized + { + if let Some(l) = len { + if l != mem::size_of::<libc::sockaddr_in6>() as libc::socklen_t { + return None; + } + } + if (*addr).sa_family as i32 != libc::AF_INET6 as i32 { + return None; + } + Some(SockaddrIn6(*(addr as *const libc::sockaddr_in6))) + } +} + +#[cfg(feature = "net")] +impl AsRef<libc::sockaddr_in6> for SockaddrIn6 { + fn as_ref(&self) -> &libc::sockaddr_in6 { + &self.0 + } +} + +#[cfg(feature = "net")] +impl fmt::Display for SockaddrIn6 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // These things are really hard to display properly. Easier to let std + // do it. + let std = net::SocketAddrV6::new(self.ip(), self.port(), + self.flowinfo(), self.scope_id()); + std.fmt(f) + } +} + +#[cfg(feature = "net")] +impl From<net::SocketAddrV6> for SockaddrIn6 { + fn from(addr: net::SocketAddrV6) -> Self { + #[allow(clippy::needless_update)] // It isn't needless on Illumos + Self(libc::sockaddr_in6{ + #[cfg(any(target_os = "dragonfly", target_os = "freebsd", + target_os = "haiku", target_os = "hermit", + target_os = "ios", target_os = "macos", + target_os = "netbsd", target_os = "openbsd"))] + sin6_len: mem::size_of::<libc::sockaddr_in6>() as u8, + sin6_family: AddressFamily::Inet6 as sa_family_t, + sin6_port: addr.port().to_be(), // network byte order + sin6_addr: Ipv6Addr::from_std(addr.ip()).0, + sin6_flowinfo: addr.flowinfo(), // host byte order + sin6_scope_id: addr.scope_id(), // host byte order + .. unsafe { mem::zeroed() } + }) + } +} + +#[cfg(feature = "net")] +impl std::str::FromStr for SockaddrIn6 { + type Err = net::AddrParseError; + + fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { + net::SocketAddrV6::from_str(s).map(SockaddrIn6::from) + } +} + + +/// A container for any sockaddr type +/// +/// Just like C's `sockaddr_storage`, this type is large enough to hold any type +/// of sockaddr. It can be used as an argument with functions like +/// [`bind`](super::bind) and [`getsockname`](super::getsockname). Though it is +/// a union, it can be safely accessed through the `as_*` methods. +/// +/// # Example +/// ``` +/// # use nix::sys::socket::*; +/// # use std::str::FromStr; +/// let localhost = SockaddrIn::from_str("127.0.0.1:8081").unwrap(); +/// let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), +/// None).unwrap(); +/// bind(fd, &localhost).expect("bind"); +/// let ss: SockaddrStorage = getsockname(fd).expect("getsockname"); +/// assert_eq!(&localhost, ss.as_sockaddr_in().unwrap()); +/// ``` +#[derive(Clone, Copy, Eq)] +#[repr(C)] +pub union SockaddrStorage { + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + alg: AlgAddr, + #[cfg(feature = "net")] + #[cfg_attr(docsrs, doc(cfg(feature = "net")))] + dl: LinkAddr, + #[cfg(any(target_os = "android", target_os = "linux"))] + nl: NetlinkAddr, + #[cfg(all(feature = "ioctl", any(target_os = "ios", target_os = "macos")))] + #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] + sctl: SysControlAddr, + #[cfg(feature = "net")] + sin: SockaddrIn, + #[cfg(feature = "net")] + sin6: SockaddrIn6, + ss: libc::sockaddr_storage, + su: UnixAddr, + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + vsock: VsockAddr +} +impl private::SockaddrLikePriv for SockaddrStorage {} +impl SockaddrLike for SockaddrStorage { + unsafe fn from_raw(addr: *const libc::sockaddr, l: Option<libc::socklen_t>) + -> Option<Self> where Self: Sized + { + if addr.is_null() { + return None; + } + if let Some(len) = l { + let ulen = len as usize; + if ulen < offset_of!(libc::sockaddr, sa_data) || + ulen > mem::size_of::<libc::sockaddr_storage>() { + None + } else{ + let mut ss: libc::sockaddr_storage = mem::zeroed(); + let ssp = &mut ss as *mut libc::sockaddr_storage as *mut u8; + ptr::copy(addr as *const u8, ssp, len as usize); + Some(Self{ss}) + } + } else { + // If length is not available and addr is of a fixed-length type, + // copy it. If addr is of a variable length type and len is not + // available, then there's nothing we can do. + match (*addr).sa_family as i32 { + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_ALG => AlgAddr::from_raw(addr, l) + .map(|alg| Self { alg}), + #[cfg(feature = "net")] + libc::AF_INET => SockaddrIn::from_raw(addr, l) + .map(|sin| Self{ sin}), + #[cfg(feature = "net")] + libc::AF_INET6 => SockaddrIn6::from_raw(addr, l) + .map(|sin6| Self{ sin6}), + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd"))] + #[cfg(feature = "net")] + libc::AF_LINK => LinkAddr::from_raw(addr, l) + .map(|dl| Self{ dl}), + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_NETLINK => NetlinkAddr::from_raw(addr, l) + .map(|nl| Self{ nl }), + #[cfg(any(target_os = "android", + target_os = "fuchsia", + target_os = "linux" + ))] + #[cfg(feature = "net")] + libc::AF_PACKET => LinkAddr::from_raw(addr, l) + .map(|dl| Self{ dl}), + #[cfg(all(feature = "ioctl", + any(target_os = "ios", target_os = "macos")))] + libc::AF_SYSTEM => SysControlAddr::from_raw(addr, l) + .map(|sctl| Self {sctl}), + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_VSOCK => VsockAddr::from_raw(addr, l) + .map(|vsock| Self{vsock}), + _ => None + } + } + } +} + +macro_rules! accessors { + ( + $fname:ident, + $fname_mut:ident, + $sockty:ty, + $family:expr, + $libc_ty:ty, + $field:ident) => + { + /// Safely and falliably downcast to an immutable reference + pub fn $fname(&self) -> Option<&$sockty> { + if self.family() == Some($family) && + self.len() >= mem::size_of::<$libc_ty>() as libc::socklen_t + { + // Safe because family and len are validated + Some(unsafe{&self.$field}) + } else { + None + } + } + + /// Safely and falliably downcast to a mutable reference + pub fn $fname_mut(&mut self) -> Option<&mut $sockty> { + if self.family() == Some($family) && + self.len() >= mem::size_of::<$libc_ty>() as libc::socklen_t + { + // Safe because family and len are validated + Some(unsafe{&mut self.$field}) + } else { + None + } + } + } +} + +impl SockaddrStorage { + #[cfg(any(target_os = "android", target_os = "linux"))] + accessors!{as_alg_addr, as_alg_addr_mut, AlgAddr, + AddressFamily::Alg, libc::sockaddr_alg, alg} + + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd"))] + #[cfg(feature = "net")] + accessors!{ + as_link_addr, as_link_addr_mut, LinkAddr, + AddressFamily::Link, libc::sockaddr_dl, dl} + + #[cfg(feature = "net")] + accessors!{ + as_sockaddr_in, as_sockaddr_in_mut, SockaddrIn, + AddressFamily::Inet, libc::sockaddr_in, sin} + + #[cfg(feature = "net")] + accessors!{ + as_sockaddr_in6, as_sockaddr_in6_mut, SockaddrIn6, + AddressFamily::Inet6, libc::sockaddr_in6, sin6} + + #[cfg(any(target_os = "android", target_os = "linux"))] + accessors!{as_netlink_addr, as_netlink_addr_mut, NetlinkAddr, + AddressFamily::Netlink, libc::sockaddr_nl, nl} + + #[cfg(all(feature = "ioctl", any(target_os = "ios", target_os = "macos")))] + #[cfg_attr(docsrs, doc(cfg(feature = "ioctl")))] + accessors!{as_sys_control_addr, as_sys_control_addr_mut, SysControlAddr, + AddressFamily::System, libc::sockaddr_ctl, sctl} + + #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(all())))] + accessors!{as_vsock_addr, as_vsock_addr_mut, VsockAddr, + AddressFamily::Vsock, libc::sockaddr_vm, vsock} +} + +impl fmt::Debug for SockaddrStorage { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("SockaddrStorage") + // Safe because sockaddr_storage has the least specific + // field types + .field("ss", unsafe{&self.ss}) + .finish() + } +} + +impl fmt::Display for SockaddrStorage { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + unsafe { + match self.ss.ss_family as i32 { + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_ALG => self.alg.fmt(f), + #[cfg(feature = "net")] + libc::AF_INET => self.sin.fmt(f), + #[cfg(feature = "net")] + libc::AF_INET6 => self.sin6.fmt(f), + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd"))] + #[cfg(feature = "net")] + libc::AF_LINK => self.dl.fmt(f), + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_NETLINK => self.nl.fmt(f), + #[cfg(any(target_os = "android", + target_os = "linux", + target_os = "fuchsia" + ))] + #[cfg(feature = "net")] + libc::AF_PACKET => self.dl.fmt(f), + #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(feature = "ioctl")] + libc::AF_SYSTEM => self.sctl.fmt(f), + libc::AF_UNIX => self.su.fmt(f), + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_VSOCK => self.vsock.fmt(f), + _ => "<Address family unspecified>".fmt(f) + } + } + } +} + +#[cfg(feature = "net")] +impl From<net::SocketAddrV4> for SockaddrStorage { + fn from(s: net::SocketAddrV4) -> Self { + unsafe { + let mut ss: Self = mem::zeroed(); + ss.sin = SockaddrIn::from(s); + ss + } + } +} + +#[cfg(feature = "net")] +impl From<net::SocketAddrV6> for SockaddrStorage { + fn from(s: net::SocketAddrV6) -> Self { + unsafe { + let mut ss: Self = mem::zeroed(); + ss.sin6 = SockaddrIn6::from(s); + ss + } + } +} + +#[cfg(feature = "net")] +impl From<net::SocketAddr> for SockaddrStorage { + fn from(s: net::SocketAddr) -> Self { + match s { + net::SocketAddr::V4(sa4) => Self::from(sa4), + net::SocketAddr::V6(sa6) => Self::from(sa6), + } + } +} + +impl Hash for SockaddrStorage { + fn hash<H: Hasher>(&self, s: &mut H) { + unsafe { + match self.ss.ss_family as i32 { + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_ALG => self.alg.hash(s), + #[cfg(feature = "net")] + libc::AF_INET => self.sin.hash(s), + #[cfg(feature = "net")] + libc::AF_INET6 => self.sin6.hash(s), + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd"))] + #[cfg(feature = "net")] + libc::AF_LINK => self.dl.hash(s), + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_NETLINK => self.nl.hash(s), + #[cfg(any(target_os = "android", + target_os = "linux", + target_os = "fuchsia" + ))] + #[cfg(feature = "net")] + libc::AF_PACKET => self.dl.hash(s), + #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(feature = "ioctl")] + libc::AF_SYSTEM => self.sctl.hash(s), + libc::AF_UNIX => self.su.hash(s), + #[cfg(any(target_os = "android", target_os = "linux"))] + libc::AF_VSOCK => self.vsock.hash(s), + _ => self.ss.hash(s) + } + } + } +} + +impl PartialEq for SockaddrStorage { + fn eq(&self, other: &Self) -> bool { + unsafe { + match (self.ss.ss_family as i32, other.ss.ss_family as i32) { + #[cfg(any(target_os = "android", target_os = "linux"))] + (libc::AF_ALG, libc::AF_ALG) => self.alg == other.alg, + #[cfg(feature = "net")] + (libc::AF_INET, libc::AF_INET) => self.sin == other.sin, + #[cfg(feature = "net")] + (libc::AF_INET6, libc::AF_INET6) => self.sin6 == other.sin6, + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd"))] + #[cfg(feature = "net")] + (libc::AF_LINK, libc::AF_LINK) => self.dl == other.dl, + #[cfg(any(target_os = "android", target_os = "linux"))] + (libc::AF_NETLINK, libc::AF_NETLINK) => self.nl == other.nl, + #[cfg(any(target_os = "android", + target_os = "fuchsia", + target_os = "linux" + ))] + #[cfg(feature = "net")] + (libc::AF_PACKET, libc::AF_PACKET) => self.dl == other.dl, + #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(feature = "ioctl")] + (libc::AF_SYSTEM, libc::AF_SYSTEM) => self.sctl == other.sctl, + (libc::AF_UNIX, libc::AF_UNIX) => self.su == other.su, + #[cfg(any(target_os = "android", target_os = "linux"))] + (libc::AF_VSOCK, libc::AF_VSOCK) => self.vsock == other.vsock, + _ => false, + } + } + } +} + +mod private { + pub trait SockaddrLikePriv { + /// Returns a mutable raw pointer to the inner structure. + /// + /// # Safety + /// + /// This method is technically safe, but modifying the inner structure's + /// `family` or `len` fields may result in violating Nix's invariants. + /// It is best to use this method only with foreign functions that do + /// not change the sockaddr type. + fn as_mut_ptr(&mut self) -> *mut libc::sockaddr { + self as *mut Self as *mut libc::sockaddr + } + } +} + /// Represents a socket address #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[deprecated( + since = "0.24.0", + note = "use SockaddrLike or SockaddrStorage instead" +)] +#[allow(missing_docs)] // Since they're all deprecated anyway +#[allow(deprecated)] #[non_exhaustive] pub enum SockAddr { #[cfg(feature = "net")] @@ -871,6 +1685,8 @@ pub enum SockAddr { Vsock(VsockAddr), } +#[allow(missing_docs)] // Since they're all deprecated anyway +#[allow(deprecated)] impl SockAddr { feature! { #![feature = "net"] @@ -1099,6 +1915,7 @@ impl SockAddr { } } +#[allow(deprecated)] impl fmt::Display for SockAddr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { @@ -1129,18 +1946,41 @@ impl fmt::Display for SockAddr { } } +#[cfg(not(target_os = "fuchsia"))] +#[cfg(feature = "net")] +#[allow(deprecated)] +impl private::SockaddrLikePriv for SockAddr {} +#[cfg(not(target_os = "fuchsia"))] +#[cfg(feature = "net")] +#[allow(deprecated)] +impl SockaddrLike for SockAddr { + unsafe fn from_raw(addr: *const libc::sockaddr, _len: Option<libc::socklen_t>) + -> Option<Self> + { + Self::from_libc_sockaddr(addr) + } +} + #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] pub mod netlink { use crate::sys::socket::addr::AddressFamily; use libc::{sa_family_t, sockaddr_nl}; use std::{fmt, mem}; + use super::*; + /// Address for the Linux kernel user interface device. + /// + /// # References + /// + /// [netlink(7)](https://man7.org/linux/man-pages/man7/netlink.7.html) #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] #[repr(transparent)] pub struct NetlinkAddr(pub(in super::super) sockaddr_nl); impl NetlinkAddr { + /// Construct a new socket address from its port ID and multicast groups + /// mask. pub fn new(pid: u32, groups: u32) -> NetlinkAddr { let mut addr: sockaddr_nl = unsafe { mem::zeroed() }; addr.nl_family = AddressFamily::Netlink as sa_family_t; @@ -1150,15 +1990,40 @@ pub mod netlink { NetlinkAddr(addr) } + /// Return the socket's port ID. pub const fn pid(&self) -> u32 { self.0.nl_pid } + /// Return the socket's multicast groups mask pub const fn groups(&self) -> u32 { self.0.nl_groups } } + impl private::SockaddrLikePriv for NetlinkAddr {} + impl SockaddrLike for NetlinkAddr { + unsafe fn from_raw(addr: *const libc::sockaddr, len: Option<libc::socklen_t>) + -> Option<Self> where Self: Sized + { + if let Some(l) = len { + if l != mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t { + return None; + } + } + if (*addr).sa_family as i32 != libc::AF_NETLINK as i32 { + return None; + } + Some(NetlinkAddr(*(addr as *const libc::sockaddr_nl))) + } + } + + impl AsRef<libc::sockaddr_nl> for NetlinkAddr { + fn as_ref(&self) -> &libc::sockaddr_nl { + &self.0 + } + } + impl fmt::Display for NetlinkAddr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "pid: {} groups: {}", self.pid(), self.groups()) @@ -1173,11 +2038,36 @@ pub mod alg { use std::{fmt, mem, str}; use std::hash::{Hash, Hasher}; use std::ffi::CStr; + use super::*; + /// Socket address for the Linux kernel crypto API #[derive(Copy, Clone)] #[repr(transparent)] pub struct AlgAddr(pub(in super::super) sockaddr_alg); + impl private::SockaddrLikePriv for AlgAddr {} + impl SockaddrLike for AlgAddr { + unsafe fn from_raw(addr: *const libc::sockaddr, l: Option<libc::socklen_t>) + -> Option<Self> where Self: Sized + { + if let Some(l) = l { + if l != mem::size_of::<libc::sockaddr_alg>() as libc::socklen_t { + return None; + } + } + if (*addr).sa_family as i32 != libc::AF_ALG as i32 { + return None; + } + Some(AlgAddr(*(addr as *const libc::sockaddr_alg))) + } + } + + impl AsRef<libc::sockaddr_alg> for AlgAddr { + fn as_ref(&self) -> &libc::sockaddr_alg { + &self.0 + } + } + // , PartialEq, Eq, Debug, Hash impl PartialEq for AlgAddr { fn eq(&self, other: &Self) -> bool { @@ -1197,6 +2087,7 @@ pub mod alg { } impl AlgAddr { + /// Construct an `AF_ALG` socket from its cipher name and type. pub fn new(alg_type: &str, alg_name: &str) -> AlgAddr { let mut addr: sockaddr_alg = unsafe { mem::zeroed() }; addr.salg_family = AF_ALG as u16; @@ -1207,10 +2098,12 @@ pub mod alg { } + /// Return the socket's cipher type, for example `hash` or `aead`. pub fn alg_type(&self) -> &CStr { unsafe { CStr::from_ptr(self.0.salg_type.as_ptr() as *const c_char) } } + /// Return the socket's cipher name, for example `sha1`. pub fn alg_name(&self) -> &CStr { unsafe { CStr::from_ptr(self.0.salg_name.as_ptr() as *const c_char) } } @@ -1240,6 +2133,7 @@ pub mod sys_control { use std::{fmt, mem}; use std::os::unix::io::RawFd; use crate::{Errno, Result}; + use super::{private, SockaddrLike}; // FIXME: Move type into `libc` #[repr(C)] @@ -1256,11 +2150,41 @@ pub mod sys_control { ioctl_readwrite!(ctl_info, CTL_IOC_MAGIC, CTL_IOC_INFO, ctl_ioc_info); + /// Apple system control socket + /// + /// # References + /// + /// https://developer.apple.com/documentation/kernel/sockaddr_ctl #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[repr(transparent)] pub struct SysControlAddr(pub(in super::super) libc::sockaddr_ctl); + impl private::SockaddrLikePriv for SysControlAddr {} + impl SockaddrLike for SysControlAddr { + unsafe fn from_raw(addr: *const libc::sockaddr, len: Option<libc::socklen_t>) + -> Option<Self> where Self: Sized + { + if let Some(l) = len { + if l != mem::size_of::<libc::sockaddr_ctl>() as libc::socklen_t { + return None; + } + } + if (*addr).sa_family as i32 != libc::AF_INET6 as i32 { + return None; + } + Some(SysControlAddr(*(addr as *const libc::sockaddr_ctl))) + } + } + + impl AsRef<libc::sockaddr_ctl> for SysControlAddr { + fn as_ref(&self) -> &libc::sockaddr_ctl { + &self.0 + } + } + impl SysControlAddr { + /// Construct a new `SysControlAddr` from its kernel unique identifier + /// and unit number. pub const fn new(id: u32, unit: u32) -> SysControlAddr { let addr = libc::sockaddr_ctl { sc_len: mem::size_of::<libc::sockaddr_ctl>() as c_uchar, @@ -1274,6 +2198,8 @@ pub mod sys_control { SysControlAddr(addr) } + /// Construct a new `SysControlAddr` from its human readable name and + /// unit number. pub fn from_name(sockfd: RawFd, name: &str, unit: u32) -> Result<SysControlAddr> { if name.len() > MAX_KCTL_NAME { return Err(Errno::ENAMETOOLONG); @@ -1288,10 +2214,12 @@ pub mod sys_control { Ok(SysControlAddr::new(info.ctl_id, unit)) } + /// Return the kernel unique identifier pub const fn id(&self) -> u32 { self.0.sc_id } + /// Return the kernel controller private unit number. pub const fn unit(&self) -> u32 { self.0.sc_unit } @@ -1311,7 +2239,7 @@ pub mod sys_control { mod datalink { feature! { #![feature = "net"] - use super::{fmt, AddressFamily}; + use super::{fmt, mem, private, SockaddrLike}; /// Hardware Address #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -1319,12 +2247,6 @@ mod datalink { pub struct LinkAddr(pub(in super::super) libc::sockaddr_ll); impl LinkAddr { - /// Always AF_PACKET - pub fn family(&self) -> AddressFamily { - assert_eq!(self.0.sll_family as i32, libc::AF_PACKET); - AddressFamily::Packet - } - /// Physical-layer protocol pub fn protocol(&self) -> u16 { self.0.sll_protocol @@ -1379,6 +2301,30 @@ mod datalink { } } } + impl private::SockaddrLikePriv for LinkAddr {} + impl SockaddrLike for LinkAddr { + unsafe fn from_raw(addr: *const libc::sockaddr, + len: Option<libc::socklen_t>) + -> Option<Self> where Self: Sized + { + if let Some(l) = len { + if l != mem::size_of::<libc::sockaddr_ll>() as libc::socklen_t { + return None; + } + } + if (*addr).sa_family as i32 != libc::AF_PACKET as i32 { + return None; + } + Some(LinkAddr(*(addr as *const libc::sockaddr_ll))) + } + } + + impl AsRef<libc::sockaddr_ll> for LinkAddr { + fn as_ref(&self) -> &libc::sockaddr_ll { + &self.0 + } + } + } } @@ -1393,7 +2339,7 @@ mod datalink { mod datalink { feature! { #![feature = "net"] - use super::{fmt, AddressFamily}; + use super::{fmt, mem, private, SockaddrLike}; /// Hardware Address #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -1401,19 +2347,6 @@ mod datalink { pub struct LinkAddr(pub(in super::super) libc::sockaddr_dl); impl LinkAddr { - /// Total length of sockaddr - #[cfg(not(target_os = "illumos"))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn len(&self) -> usize { - self.0.sdl_len as usize - } - - /// always == AF_LINK - pub fn family(&self) -> AddressFamily { - assert_eq!(i32::from(self.0.sdl_family), libc::AF_LINK); - AddressFamily::Link - } - /// interface index, if != 0, system given index for interface pub fn ifindex(&self) -> usize { self.0.sdl_index as usize @@ -1424,7 +2357,7 @@ mod datalink { self.0.sdl_type } - // MAC address start position + /// MAC address start position pub fn nlen(&self) -> usize { self.0.sdl_nlen as usize } @@ -1484,6 +2417,30 @@ mod datalink { } } } + impl private::SockaddrLikePriv for LinkAddr {} + impl SockaddrLike for LinkAddr { + unsafe fn from_raw(addr: *const libc::sockaddr, + len: Option<libc::socklen_t>) + -> Option<Self> where Self: Sized + { + if let Some(l) = len { + if l != mem::size_of::<libc::sockaddr_dl>() as libc::socklen_t { + return None; + } + } + if (*addr).sa_family as i32 != libc::AF_LINK as i32 { + return None; + } + Some(LinkAddr(*(addr as *const libc::sockaddr_dl))) + } + } + + impl AsRef<libc::sockaddr_dl> for LinkAddr { + fn as_ref(&self) -> &libc::sockaddr_dl { + &self.0 + } + } + } } @@ -1494,11 +2451,40 @@ pub mod vsock { use libc::{sa_family_t, sockaddr_vm}; use std::{fmt, mem}; use std::hash::{Hash, Hasher}; + use super::*; + /// Socket address for VMWare VSockets protocol + /// + /// # References + /// + /// [vsock(7)](https://man7.org/linux/man-pages/man7/vsock.7.html) #[derive(Copy, Clone)] #[repr(transparent)] pub struct VsockAddr(pub(in super::super) sockaddr_vm); + impl private::SockaddrLikePriv for VsockAddr {} + impl SockaddrLike for VsockAddr { + unsafe fn from_raw(addr: *const libc::sockaddr, len: Option<libc::socklen_t>) + -> Option<Self> where Self: Sized + { + if let Some(l) = len { + if l != mem::size_of::<libc::sockaddr_vm>() as libc::socklen_t { + return None; + } + } + if (*addr).sa_family as i32 != libc::AF_INET6 as i32 { + return None; + } + Some(VsockAddr(*(addr as *const libc::sockaddr_vm))) + } + } + + impl AsRef<libc::sockaddr_vm> for VsockAddr { + fn as_ref(&self) -> &libc::sockaddr_vm { + &self.0 + } + } + impl PartialEq for VsockAddr { fn eq(&self, other: &Self) -> bool { let (inner, other) = (self.0, other.0); @@ -1521,6 +2507,7 @@ pub mod vsock { /// The address for AF_VSOCK socket is defined as a combination of a /// 32-bit Context Identifier (CID) and a 32-bit port number. impl VsockAddr { + /// Construct a `VsockAddr` from its raw fields. pub fn new(cid: u32, port: u32) -> VsockAddr { let mut addr: sockaddr_vm = unsafe { mem::zeroed() }; addr.svm_family = AddressFamily::Vsock as sa_family_t; @@ -1556,112 +2543,135 @@ pub mod vsock { #[cfg(test)] mod tests { - #[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "illumos", - target_os = "openbsd"))] use super::*; - /// Don't panic when trying to display an empty datalink address - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[test] - fn test_datalink_display() { - let la = LinkAddr(libc::sockaddr_dl{ - sdl_len: 56, - sdl_family: 18, - sdl_index: 5, - sdl_type: 24, - sdl_nlen: 3, - sdl_alen: 0, - sdl_slen: 0, - .. unsafe{mem::zeroed()} - }); - format!("{}", la); - } + mod link { + #[cfg(any(target_os = "ios", + target_os = "macos", + target_os = "illumos" + ))] + use super::{*, super::super::socklen_t}; - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[test] - fn test_macos_loopback_datalink_addr() { - let bytes = [20i8, 18, 1, 0, 24, 3, 0, 0, 108, 111, 48, 0, 0, 0, 0, 0]; - let sa = bytes.as_ptr() as *const libc::sockaddr; - let _sock_addr = unsafe { SockAddr::from_libc_sockaddr(sa) }; - assert!(_sock_addr.is_none()); - } + /// Don't panic when trying to display an empty datalink address + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + #[test] + fn test_datalink_display() { + use super::super::LinkAddr; + use std::mem; + + let la = LinkAddr(libc::sockaddr_dl{ + sdl_len: 56, + sdl_family: 18, + sdl_index: 5, + sdl_type: 24, + sdl_nlen: 3, + sdl_alen: 0, + sdl_slen: 0, + .. unsafe{mem::zeroed()} + }); + format!("{}", la); + } + + #[cfg(any(target_os = "ios", + target_os = "macos" + ))] + #[test] + fn macos_loopback() { + let bytes = [20i8, 18, 1, 0, 24, 3, 0, 0, 108, 111, 48, 0, 0, 0, 0, 0]; + let sa = bytes.as_ptr() as *const libc::sockaddr; + let len = Some(bytes.len() as socklen_t); + let sock_addr = unsafe { SockaddrStorage::from_raw(sa, len) }.unwrap(); + assert_eq!(sock_addr.family(), Some(AddressFamily::Link)); + match sock_addr.as_link_addr() { + Some(dl) => { + assert!(dl.addr().is_none()); + }, + None => panic!("Can't unwrap sockaddr storage") + } + } - #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd"))] - #[test] - fn test_macos_tap_datalink_addr() { - let bytes = [20i8, 18, 7, 0, 6, 3, 6, 0, 101, 110, 48, 24, 101, -112, -35, 76, -80]; - let ptr = bytes.as_ptr(); - let sa = ptr as *const libc::sockaddr; - let _sock_addr = unsafe { SockAddr::from_libc_sockaddr(sa) }; + #[cfg(any(target_os = "ios", + target_os = "macos" + ))] + #[test] + fn macos_tap() { + let bytes = [20i8, 18, 7, 0, 6, 3, 6, 0, 101, 110, 48, 24, 101, -112, -35, 76, -80]; + let ptr = bytes.as_ptr(); + let sa = ptr as *const libc::sockaddr; + let len = Some(bytes.len() as socklen_t); + + let sock_addr = unsafe { SockaddrStorage::from_raw(sa, len).unwrap() }; + assert_eq!(sock_addr.family(), Some(AddressFamily::Link)); + match sock_addr.as_link_addr() { + Some(dl) => assert_eq!(dl.addr(), + Some([24u8, 101, 144, 221, 76, 176])), + None => panic!("Can't unwrap sockaddr storage") + } + } - assert!(_sock_addr.is_some()); + #[cfg(target_os = "illumos")] + #[test] + fn illumos_tap() { + let bytes = [25u8, 0, 0, 0, 6, 0, 6, 0, 24, 101, 144, 221, 76, 176]; + let ptr = bytes.as_ptr(); + let sa = ptr as *const libc::sockaddr; + let len = Some(bytes.len() as socklen_t); + let _sock_addr = unsafe { SockaddrStorage::from_raw(sa, len) }; - let sock_addr = _sock_addr.unwrap(); + assert!(_sock_addr.is_some()); - assert_eq!(sock_addr.family(), AddressFamily::Link); + let sock_addr = _sock_addr.unwrap(); - match sock_addr { - SockAddr::Link(ether_addr) => { - assert_eq!(ether_addr.addr(), - Some([24u8, 101, 144, 221, 76, 176])); - }, - _ => { unreachable!() } - }; - } + assert_eq!(sock_addr.family().unwrap(), AddressFamily::Link); - #[cfg(target_os = "illumos")] - #[test] - fn test_illumos_tap_datalink_addr() { - let bytes = [25u8, 0, 0, 0, 6, 0, 6, 0, 24, 101, 144, 221, 76, 176]; - let ptr = bytes.as_ptr(); - let sa = ptr as *const libc::sockaddr; - let _sock_addr = unsafe { SockAddr::from_libc_sockaddr(sa) }; + assert_eq!(sock_addr.as_link_addr().unwrap().addr(), + Some([24u8, 101, 144, 221, 76, 176])); + } + } - assert!(_sock_addr.is_some()); + mod sockaddr_in { + use super::*; + use std::str::FromStr; - let sock_addr = _sock_addr.unwrap(); + #[test] + fn display() { + let s = "127.0.0.1:8080"; + let addr = SockaddrIn::from_str(s).unwrap(); + assert_eq!(s, format!("{}", addr)); + } + } - assert_eq!(sock_addr.family(), AddressFamily::Link); + mod sockaddr_in6 { + use super::*; + use std::str::FromStr; - match sock_addr { - SockAddr::Link(ether_addr) => { - assert_eq!(ether_addr.addr(), - Some([24u8, 101, 144, 221, 76, 176])); - }, - _ => { unreachable!() } - }; + #[test] + fn display() { + let s = "[1234:5678:90ab:cdef::1111:2222]:8080"; + let addr = SockaddrIn6::from_str(s).unwrap(); + assert_eq!(s, format!("{}", addr)); + } } - #[cfg(any(target_os = "android", target_os = "linux"))] - #[test] - fn test_abstract_sun_path() { - let name = String::from("nix\0abstract\0test"); - let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap(); - - let sun_path1 = unsafe { &(*addr.as_ptr()).sun_path[..addr.path_len()] }; - let sun_path2 = [0, 110, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, 115, 116]; - assert_eq!(sun_path1, sun_path2); + mod unixaddr { + #[cfg(any(target_os = "android", target_os = "linux"))] + use super::*; + + #[cfg(any(target_os = "android", target_os = "linux"))] + #[test] + fn abstract_sun_path() { + let name = String::from("nix\0abstract\0test"); + let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap(); + + let sun_path1 = unsafe { &(*addr.as_ptr()).sun_path[..addr.path_len()] }; + let sun_path2 = [0, 110, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, 115, 116]; + assert_eq!(sun_path1, sun_path2); + } + } } diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 7ed2d82d..f5004b45 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -17,6 +17,7 @@ use crate::sys::{ uio::IoVec }; +#[deny(missing_docs)] mod addr; #[deny(missing_docs)] pub mod sockopt; @@ -27,12 +28,16 @@ pub mod sockopt; * */ +pub use self::addr::{SockaddrLike, SockaddrStorage}; + #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] +#[allow(deprecated)] pub use self::addr::{ AddressFamily, SockAddr, UnixAddr, }; +#[allow(deprecated)] #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] #[cfg(feature = "net")] pub use self::addr::{ @@ -40,14 +45,18 @@ pub use self::addr::{ IpAddr, Ipv4Addr, Ipv6Addr, - LinkAddr + LinkAddr, + SockaddrIn, + SockaddrIn6 }; #[cfg(any(target_os = "illumos", target_os = "solaris"))] +#[allow(deprecated)] pub use self::addr::{ AddressFamily, SockAddr, UnixAddr, }; +#[allow(deprecated)] #[cfg(any(target_os = "illumos", target_os = "solaris"))] #[cfg(feature = "net")] pub use self::addr::{ @@ -55,8 +64,13 @@ pub use self::addr::{ IpAddr, Ipv4Addr, Ipv6Addr, + SockaddrIn, + SockaddrIn6 }; +#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(feature = "ioctl")] +pub use crate::sys::socket::addr::sys_control::SysControlAddr; #[cfg(any(target_os = "android", target_os = "linux"))] pub use crate::sys::socket::addr::netlink::NetlinkAddr; #[cfg(any(target_os = "android", target_os = "linux"))] @@ -550,15 +564,15 @@ macro_rules! cmsg_space { } #[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct RecvMsg<'a> { +pub struct RecvMsg<'a, S> { pub bytes: usize, cmsghdr: Option<&'a cmsghdr>, - pub address: Option<SockAddr>, + pub address: Option<S>, pub flags: MsgFlags, mhdr: msghdr, } -impl<'a> RecvMsg<'a> { +impl<'a, S> RecvMsg<'a, S> { /// Iterate over the valid control messages pointed to by this /// msghdr. pub fn cmsgs(&self) -> CmsgIterator { @@ -635,6 +649,7 @@ pub enum ControlMessageOwned { /// # use nix::sys::uio::IoVec; /// # use nix::sys::time::*; /// # use std::time::*; + /// # use std::str::FromStr; /// # fn main() { /// // Set up /// let message = "Ohayō!".as_bytes(); @@ -644,9 +659,9 @@ pub enum ControlMessageOwned { /// SockFlag::empty(), /// None).unwrap(); /// setsockopt(in_socket, sockopt::ReceiveTimestamp, &true).unwrap(); - /// let localhost = InetAddr::new(IpAddr::new_v4(127, 0, 0, 1), 0); - /// bind(in_socket, &SockAddr::new_inet(localhost)).unwrap(); - /// let address = getsockname(in_socket).unwrap(); + /// let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap(); + /// bind(in_socket, &localhost); + /// let address: SockaddrIn = getsockname(in_socket).unwrap(); /// // Get initial time /// let time0 = SystemTime::now(); /// // Send the message @@ -658,7 +673,8 @@ pub enum ControlMessageOwned { /// let mut buffer = vec![0u8; message.len()]; /// let mut cmsgspace = cmsg_space!(TimeVal); /// let iov = [IoVec::from_mut_slice(&mut buffer)]; - /// let r = recvmsg(in_socket, &iov, Some(&mut cmsgspace), flags).unwrap(); + /// let r = recvmsg::<SockaddrIn>(in_socket, &iov, Some(&mut cmsgspace), flags) + /// .unwrap(); /// let rtime = match r.cmsgs().next() { /// Some(ControlMessageOwned::ScmTimestamp(rtime)) => rtime, /// Some(_) => panic!("Unexpected control message"), @@ -1334,8 +1350,42 @@ impl<'a> ControlMessage<'a> { /// as with sendto. /// /// Allocates if cmsgs is nonempty. -pub fn sendmsg(fd: RawFd, iov: &[IoVec<&[u8]>], cmsgs: &[ControlMessage], - flags: MsgFlags, addr: Option<&SockAddr>) -> Result<usize> +/// +/// # Examples +/// When not directing to any specific address, use `()` for the generic type +/// ``` +/// # use nix::sys::socket::*; +/// # use nix::unistd::pipe; +/// # use nix::sys::uio::IoVec; +/// let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, +/// SockFlag::empty()) +/// .unwrap(); +/// let (r, w) = pipe().unwrap(); +/// +/// let iov = [IoVec::from_slice(b"hello")]; +/// let fds = [r]; +/// let cmsg = ControlMessage::ScmRights(&fds); +/// sendmsg::<()>(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(); +/// ``` +/// When directing to a specific address, the generic type will be inferred. +/// ``` +/// # use nix::sys::socket::*; +/// # use nix::unistd::pipe; +/// # use nix::sys::uio::IoVec; +/// # use std::str::FromStr; +/// let localhost = SockaddrIn::from_str("1.2.3.4:8080").unwrap(); +/// let fd = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), +/// None).unwrap(); +/// let (r, w) = pipe().unwrap(); +/// +/// let iov = [IoVec::from_slice(b"hello")]; +/// let fds = [r]; +/// let cmsg = ControlMessage::ScmRights(&fds); +/// sendmsg(fd, &iov, &[cmsg], MsgFlags::empty(), Some(&localhost)).unwrap(); +/// ``` +pub fn sendmsg<S>(fd: RawFd, iov: &[IoVec<&[u8]>], cmsgs: &[ControlMessage], + flags: MsgFlags, addr: Option<&S>) -> Result<usize> + where S: SockaddrLike { let capacity = cmsgs.iter().map(|c| c.space()).sum(); @@ -1357,14 +1407,15 @@ pub fn sendmsg(fd: RawFd, iov: &[IoVec<&[u8]>], cmsgs: &[ControlMessage], target_os = "netbsd", ))] #[derive(Debug)] -pub struct SendMmsgData<'a, I, C> +pub struct SendMmsgData<'a, I, C, S> where I: AsRef<[IoVec<&'a [u8]>]>, - C: AsRef<[ControlMessage<'a>]> + C: AsRef<[ControlMessage<'a>]>, + S: SockaddrLike + 'a { pub iov: I, pub cmsgs: C, - pub addr: Option<SockAddr>, + pub addr: Option<S>, pub _lt: std::marker::PhantomData<&'a I>, } @@ -1391,14 +1442,15 @@ pub struct SendMmsgData<'a, I, C> target_os = "freebsd", target_os = "netbsd", ))] -pub fn sendmmsg<'a, I, C>( +pub fn sendmmsg<'a, I, C, S>( fd: RawFd, - data: impl std::iter::IntoIterator<Item=&'a SendMmsgData<'a, I, C>>, + data: impl std::iter::IntoIterator<Item=&'a SendMmsgData<'a, I, C, S>>, flags: MsgFlags ) -> Result<Vec<usize>> where I: AsRef<[IoVec<&'a [u8]>]> + 'a, C: AsRef<[ControlMessage<'a>]> + 'a, + S: SockaddrLike + 'a { let iter = data.into_iter(); @@ -1486,15 +1538,16 @@ pub struct RecvMmsgData<'a, I> target_os = "netbsd", ))] #[allow(clippy::needless_collect)] // Complicated false positive -pub fn recvmmsg<'a, I>( +pub fn recvmmsg<'a, I, S>( fd: RawFd, data: impl std::iter::IntoIterator<Item=&'a mut RecvMmsgData<'a, I>, IntoIter=impl ExactSizeIterator + Iterator<Item=&'a mut RecvMmsgData<'a, I>>>, flags: MsgFlags, timeout: Option<crate::sys::time::TimeSpec> -) -> Result<Vec<RecvMsg<'a>>> +) -> Result<Vec<RecvMsg<'a, S>>> where I: AsRef<[IoVec<&'a mut [u8]>]> + 'a, + S: Copy + SockaddrLike + 'a { let iter = data.into_iter(); @@ -1556,13 +1609,15 @@ pub fn recvmmsg<'a, I>( .collect()) } -unsafe fn read_mhdr<'a, 'b>( +unsafe fn read_mhdr<'a, 'b, S>( mhdr: msghdr, r: isize, msg_controllen: usize, - address: sockaddr_storage, + address: S, cmsg_buffer: &'a mut Option<&'b mut Vec<u8>> -) -> RecvMsg<'b> { +) -> RecvMsg<'b, S> + where S: SockaddrLike +{ let cmsghdr = { if mhdr.msg_controllen > 0 { // got control message(s) @@ -1578,27 +1633,23 @@ unsafe fn read_mhdr<'a, 'b>( }.as_ref() }; - let address = sockaddr_storage_to_addr( - &address , - mhdr.msg_namelen as usize - ).ok(); - RecvMsg { bytes: r as usize, cmsghdr, - address, + address: Some(address), flags: MsgFlags::from_bits_truncate(mhdr.msg_flags), mhdr, } } -unsafe fn pack_mhdr_to_receive<'a, I>( +unsafe fn pack_mhdr_to_receive<'a, I, S>( iov: I, cmsg_buffer: &mut Option<&mut Vec<u8>>, - address: *mut sockaddr_storage, + address: *mut S, ) -> (usize, msghdr) where I: AsRef<[IoVec<&'a mut [u8]>]> + 'a, + S: SockaddrLike + 'a { let (msg_control, msg_controllen) = cmsg_buffer.as_mut() .map(|v| (v.as_mut_ptr(), v.capacity())) @@ -1609,8 +1660,8 @@ unsafe fn pack_mhdr_to_receive<'a, I>( // initialize it. let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed(); let p = mhdr.as_mut_ptr(); - (*p).msg_name = address as *mut c_void; - (*p).msg_namelen = mem::size_of::<sockaddr_storage>() as socklen_t; + (*p).msg_name = (*address).as_mut_ptr() as *mut c_void; + (*p).msg_namelen = S::size(); (*p).msg_iov = iov.as_ref().as_ptr() as *mut iovec; (*p).msg_iovlen = iov.as_ref().len() as _; (*p).msg_control = msg_control as *mut c_void; @@ -1622,27 +1673,19 @@ unsafe fn pack_mhdr_to_receive<'a, I>( (msg_controllen, mhdr) } -fn pack_mhdr_to_send<'a, I, C>( +fn pack_mhdr_to_send<'a, I, C, S>( cmsg_buffer: &mut [u8], iov: I, cmsgs: C, - addr: Option<&SockAddr> + addr: Option<&S> ) -> msghdr where I: AsRef<[IoVec<&'a [u8]>]>, - C: AsRef<[ControlMessage<'a>]> + C: AsRef<[ControlMessage<'a>]>, + S: SockaddrLike + 'a { let capacity = cmsg_buffer.len(); - // Next encode the sending address, if provided - let (name, namelen) = match addr { - Some(addr) => { - let (x, y) = addr.as_ffi_pair(); - (x as *const _, y) - }, - None => (ptr::null(), 0), - }; - // The message header must be initialized before the individual cmsgs. let cmsg_ptr = if capacity > 0 { cmsg_buffer.as_ptr() as *mut c_void @@ -1655,8 +1698,8 @@ fn pack_mhdr_to_send<'a, I, C>( // initialize it. let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed(); let p = mhdr.as_mut_ptr(); - (*p).msg_name = name as *mut _; - (*p).msg_namelen = namelen; + (*p).msg_name = addr.map(S::as_ptr).unwrap_or(ptr::null()) as *mut _; + (*p).msg_namelen = addr.map(S::len).unwrap_or(0); // transmute iov into a mutable pointer. sendmsg doesn't really mutate // the buffer, but the standard says that it takes a mutable pointer (*p).msg_iov = iov.as_ref().as_ptr() as *mut _; @@ -1697,9 +1740,10 @@ fn pack_mhdr_to_send<'a, I, C>( /// /// # References /// [recvmsg(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html) -pub fn recvmsg<'a>(fd: RawFd, iov: &[IoVec<&mut [u8]>], +pub fn recvmsg<'a, S>(fd: RawFd, iov: &[IoVec<&mut [u8]>], mut cmsg_buffer: Option<&'a mut Vec<u8>>, - flags: MsgFlags) -> Result<RecvMsg<'a>> + flags: MsgFlags) -> Result<RecvMsg<'a, S>> + where S: SockaddrLike + 'a { let mut address = mem::MaybeUninit::uninit(); @@ -1779,10 +1823,9 @@ pub fn listen(sockfd: RawFd, backlog: usize) -> Result<()> { /// Bind a name to a socket /// /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html) -pub fn bind(fd: RawFd, addr: &SockAddr) -> Result<()> { +pub fn bind(fd: RawFd, addr: &dyn SockaddrLike) -> Result<()> { let res = unsafe { - let (ptr, len) = addr.as_ffi_pair(); - libc::bind(fd, ptr, len) + libc::bind(fd, addr.as_ptr(), addr.len()) }; Errno::result(res).map(drop) @@ -1825,10 +1868,9 @@ pub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result<RawFd> { /// Initiate a connection on a socket /// /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html) -pub fn connect(fd: RawFd, addr: &SockAddr) -> Result<()> { +pub fn connect(fd: RawFd, addr: &dyn SockaddrLike) -> Result<()> { let res = unsafe { - let (ptr, len) = addr.as_ffi_pair(); - libc::connect(fd, ptr, len) + libc::connect(fd, addr.as_ptr(), addr.len()) }; Errno::result(res).map(drop) @@ -1855,36 +1897,38 @@ pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> { /// address of the sender. /// /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html) -pub fn recvfrom(sockfd: RawFd, buf: &mut [u8]) - -> Result<(usize, Option<SockAddr>)> +pub fn recvfrom<T:SockaddrLike>(sockfd: RawFd, buf: &mut [u8]) + -> Result<(usize, Option<T>)> { unsafe { - let mut addr: sockaddr_storage = mem::zeroed(); - let mut len = mem::size_of::<sockaddr_storage>() as socklen_t; + let mut addr = mem::MaybeUninit::uninit(); + let mut len = mem::size_of::<T>() as socklen_t; let ret = Errno::result(libc::recvfrom( sockfd, buf.as_ptr() as *mut c_void, buf.len() as size_t, 0, - &mut addr as *mut libc::sockaddr_storage as *mut libc::sockaddr, + addr.as_mut_ptr() as *mut libc::sockaddr, &mut len as *mut socklen_t))? as usize; - match sockaddr_storage_to_addr(&addr, len as usize) { - Err(Errno::ENOTCONN) => Ok((ret, None)), - Ok(addr) => Ok((ret, Some(addr))), - Err(e) => Err(e) - } + Ok((ret, T::from_raw(&addr.assume_init(), Some(len)))) } } /// Send a message to a socket /// /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html) -pub fn sendto(fd: RawFd, buf: &[u8], addr: &SockAddr, flags: MsgFlags) -> Result<usize> { +pub fn sendto(fd: RawFd, buf: &[u8], addr: &dyn SockaddrLike, flags: MsgFlags) -> Result<usize> { let ret = unsafe { - let (ptr, len) = addr.as_ffi_pair(); - libc::sendto(fd, buf.as_ptr() as *const c_void, buf.len() as size_t, flags.bits(), ptr, len) + libc::sendto( + fd, + buf.as_ptr() as *const c_void, + buf.len() as size_t, + flags.bits(), + addr.as_ptr(), + addr.len() + ) }; Errno::result(ret).map(|r| r as usize) @@ -1954,10 +1998,10 @@ pub fn setsockopt<O: SetSockOpt>(fd: RawFd, opt: O, val: &O::Val) -> Result<()> /// Get the address of the peer connected to the socket `fd`. /// /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html) -pub fn getpeername(fd: RawFd) -> Result<SockAddr> { +pub fn getpeername<T: SockaddrLike>(fd: RawFd) -> Result<T> { unsafe { - let mut addr = mem::MaybeUninit::uninit(); - let mut len = mem::size_of::<sockaddr_storage>() as socklen_t; + let mut addr = mem::MaybeUninit::<T>::uninit(); + let mut len = T::size(); let ret = libc::getpeername( fd, @@ -1967,17 +2011,18 @@ pub fn getpeername(fd: RawFd) -> Result<SockAddr> { Errno::result(ret)?; - sockaddr_storage_to_addr(&addr.assume_init(), len as usize) + T::from_raw(addr.assume_init().as_ptr(), Some(len)) + .ok_or(Errno::EINVAL) } } /// Get the current address to which the socket `fd` is bound. /// /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html) -pub fn getsockname(fd: RawFd) -> Result<SockAddr> { +pub fn getsockname<T: SockaddrLike>(fd: RawFd) -> Result<T> { unsafe { - let mut addr = mem::MaybeUninit::uninit(); - let mut len = mem::size_of::<sockaddr_storage>() as socklen_t; + let mut addr = mem::MaybeUninit::<T>::uninit(); + let mut len = T::size(); let ret = libc::getsockname( fd, @@ -1987,7 +2032,8 @@ pub fn getsockname(fd: RawFd) -> Result<SockAddr> { Errno::result(ret)?; - sockaddr_storage_to_addr(&addr.assume_init(), len as usize) + T::from_raw(addr.assume_init().as_ptr(), Some(len)) + .ok_or(Errno::EINVAL) } } @@ -1999,6 +2045,11 @@ pub fn getsockname(fd: RawFd) -> Result<SockAddr> { /// allocated and valid. It must be at least as large as all the useful parts /// of the structure. Note that in the case of a `sockaddr_un`, `len` need not /// include the terminating null. +#[deprecated( + since = "0.24.0", + note = "use SockaddrLike or SockaddrStorage instead" +)] +#[allow(deprecated)] pub fn sockaddr_storage_to_addr( addr: &sockaddr_storage, len: usize) -> Result<SockAddr> { diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 01f5f878..e03edc3b 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -1,8 +1,11 @@ -use nix::sys::socket::{AddressFamily, InetAddr, SockAddr, UnixAddr, getsockname, sockaddr, sockaddr_in6, sockaddr_storage_to_addr}; +#[allow(deprecated)] +use nix::sys::socket::InetAddr; +use nix::sys::socket::{AddressFamily, + UnixAddr, getsockname, sockaddr, sockaddr_in6}; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; use std::mem::{self, MaybeUninit}; -use std::net::{self, Ipv6Addr, SocketAddr, SocketAddrV6}; +use std::net::{self, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use std::os::unix::io::RawFd; use std::path::Path; use std::slice; @@ -11,6 +14,7 @@ use libc::{c_char, sockaddr_storage}; #[cfg(any(target_os = "linux", target_os= "android"))] use crate::*; +#[allow(deprecated)] #[test] pub fn test_inetv4_addr_to_sock_addr() { let actual: net::SocketAddr = FromStr::from_str("127.0.0.1:3000").unwrap(); @@ -34,8 +38,11 @@ pub fn test_inetv4_addr_to_sock_addr() { assert_eq!(actual, inet); } +#[allow(deprecated)] #[test] pub fn test_inetv4_addr_roundtrip_sockaddr_storage_to_addr() { + use nix::sys::socket::{SockAddr, sockaddr_storage_to_addr}; + let actual: net::SocketAddr = FromStr::from_str("127.0.0.1:3000").unwrap(); let addr = InetAddr::from_std(&actual); let sockaddr = SockAddr::new_inet(addr); @@ -63,13 +70,11 @@ pub fn test_inetv4_addr_roundtrip_sockaddr_storage_to_addr() { pub fn test_timestamping() { use nix::sys::socket::{ recvmsg, sendmsg, setsockopt, socket, sockopt::Timestamping, ControlMessageOwned, MsgFlags, - SockFlag, SockType, TimestampingFlag, + SockaddrIn, SockFlag, SockType, TimestampingFlag, }; use nix::sys::uio::IoVec; - let std_sa = SocketAddr::from_str("127.0.0.1:6790").unwrap(); - let inet_addr = InetAddr::from_std(&std_sa); - let sock_addr = SockAddr::new_inet(inet_addr); + let sock_addr = SockaddrIn::from_str("127.0.0.1:6790").unwrap(); let ssock = socket( AddressFamily::Inet, @@ -97,7 +102,7 @@ pub fn test_timestamping() { let iov2 = [IoVec::from_mut_slice(&mut rbuf)]; let mut cmsg = cmsg_space!(nix::sys::socket::Timestamps); sendmsg(ssock, &iov1, &[], flags, Some(&sock_addr)).unwrap(); - let recv = recvmsg(rsock, &iov2, Some(&mut cmsg), flags).unwrap(); + let recv = recvmsg::<()>(rsock, &iov2, Some(&mut cmsg), flags).unwrap(); let mut ts = None; for c in recv.cmsgs() { @@ -115,29 +120,11 @@ pub fn test_timestamping() { assert!(std::time::Duration::from(diff).as_secs() < 60); } -#[test] -pub fn test_inetv6_addr_to_sock_addr() { - let port: u16 = 3000; - let flowinfo: u32 = 1; - let scope_id: u32 = 2; - let ip: Ipv6Addr = "fe80::1".parse().unwrap(); - - let actual = SocketAddr::V6(SocketAddrV6::new(ip, port, flowinfo, scope_id)); - let addr = InetAddr::from_std(&actual); - - match addr { - InetAddr::V6(addr) => { - assert_eq!(addr.sin6_port, port.to_be()); - assert_eq!(addr.sin6_flowinfo, flowinfo); - assert_eq!(addr.sin6_scope_id, scope_id); - } - _ => panic!("nope"), - } - - assert_eq!(actual, addr.to_std()); -} +#[allow(deprecated)] #[test] pub fn test_inetv6_addr_roundtrip_sockaddr_storage_to_addr() { + use nix::sys::socket::{SockAddr, sockaddr_storage_to_addr}; + let port: u16 = 3000; let flowinfo: u32 = 1; let scope_id: u32 = 2; @@ -244,13 +231,13 @@ pub fn test_abstract_uds_addr() { #[test] pub fn test_getsockname() { use nix::sys::socket::{socket, AddressFamily, SockType, SockFlag}; - use nix::sys::socket::{bind, SockAddr}; + use nix::sys::socket::bind; let tempdir = tempfile::tempdir().unwrap(); let sockname = tempdir.path().join("sock"); let sock = socket(AddressFamily::Unix, SockType::Stream, SockFlag::empty(), None) .expect("socket failed"); - let sockaddr = SockAddr::new_unix(&sockname).unwrap(); + let sockaddr = UnixAddr::new(&sockname).unwrap(); bind(sock, &sockaddr).expect("bind failed"); assert_eq!(sockaddr, getsockname(sock).expect("getsockname failed")); } @@ -277,10 +264,10 @@ mod recvfrom { const MSG: &[u8] = b"Hello, World!"; - fn sendrecv<Fs, Fr>(rsock: RawFd, ssock: RawFd, f_send: Fs, mut f_recv: Fr) -> Option<SockAddr> + fn sendrecv<Fs, Fr>(rsock: RawFd, ssock: RawFd, f_send: Fs, mut f_recv: Fr) -> Option<SockaddrStorage> where Fs: Fn(RawFd, &[u8], MsgFlags) -> Result<usize> + Send + 'static, - Fr: FnMut(usize, Option<SockAddr>), + Fr: FnMut(usize, Option<SockaddrStorage>), { let mut buf: [u8; 13] = [0u8; 13]; let mut l = 0; @@ -316,9 +303,8 @@ mod recvfrom { #[test] pub fn udp() { - let std_sa = SocketAddr::from_str("127.0.0.1:6789").unwrap(); - let inet_addr = InetAddr::from_std(&std_sa); - let sock_addr = SockAddr::new_inet(inet_addr); + let std_sa = SocketAddrV4::from_str("127.0.0.1:6789").unwrap(); + let sock_addr = SockaddrIn::from(std_sa); let rsock = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), @@ -335,7 +321,7 @@ mod recvfrom { sendto(s, m, &sock_addr, flags) },|_, _| {}); // UDP sockets should set the from address - assert_eq!(AddressFamily::Inet, from.unwrap().family()); + assert_eq!(AddressFamily::Inet, from.unwrap().family().unwrap()); } #[cfg(target_os = "linux")] @@ -356,9 +342,7 @@ mod recvfrom { // with size 2 and two UDP packet with size 1 will be sent. let segment_size: u16 = 2; - let std_sa = SocketAddr::from_str("127.0.0.1:6791").unwrap(); - let inet_addr = InetAddr::from_std(&std_sa); - let sock_addr = SockAddr::new_inet(inet_addr); + let sock_addr = SockaddrIn::new(127, 0, 0, 1, 6791); let rsock = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), @@ -429,12 +413,10 @@ mod recvfrom { pub fn udp_sendmmsg() { use nix::sys::uio::IoVec; - let std_sa = SocketAddr::from_str("127.0.0.1:6793").unwrap(); - let std_sa2 = SocketAddr::from_str("127.0.0.1:6794").unwrap(); - let inet_addr = InetAddr::from_std(&std_sa); - let inet_addr2 = InetAddr::from_std(&std_sa2); - let sock_addr = SockAddr::new_inet(inet_addr); - let sock_addr2 = SockAddr::new_inet(inet_addr2); + let std_sa = SocketAddrV4::from_str("127.0.0.1:6793").unwrap(); + let std_sa2 = SocketAddrV4::from_str("127.0.0.1:6794").unwrap(); + let sock_addr = SockaddrIn::from(std_sa); + let sock_addr2 = SockaddrIn::from(std_sa2); let rsock = socket(AddressFamily::Inet, SockType::Datagram, @@ -482,7 +464,7 @@ mod recvfrom { }) }, |_, _ | {}); // UDP sockets should set the from address - assert_eq!(AddressFamily::Inet, from.unwrap().family()); + assert_eq!(AddressFamily::Inet, from.unwrap().family().unwrap()); } #[cfg(any( @@ -499,9 +481,8 @@ mod recvfrom { const NUM_MESSAGES_SENT: usize = 2; const DATA: [u8; 2] = [1,2]; - let std_sa = SocketAddr::from_str("127.0.0.1:6798").unwrap(); - let inet_addr = InetAddr::from_std(&std_sa); - let sock_addr = SockAddr::new_inet(inet_addr); + let inet_addr = SocketAddrV4::from_str("127.0.0.1:6798").unwrap(); + let sock_addr = SockaddrIn::from(inet_addr); let rsock = socket(AddressFamily::Inet, SockType::Datagram, @@ -537,11 +518,11 @@ mod recvfrom { }) }; - let res = recvmmsg(rsock, &mut msgs, MsgFlags::empty(), None).expect("recvmmsg"); + let res: Vec<RecvMsg<SockaddrIn>> = recvmmsg(rsock, &mut msgs, MsgFlags::empty(), None).expect("recvmmsg"); assert_eq!(res.len(), DATA.len()); for RecvMsg { address, bytes, .. } in res.into_iter() { - assert_eq!(AddressFamily::Inet, address.unwrap().family()); + assert_eq!(AddressFamily::Inet, address.unwrap().family().unwrap()); assert_eq!(DATA.len(), bytes); } @@ -566,9 +547,8 @@ mod recvfrom { const NUM_MESSAGES_SENT: usize = 2; const DATA: [u8; 4] = [1,2,3,4]; - let std_sa = SocketAddr::from_str("127.0.0.1:6799").unwrap(); - let inet_addr = InetAddr::from_std(&std_sa); - let sock_addr = SockAddr::new_inet(inet_addr); + let inet_addr = SocketAddrV4::from_str("127.0.0.1:6799").unwrap(); + let sock_addr = SockaddrIn::from(inet_addr); let rsock = socket(AddressFamily::Inet, SockType::Datagram, @@ -609,11 +589,11 @@ mod recvfrom { }) }; - let res = recvmmsg(rsock, &mut msgs, MsgFlags::MSG_DONTWAIT, None).expect("recvmmsg"); + let res: Vec<RecvMsg<SockaddrIn>> = recvmmsg(rsock, &mut msgs, MsgFlags::MSG_DONTWAIT, None).expect("recvmmsg"); assert_eq!(res.len(), NUM_MESSAGES_SENT); for RecvMsg { address, bytes, .. } in res.into_iter() { - assert_eq!(AddressFamily::Inet, address.unwrap().family()); + assert_eq!(AddressFamily::Inet, address.unwrap().family().unwrap()); assert_eq!(DATA.len(), bytes); } @@ -633,7 +613,7 @@ pub fn test_recvmsg_ebadf() { let mut buf = [0u8; 5]; let iov = [IoVec::from_mut_slice(&mut buf[..])]; let fd = -1; // Bad file descriptor - let r = recvmsg(fd, &iov, None, MsgFlags::empty()); + let r = recvmsg::<()>(fd, &iov, None, MsgFlags::empty()); assert_eq!(r.err().unwrap(), Errno::EBADF); } @@ -657,7 +637,7 @@ pub fn test_scm_rights() { let iov = [IoVec::from_slice(b"hello")]; let fds = [r]; let cmsg = ControlMessage::ScmRights(&fds); - assert_eq!(sendmsg(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(), 5); + assert_eq!(sendmsg::<()>(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(), 5); close(r).unwrap(); close(fd1).unwrap(); } @@ -666,7 +646,7 @@ pub fn test_scm_rights() { let mut buf = [0u8; 5]; let iov = [IoVec::from_mut_slice(&mut buf[..])]; let mut cmsgspace = cmsg_space!([RawFd; 1]); - let msg = recvmsg(fd2, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap(); + let msg = recvmsg::<()>(fd2, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap(); for cmsg in msg.cmsgs() { if let ControlMessageOwned::ScmRights(fd) = cmsg { @@ -700,7 +680,7 @@ pub fn test_af_alg_cipher() { use nix::sys::uio::IoVec; use nix::unistd::read; use nix::sys::socket::{socket, sendmsg, bind, accept, setsockopt, - AddressFamily, SockType, SockFlag, SockAddr, + AddressFamily, SockType, SockFlag, AlgAddr, ControlMessage, MsgFlags}; use nix::sys::socket::sockopt::AlgSetKey; @@ -723,22 +703,18 @@ pub fn test_af_alg_cipher() { let sock = socket(AddressFamily::Alg, SockType::SeqPacket, SockFlag::empty(), None) .expect("socket failed"); - let sockaddr = SockAddr::new_alg(alg_type, alg_name); + let sockaddr = AlgAddr::new(alg_type, alg_name); bind(sock, &sockaddr).expect("bind failed"); - if let SockAddr::Alg(alg) = sockaddr { - assert_eq!(alg.alg_name().to_string_lossy(), alg_name); - assert_eq!(alg.alg_type().to_string_lossy(), alg_type); - } else { - panic!("unexpected SockAddr"); - } + assert_eq!(sockaddr.alg_name().to_string_lossy(), alg_name); + assert_eq!(sockaddr.alg_type().to_string_lossy(), alg_type); setsockopt(sock, AlgSetKey::default(), &key).expect("setsockopt"); let session_socket = accept(sock).expect("accept failed"); let msgs = [ControlMessage::AlgSetOp(&libc::ALG_OP_ENCRYPT), ControlMessage::AlgSetIv(iv.as_slice())]; let iov = IoVec::from_slice(&payload); - sendmsg(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg encrypt"); + sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg encrypt"); // allocate buffer for encrypted data let mut encrypted = vec![0u8; payload_len]; @@ -750,7 +726,7 @@ pub fn test_af_alg_cipher() { let iv = vec![1u8; iv_len]; let msgs = [ControlMessage::AlgSetOp(&libc::ALG_OP_DECRYPT), ControlMessage::AlgSetIv(iv.as_slice())]; - sendmsg(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg decrypt"); + sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg decrypt"); // allocate buffer for decrypted data let mut decrypted = vec![0u8; payload_len]; @@ -771,7 +747,7 @@ pub fn test_af_alg_aead() { use nix::sys::uio::IoVec; use nix::unistd::{read, close}; use nix::sys::socket::{socket, sendmsg, bind, accept, setsockopt, - AddressFamily, SockType, SockFlag, SockAddr, + AddressFamily, SockType, SockFlag, AlgAddr, ControlMessage, MsgFlags}; use nix::sys::socket::sockopt::{AlgSetKey, AlgSetAeadAuthSize}; @@ -807,7 +783,7 @@ pub fn test_af_alg_aead() { let sock = socket(AddressFamily::Alg, SockType::SeqPacket, SockFlag::empty(), None) .expect("socket failed"); - let sockaddr = SockAddr::new_alg(alg_type, alg_name); + let sockaddr = AlgAddr::new(alg_type, alg_name); bind(sock, &sockaddr).expect("bind failed"); setsockopt(sock, AlgSetAeadAuthSize, &auth_size).expect("setsockopt AlgSetAeadAuthSize"); @@ -819,7 +795,7 @@ pub fn test_af_alg_aead() { ControlMessage::AlgSetIv(iv.as_slice()), ControlMessage::AlgSetAeadAssoclen(&assoc_size)]; let iov = IoVec::from_slice(&payload); - sendmsg(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg encrypt"); + sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg encrypt"); // allocate buffer for encrypted data let mut encrypted = vec![0u8; (assoc_size as usize) + payload_len + auth_size]; @@ -842,7 +818,7 @@ pub fn test_af_alg_aead() { ControlMessage::AlgSetIv(iv.as_slice()), ControlMessage::AlgSetAeadAssoclen(&assoc_size), ]; - sendmsg(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg decrypt"); + sendmsg::<()>(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg decrypt"); // allocate buffer for decrypted data let mut decrypted = vec![0u8; payload_len + (assoc_size as usize) + auth_size]; @@ -872,7 +848,7 @@ pub fn test_sendmsg_ipv4packetinfo() { use cfg_if::cfg_if; use nix::sys::uio::IoVec; use nix::sys::socket::{socket, sendmsg, bind, - AddressFamily, SockType, SockFlag, SockAddr, + AddressFamily, SockType, SockFlag, SockaddrIn, ControlMessage, MsgFlags}; let sock = socket(AddressFamily::Inet, @@ -881,39 +857,32 @@ pub fn test_sendmsg_ipv4packetinfo() { None) .expect("socket failed"); - let std_sa = SocketAddr::from_str("127.0.0.1:4000").unwrap(); - let inet_addr = InetAddr::from_std(&std_sa); - let sock_addr = SockAddr::new_inet(inet_addr); + let sock_addr = SockaddrIn::new(127,0,0,1, 4000); bind(sock, &sock_addr).expect("bind failed"); let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; let iov = [IoVec::from_slice(&slice)]; - if let InetAddr::V4(sin) = inet_addr { - cfg_if! { - if #[cfg(target_os = "netbsd")] { - let _dontcare = sin; - let pi = libc::in_pktinfo { - ipi_ifindex: 0, /* Unspecified interface */ - ipi_addr: libc::in_addr { s_addr: 0 }, - }; - } else { - let pi = libc::in_pktinfo { - ipi_ifindex: 0, /* Unspecified interface */ - ipi_addr: libc::in_addr { s_addr: 0 }, - ipi_spec_dst: sin.sin_addr, - }; - } + cfg_if! { + if #[cfg(target_os = "netbsd")] { + let pi = libc::in_pktinfo { + ipi_ifindex: 0, /* Unspecified interface */ + ipi_addr: libc::in_addr { s_addr: 0 }, + }; + } else { + let pi = libc::in_pktinfo { + ipi_ifindex: 0, /* Unspecified interface */ + ipi_addr: libc::in_addr { s_addr: 0 }, + ipi_spec_dst: sock_addr.as_ref().sin_addr, + }; } + } - let cmsg = [ControlMessage::Ipv4PacketInfo(&pi)]; + let cmsg = [ControlMessage::Ipv4PacketInfo(&pi)]; - sendmsg(sock, &iov, &cmsg, MsgFlags::empty(), Some(&sock_addr)) - .expect("sendmsg"); - } else { - panic!("No IPv4 addresses available for testing?"); - } + sendmsg(sock, &iov, &cmsg, MsgFlags::empty(), Some(&sock_addr)) + .expect("sendmsg"); } // Verify `ControlMessage::Ipv6PacketInfo` for `sendmsg`. @@ -933,7 +902,7 @@ pub fn test_sendmsg_ipv6packetinfo() { use nix::errno::Errno; use nix::sys::uio::IoVec; use nix::sys::socket::{socket, sendmsg, bind, - AddressFamily, SockType, SockFlag, SockAddr, + AddressFamily, SockType, SockFlag, SockaddrIn6, ControlMessage, MsgFlags}; let sock = socket(AddressFamily::Inet6, @@ -942,9 +911,8 @@ pub fn test_sendmsg_ipv6packetinfo() { None) .expect("socket failed"); - let std_sa = SocketAddr::from_str("[::1]:6000").unwrap(); - let inet_addr = InetAddr::from_std(&std_sa); - let sock_addr = SockAddr::new_inet(inet_addr); + let std_sa = SocketAddrV6::from_str("[::1]:6000").unwrap(); + let sock_addr: SockaddrIn6 = SockaddrIn6::from(std_sa); if let Err(Errno::EADDRNOTAVAIL) = bind(sock, &sock_addr) { println!("IPv6 not available, skipping test."); @@ -954,19 +922,15 @@ pub fn test_sendmsg_ipv6packetinfo() { let slice = [1u8, 2, 3, 4, 5, 6, 7, 8]; let iov = [IoVec::from_slice(&slice)]; - if let InetAddr::V6(sin) = inet_addr { - let pi = libc::in6_pktinfo { - ipi6_ifindex: 0, /* Unspecified interface */ - ipi6_addr: sin.sin6_addr, - }; + let pi = libc::in6_pktinfo { + ipi6_ifindex: 0, /* Unspecified interface */ + ipi6_addr: sock_addr.as_ref().sin6_addr, + }; - let cmsg = [ControlMessage::Ipv6PacketInfo(&pi)]; + let cmsg = [ControlMessage::Ipv6PacketInfo(&pi)]; - sendmsg(sock, &iov, &cmsg, MsgFlags::empty(), Some(&sock_addr)) - .expect("sendmsg"); - } else { - println!("No IPv6 addresses available for testing: skipping testing Ipv6PacketInfo"); - } + sendmsg::<SockaddrIn6>(sock, &iov, &cmsg, MsgFlags::empty(), Some(&sock_addr)) + .expect("sendmsg"); } /// Tests that passing multiple fds using a single `ControlMessage` works. @@ -987,7 +951,7 @@ fn test_scm_rights_single_cmsg_multiple_fds() { let mut buf = [0u8; 8]; let iovec = [IoVec::from_mut_slice(&mut buf)]; let mut space = cmsg_space!([RawFd; 2]); - let msg = recvmsg( + let msg = recvmsg::<()>( receive.as_raw_fd(), &iovec, Some(&mut space), @@ -1014,7 +978,7 @@ fn test_scm_rights_single_cmsg_multiple_fds() { let iov = [IoVec::from_slice(&slice)]; let fds = [libc::STDIN_FILENO, libc::STDOUT_FILENO]; // pass stdin and stdout let cmsg = [ControlMessage::ScmRights(&fds)]; - sendmsg(send.as_raw_fd(), &iov, &cmsg, MsgFlags::empty(), None).unwrap(); + sendmsg::<()>(send.as_raw_fd(), &iov, &cmsg, MsgFlags::empty(), None).unwrap(); thread.join().unwrap(); } @@ -1034,7 +998,7 @@ pub fn test_sendmsg_empty_cmsgs() { { let iov = [IoVec::from_slice(b"hello")]; - assert_eq!(sendmsg(fd1, &iov, &[], MsgFlags::empty(), None).unwrap(), 5); + assert_eq!(sendmsg::<()>(fd1, &iov, &[], MsgFlags::empty(), None).unwrap(), 5); close(fd1).unwrap(); } @@ -1042,7 +1006,7 @@ pub fn test_sendmsg_empty_cmsgs() { let mut buf = [0u8; 5]; let iov = [IoVec::from_mut_slice(&mut buf[..])]; let mut cmsgspace = cmsg_space!([RawFd; 1]); - let msg = recvmsg(fd2, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap(); + let msg = recvmsg::<()>(fd2, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap(); for _ in msg.cmsgs() { panic!("unexpected cmsg"); @@ -1083,7 +1047,7 @@ fn test_scm_credentials() { let cmsg = ControlMessage::ScmCredentials(&cred); #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] let cmsg = ControlMessage::ScmCreds; - assert_eq!(sendmsg(send, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(), 5); + assert_eq!(sendmsg::<()>(send, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(), 5); close(send).unwrap(); } @@ -1091,7 +1055,7 @@ fn test_scm_credentials() { let mut buf = [0u8; 5]; let iov = [IoVec::from_mut_slice(&mut buf[..])]; let mut cmsgspace = cmsg_space!(UnixCredentials); - let msg = recvmsg(recv, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap(); + let msg = recvmsg::<()>(recv, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap(); let mut received_cred = None; for cmsg in msg.cmsgs() { @@ -1168,7 +1132,7 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) { ControlMessage::ScmCredentials(&cred), ControlMessage::ScmRights(&fds), ]; - assert_eq!(sendmsg(send, &iov, &cmsgs, MsgFlags::empty(), None).unwrap(), 5); + assert_eq!(sendmsg::<()>(send, &iov, &cmsgs, MsgFlags::empty(), None).unwrap(), 5); close(r).unwrap(); close(send).unwrap(); } @@ -1176,7 +1140,7 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) { { let mut buf = [0u8; 5]; let iov = [IoVec::from_mut_slice(&mut buf[..])]; - let msg = recvmsg(recv, &iov, Some(&mut space), MsgFlags::empty()).unwrap(); + let msg = recvmsg::<()>(recv, &iov, Some(&mut space), MsgFlags::empty()).unwrap(); let mut received_cred = None; assert_eq!(msg.cmsgs().count(), 2, "expected 2 cmsgs"); @@ -1218,7 +1182,7 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) { #[test] pub fn test_unixdomain() { use nix::sys::socket::{SockType, SockFlag}; - use nix::sys::socket::{bind, socket, connect, listen, accept, SockAddr}; + use nix::sys::socket::{bind, socket, connect, listen, accept, UnixAddr}; use nix::unistd::{read, write, close}; use std::thread; @@ -1226,7 +1190,7 @@ pub fn test_unixdomain() { let sockname = tempdir.path().join("sock"); let s1 = socket(AddressFamily::Unix, SockType::Stream, SockFlag::empty(), None).expect("socket failed"); - let sockaddr = SockAddr::new_unix(&sockname).unwrap(); + let sockaddr = UnixAddr::new(&sockname).unwrap(); bind(s1, &sockaddr).expect("bind failed"); listen(s1, 10).expect("listen failed"); @@ -1254,13 +1218,14 @@ pub fn test_unixdomain() { #[test] pub fn test_syscontrol() { use nix::errno::Errno; - use nix::sys::socket::{socket, SockAddr, SockType, SockFlag, SockProtocol}; + use nix::sys::socket::{socket, SysControlAddr, SockType, SockFlag, SockProtocol}; let fd = socket(AddressFamily::System, SockType::Datagram, SockFlag::empty(), SockProtocol::KextControl) .expect("socket failed"); - let _sockaddr = SockAddr::new_sys_control(fd, "com.apple.net.utun_control", 0).expect("resolving sys_control name failed"); - assert_eq!(SockAddr::new_sys_control(fd, "foo.bar.lol", 0).err(), Some(Errno::ENOENT)); + SysControlAddr::from_name(fd, "com.apple.net.utun_control", 0) + .expect("resolving sys_control name failed"); + assert_eq!(SysControlAddr::from_name(fd, "foo.bar.lol", 0).err(), Some(Errno::ENOENT)); // requires root privileges // connect(fd, &sockaddr).expect("connect failed"); @@ -1280,6 +1245,7 @@ fn loopback_address(family: AddressFamily) -> Option<nix::ifaddrs::InterfaceAddr use std::io::Write; use nix::ifaddrs::getifaddrs; use nix::net::if_::*; + use nix::sys::socket::SockaddrLike; let addrs = match getifaddrs() { Ok(iter) => iter, @@ -1292,22 +1258,10 @@ fn loopback_address(family: AddressFamily) -> Option<nix::ifaddrs::InterfaceAddr }; // return first address matching family for ifaddr in addrs { - if ifaddr.flags.contains(InterfaceFlags::IFF_LOOPBACK) { - match ifaddr.address { - Some(SockAddr::Inet(InetAddr::V4(..))) => { - match family { - AddressFamily::Inet => return Some(ifaddr), - _ => continue - } - }, - Some(SockAddr::Inet(InetAddr::V6(..))) => { - match family { - AddressFamily::Inet6 => return Some(ifaddr), - _ => continue - } - }, - _ => continue, - } + if ifaddr.flags.contains(InterfaceFlags::IFF_LOOPBACK) && + ifaddr.address.as_ref().and_then(SockaddrLike::family) == Some(family) + { + return Some(ifaddr) } } None @@ -1332,7 +1286,7 @@ fn loopback_address(family: AddressFamily) -> Option<nix::ifaddrs::InterfaceAddr #[test] pub fn test_recv_ipv4pktinfo() { use nix::sys::socket::sockopt::Ipv4PacketInfo; - use nix::sys::socket::{bind, SockFlag, SockType}; + use nix::sys::socket::{bind, SockaddrIn, SockFlag, SockType}; use nix::sys::socket::{getsockname, setsockopt, socket}; use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; use nix::sys::uio::IoVec; @@ -1351,7 +1305,7 @@ pub fn test_recv_ipv4pktinfo() { None, ).expect("receive socket failed"); bind(receive, &lo).expect("bind failed"); - let sa = getsockname(receive).expect("getsockname failed"); + let sa: SockaddrIn = getsockname(receive).expect("getsockname failed"); setsockopt(receive, Ipv4PacketInfo, &true).expect("setsockopt failed"); { @@ -1371,7 +1325,7 @@ pub fn test_recv_ipv4pktinfo() { let mut buf = [0u8; 8]; let iovec = [IoVec::from_mut_slice(&mut buf)]; let mut space = cmsg_space!(libc::in_pktinfo); - let msg = recvmsg( + let msg = recvmsg::<()>( receive, &iovec, Some(&mut space), @@ -1422,8 +1376,8 @@ pub fn test_recv_ipv4pktinfo() { pub fn test_recvif() { use nix::net::if_::*; use nix::sys::socket::sockopt::{Ipv4RecvIf, Ipv4RecvDstAddr}; - use nix::sys::socket::{bind, SockFlag, SockType}; - use nix::sys::socket::{getsockname, setsockopt, socket, SockAddr}; + use nix::sys::socket::{bind, SockaddrIn, SockFlag, SockType}; + use nix::sys::socket::{getsockname, setsockopt, socket}; use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; use nix::sys::uio::IoVec; @@ -1440,7 +1394,7 @@ pub fn test_recvif() { None, ).expect("receive socket failed"); bind(receive, &lo).expect("bind failed"); - let sa = getsockname(receive).expect("getsockname failed"); + let sa: SockaddrIn = getsockname(receive).expect("getsockname failed"); setsockopt(receive, Ipv4RecvIf, &true).expect("setsockopt IP_RECVIF failed"); setsockopt(receive, Ipv4RecvDstAddr, &true).expect("setsockopt IP_RECVDSTADDR failed"); @@ -1461,7 +1415,7 @@ pub fn test_recvif() { let mut buf = [0u8; 8]; let iovec = [IoVec::from_mut_slice(&mut buf)]; let mut space = cmsg_space!(libc::sockaddr_dl, libc::in_addr); - let msg = recvmsg( + let msg = recvmsg::<()>( receive, &iovec, Some(&mut space), @@ -1490,11 +1444,11 @@ pub fn test_recvif() { }, ControlMessageOwned::Ipv4RecvDstAddr(addr) => { rx_recvdstaddr = true; - if let SockAddr::Inet(InetAddr::V4(a)) = lo { - assert_eq!(a.sin_addr.s_addr, + if let Some(sin) = lo.as_sockaddr_in() { + assert_eq!(sin.as_ref().sin_addr.s_addr, addr.s_addr, "unexpected destination address (expected {}, got {})", - a.sin_addr.s_addr, + sin.as_ref().sin_addr.s_addr, addr.s_addr); } else { panic!("unexpected Sockaddr"); @@ -1535,7 +1489,7 @@ pub fn test_recvif() { pub fn test_recv_ipv6pktinfo() { use nix::net::if_::*; use nix::sys::socket::sockopt::Ipv6RecvPacketInfo; - use nix::sys::socket::{bind, SockFlag, SockType}; + use nix::sys::socket::{bind, SockaddrIn6, SockFlag, SockType}; use nix::sys::socket::{getsockname, setsockopt, socket}; use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags}; use nix::sys::uio::IoVec; @@ -1553,7 +1507,7 @@ pub fn test_recv_ipv6pktinfo() { None, ).expect("receive socket failed"); bind(receive, &lo).expect("bind failed"); - let sa = getsockname(receive).expect("getsockname failed"); + let sa: SockaddrIn6 = getsockname(receive).expect("getsockname failed"); setsockopt(receive, Ipv6RecvPacketInfo, &true).expect("setsockopt failed"); { @@ -1573,7 +1527,7 @@ pub fn test_recv_ipv6pktinfo() { let mut buf = [0u8; 8]; let iovec = [IoVec::from_mut_slice(&mut buf)]; let mut space = cmsg_space!(libc::in6_pktinfo); - let msg = recvmsg( + let msg = recvmsg::<()>( receive, &iovec, Some(&mut space), @@ -1611,7 +1565,7 @@ pub fn test_recv_ipv6pktinfo() { pub fn test_vsock() { use nix::errno::Errno; use nix::sys::socket::{AddressFamily, socket, bind, connect, listen, - SockAddr, SockType, SockFlag}; + SockType, SockFlag, VsockAddr}; use nix::unistd::{close}; use std::thread; @@ -1622,12 +1576,12 @@ pub fn test_vsock() { .expect("socket failed"); // VMADDR_CID_HYPERVISOR is reserved, so we expect an EADDRNOTAVAIL error. - let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_HYPERVISOR, port); - assert_eq!(bind(s1, &sockaddr).err(), + let sockaddr_hv = VsockAddr::new(libc::VMADDR_CID_HYPERVISOR, port); + assert_eq!(bind(s1, &sockaddr_hv).err(), Some(Errno::EADDRNOTAVAIL)); - let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_ANY, port); - assert_eq!(bind(s1, &sockaddr), Ok(())); + let sockaddr_any = VsockAddr::new(libc::VMADDR_CID_ANY, port); + assert_eq!(bind(s1, &sockaddr_any), Ok(())); listen(s1, 10).expect("listen failed"); let thr = thread::spawn(move || { @@ -1637,11 +1591,11 @@ pub fn test_vsock() { SockFlag::empty(), None) .expect("socket failed"); - let sockaddr = SockAddr::new_vsock(cid, port); + let sockaddr_host = VsockAddr::new(cid, port); // The current implementation does not support loopback devices, so, // for now, we expect a failure on the connect. - assert_ne!(connect(s2, &sockaddr), Ok(())); + assert_ne!(connect(s2, &sockaddr_host), Ok(())); close(s2).unwrap(); }); @@ -1669,9 +1623,9 @@ fn test_recvmsg_timestampns() { SockFlag::empty(), None).unwrap(); setsockopt(in_socket, sockopt::ReceiveTimestampns, &true).unwrap(); - let localhost = InetAddr::new(IpAddr::new_v4(127, 0, 0, 1), 0); - bind(in_socket, &SockAddr::new_inet(localhost)).unwrap(); - let address = getsockname(in_socket).unwrap(); + let localhost = SockaddrIn::new(127, 0, 0, 1, 0); + bind(in_socket, &localhost).unwrap(); + let address: SockaddrIn = getsockname(in_socket).unwrap(); // Get initial time let time0 = SystemTime::now(); // Send the message @@ -1683,7 +1637,7 @@ fn test_recvmsg_timestampns() { let mut buffer = vec![0u8; message.len()]; let mut cmsgspace = nix::cmsg_space!(TimeSpec); let iov = [IoVec::from_mut_slice(&mut buffer)]; - let r = recvmsg(in_socket, &iov, Some(&mut cmsgspace), flags).unwrap(); + let r = recvmsg::<()>(in_socket, &iov, Some(&mut cmsgspace), flags).unwrap(); let rtime = match r.cmsgs().next() { Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime, Some(_) => panic!("Unexpected control message"), @@ -1720,9 +1674,9 @@ fn test_recvmmsg_timestampns() { SockFlag::empty(), None).unwrap(); setsockopt(in_socket, sockopt::ReceiveTimestampns, &true).unwrap(); - let localhost = InetAddr::new(IpAddr::new_v4(127, 0, 0, 1), 0); - bind(in_socket, &SockAddr::new_inet(localhost)).unwrap(); - let address = getsockname(in_socket).unwrap(); + let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap(); + bind(in_socket, &localhost).unwrap(); + let address: SockaddrIn = getsockname(in_socket).unwrap(); // Get initial time let time0 = SystemTime::now(); // Send the message @@ -1740,7 +1694,7 @@ fn test_recvmmsg_timestampns() { cmsg_buffer: Some(&mut cmsgspace), }, ]; - let r = recvmmsg(in_socket, &mut data, flags, None).unwrap(); + let r: Vec<RecvMsg<()>> = recvmmsg(in_socket, &mut data, flags, None).unwrap(); let rtime = match r[0].cmsgs().next() { Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime, Some(_) => panic!("Unexpected control message"), @@ -1783,10 +1737,10 @@ fn test_recvmsg_rxq_ovfl() { SockFlag::empty(), None).unwrap(); - let localhost = InetAddr::new(IpAddr::new_v4(127, 0, 0, 1), 0); - bind(in_socket, &SockAddr::new_inet(localhost)).unwrap(); + let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap(); + bind(in_socket, &localhost).unwrap(); - let address = getsockname(in_socket).unwrap(); + let address: SockaddrIn = getsockname(in_socket).unwrap(); connect(out_socket, &address).unwrap(); // Set SO_RXQ_OVFL flag. @@ -1815,7 +1769,7 @@ fn test_recvmsg_rxq_ovfl() { let iov = [IoVec::from_mut_slice(&mut buffer)]; - match recvmsg( + match recvmsg::<()>( in_socket, &iov, Some(&mut cmsgspace), @@ -1847,7 +1801,7 @@ fn test_recvmsg_rxq_ovfl() { ))] mod linux_errqueue { use nix::sys::socket::*; - use super::{FromStr, SocketAddr}; + use super::FromStr; // Send a UDP datagram to a bogus destination address and observe an ICMP error (v4). // @@ -1953,12 +1907,8 @@ mod linux_errqueue { use nix::sys::uio::IoVec; const MESSAGE_CONTENTS: &str = "ABCDEF"; - - let sock_addr = { - let std_sa = SocketAddr::from_str(sa).unwrap(); - let inet_addr = InetAddr::from_std(&std_sa); - SockAddr::new_inet(inet_addr) - }; + let std_sa = std::net::SocketAddr::from_str(sa).unwrap(); + let sock_addr = SockaddrStorage::from(std_sa); let sock = socket(af, SockType::Datagram, SockFlag::SOCK_CLOEXEC, None).unwrap(); setsockopt(sock, opt, &true).unwrap(); if let Err(e) = sendto(sock, MESSAGE_CONTENTS.as_bytes(), &sock_addr, MsgFlags::empty()) { @@ -2006,16 +1956,14 @@ mod linux_errqueue { pub fn test_txtime() { use nix::sys::socket::{ bind, recvmsg, sendmsg, setsockopt, socket, sockopt, ControlMessage, - MsgFlags, SockFlag, SockType, + MsgFlags, SockaddrIn, SockFlag, SockType, }; use nix::sys::time::TimeValLike; use nix::time::{ClockId, clock_gettime}; require_kernel_version!(test_txtime, ">= 5.8"); - let std_sa = SocketAddr::from_str("127.0.0.1:6802").unwrap(); - let inet_addr = InetAddr::from_std(&std_sa); - let sock_addr = SockAddr::new_inet(inet_addr); + let sock_addr = SockaddrIn::from_str("127.0.0.1:6802").unwrap(); let ssock = socket( AddressFamily::Inet, @@ -2052,5 +2000,5 @@ pub fn test_txtime() { let mut rbuf = [0u8; 2048]; let iov2 = [nix::sys::uio::IoVec::from_mut_slice(&mut rbuf)]; - recvmsg(rsock, &iov2, None, MsgFlags::empty()).unwrap(); + recvmsg::<()>(rsock, &iov2, None, MsgFlags::empty()).unwrap(); } diff --git a/test/sys/test_sockopt.rs b/test/sys/test_sockopt.rs index 59b97c8b..df01e9ee 100644 --- a/test/sys/test_sockopt.rs +++ b/test/sys/test_sockopt.rs @@ -72,14 +72,13 @@ fn test_so_buf() { #[test] fn test_so_tcp_maxseg() { - use std::net::SocketAddr; + use std::net::SocketAddrV4; use std::str::FromStr; - use nix::sys::socket::{accept, bind, connect, listen, InetAddr, SockAddr}; + use nix::sys::socket::{accept, bind, connect, listen, SockaddrIn}; use nix::unistd::{close, write}; - let std_sa = SocketAddr::from_str("127.0.0.1:4001").unwrap(); - let inet_addr = InetAddr::from_std(&std_sa); - let sock_addr = SockAddr::new_inet(inet_addr); + let std_sa = SocketAddrV4::from_str("127.0.0.1:4001").unwrap(); + let sock_addr = SockaddrIn::from(std_sa); let rsock = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), SockProtocol::Tcp) .unwrap(); |