From 76d70b4b25ef499c8bb0a322590eb86e3370b548 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Tue, 21 Dec 2021 06:10:50 -0700 Subject: [PATCH] Replace the Sockaddr enum with a union The SockAddr enum is quite large, and the user must allocate space for the whole thing even though he usually knows what type he needs. Furthermore, thanks to the sa_family field, the sockaddr types are basically an enum even in C. So replace the ungainly enum with a SockaddrLike trait implemented by all sockaddr types and a SockaddrStorage union that has safe accessors. Also, deprecate InetAddr, which only existed to support SockAddr. Supplants #1504 Fixes #1544 --- CHANGELOG.md | 3 + src/ifaddrs.rs | 24 +- src/lib.rs | 1 + src/sys/socket/addr.rs | 1238 ++++++++++++++++++++++++++++++++++---- src/sys/socket/mod.rs | 197 +++--- test/sys/test_socket.rs | 320 +++++----- test/sys/test_sockopt.rs | 9 +- 7 files changed, 1402 insertions(+), 390 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e54639b79f..737148af47 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`. (#[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 ed6328f3ef..f834d30762 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, + pub address: Option, /// Netmask of this interface - pub netmask: Option, + pub netmask: Option, /// Broadcast address of this interface, if applicable - pub broadcast: Option, + pub broadcast: Option, /// Point-to-point destination address - pub destination: Option, + pub destination: Option, } 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 /// ``` diff --git a/src/lib.rs b/src/lib.rs index 6809382978..172ca3a1d5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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 7803ec76c7..9d22beea58 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) + -> Option 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::() 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 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` 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) + -> Option 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 { + // 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::() 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 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) + -> Option where Self: Sized + { + None + } + + fn family(&self) -> Option { + 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) + -> Option where Self: Sized + { + if let Some(l) = len { + if l != mem::size_of::() 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 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 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::() 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 { + 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) + -> Option where Self: Sized + { + if let Some(l) = len { + if l != mem::size_of::() 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 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 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::() 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 { + 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) + -> Option 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::() { + 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), + _ => "
".fmt(f) + } + } + } +} + +#[cfg(feature = "net")] +impl From 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 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 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(&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) + -> Option + { + 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) + -> Option where Self: Sized + { + if let Some(l) = len { + if l != mem::size_of::() 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 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) + -> Option where Self: Sized + { + if let Some(l) = l { + if l != mem::size_of::() 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 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) + -> Option where Self: Sized + { + if let Some(l) = len { + if l != mem::size_of::() 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 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::() 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 { 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) + -> Option where Self: Sized + { + if let Some(l) = len { + if l != mem::size_of::() 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 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) + -> Option where Self: Sized + { + if let Some(l) = len { + if l != mem::size_of::() 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 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) + -> Option where Self: Sized + { + if let Some(l) = len { + if l != mem::size_of::() 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 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 7ed2d82dd7..f5004b4541 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, + pub address: Option, 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::(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 +/// +/// # 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(fd: RawFd, iov: &[IoVec<&[u8]>], cmsgs: &[ControlMessage], + flags: MsgFlags, addr: Option<&S>) -> Result + 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, + pub addr: Option, 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>, + data: impl std::iter::IntoIterator>, flags: MsgFlags ) -> Result> 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, IntoIter=impl ExactSizeIterator + Iterator>>, flags: MsgFlags, timeout: Option -) -> Result>> +) -> Result>> 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> -) -> 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>, - 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::::zeroed(); let p = mhdr.as_mut_ptr(); - (*p).msg_name = address as *mut c_void; - (*p).msg_namelen = mem::size_of::() 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::::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>, - flags: MsgFlags) -> Result> + flags: MsgFlags) -> Result> + 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 { /// 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 { /// 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)> +pub fn recvfrom(sockfd: RawFd, buf: &mut [u8]) + -> Result<(usize, Option)> { unsafe { - let mut addr: sockaddr_storage = mem::zeroed(); - let mut len = mem::size_of::() as socklen_t; + let mut addr = mem::MaybeUninit::uninit(); + let mut len = mem::size_of::() 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 { +pub fn sendto(fd: RawFd, buf: &[u8], addr: &dyn SockaddrLike, flags: MsgFlags) -> Result { 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(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 { +pub fn getpeername(fd: RawFd) -> Result { unsafe { - let mut addr = mem::MaybeUninit::uninit(); - let mut len = mem::size_of::() as socklen_t; + let mut addr = mem::MaybeUninit::::uninit(); + let mut len = T::size(); let ret = libc::getpeername( fd, @@ -1967,17 +2011,18 @@ pub fn getpeername(fd: RawFd) -> Result { 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 { +pub fn getsockname(fd: RawFd) -> Result { unsafe { - let mut addr = mem::MaybeUninit::uninit(); - let mut len = mem::size_of::() as socklen_t; + let mut addr = mem::MaybeUninit::::uninit(); + let mut len = T::size(); let ret = libc::getsockname( fd, @@ -1987,7 +2032,8 @@ pub fn getsockname(fd: RawFd) -> Result { 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 { /// 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 { diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 01f5f87875..e03edc3b40 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(rsock: RawFd, ssock: RawFd, f_send: Fs, mut f_recv: Fr) -> Option + fn sendrecv(rsock: RawFd, ssock: RawFd, f_send: Fs, mut f_recv: Fr) -> Option where Fs: Fn(RawFd, &[u8], MsgFlags) -> Result + Send + 'static, - Fr: FnMut(usize, Option), + Fr: FnMut(usize, Option), { 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> = 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> = 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::(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) { 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) { { 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) { #[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 iter, @@ -1292,22 +1258,10 @@ fn loopback_address(family: AddressFamily) -> Option { - 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( 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> = 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 59b97c8b7a..df01e9ee11 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();