diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fcdcbe48e..aa4888d973 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added `SOF_TIMESTAMPING_OPT_ID` and `SOF_TIMESTAMPING_OPT_TSONLY` to `nix::sys::socket::TimestampingFlag`. ([#2048](https://github.com/nix-rust/nix/pull/2048)) - Enabled socket timestamping options on Android. ([#2077](https://github.com/nix-rust/nix/pull/2077)) +- Added vsock support for macOS ([#2056](https://github.com/nix-rust/nix/pull/2056)) - Added `SO_SETFIB` and `SO_USER_COOKIE` to `nix::sys::socket::sockopt` for FreeBSD. ([#2085](https://github.com/nix-rust/nix/pull/2085)) diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 1d86e756f9..685acf7bb3 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -13,7 +13,7 @@ ))] #[cfg(feature = "net")] pub use self::datalink::LinkAddr; -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] pub use self::vsock::VsockAddr; use super::sa_family_t; use crate::errno::Errno; @@ -248,7 +248,7 @@ pub enum AddressFamily { #[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(any(target_os = "android", target_os = "linux", target_os = "macos"))] #[cfg_attr(docsrs, doc(cfg(all())))] Vsock = libc::AF_VSOCK, /// ARPANet IMP addresses @@ -443,7 +443,7 @@ impl AddressFamily { target_os = "openbsd" ))] libc::AF_LINK => Some(AddressFamily::Link), - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] libc::AF_VSOCK => Some(AddressFamily::Vsock), _ => None, } @@ -1286,7 +1286,7 @@ pub union SockaddrStorage { sin6: SockaddrIn6, ss: libc::sockaddr_storage, su: UnixAddr, - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos" ))] #[cfg_attr(docsrs, doc(cfg(all())))] vsock: VsockAddr, } @@ -1378,7 +1378,7 @@ impl SockaddrLike for SockaddrStorage { libc::AF_SYSTEM => { SysControlAddr::from_raw(addr, l).map(|sctl| Self { sctl }) } - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos" ))] libc::AF_VSOCK => { VsockAddr::from_raw(addr, l).map(|vsock| Self { vsock }) } @@ -1554,7 +1554,7 @@ impl SockaddrStorage { 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(any(target_os = "android", target_os = "linux", target_os = "macos"))] #[cfg_attr(docsrs, doc(cfg(all())))] accessors! {as_vsock_addr, as_vsock_addr_mut, VsockAddr, AddressFamily::Vsock, libc::sockaddr_vm, vsock} @@ -1604,7 +1604,7 @@ impl fmt::Display for SockaddrStorage { #[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"))] + #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] libc::AF_VSOCK => self.vsock.fmt(f), _ => "
".fmt(f), } @@ -1678,7 +1678,7 @@ impl Hash for SockaddrStorage { #[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"))] + #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] libc::AF_VSOCK => self.vsock.hash(s), _ => self.ss.hash(s), } @@ -1720,7 +1720,7 @@ impl PartialEq for SockaddrStorage { #[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"))] + #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] (libc::AF_VSOCK, libc::AF_VSOCK) => self.vsock == other.vsock, _ => false, } @@ -2268,7 +2268,7 @@ mod datalink { } } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] #[cfg_attr(docsrs, doc(cfg(all())))] pub mod vsock { use super::*; @@ -2314,20 +2314,33 @@ pub mod vsock { } impl PartialEq for VsockAddr { + #[cfg(any(target_os = "android", target_os = "linux"))] fn eq(&self, other: &Self) -> bool { let (inner, other) = (self.0, other.0); (inner.svm_family, inner.svm_cid, inner.svm_port) == (other.svm_family, other.svm_cid, other.svm_port) } + #[cfg(target_os = "macos")] + fn eq(&self, other: &Self) -> bool { + let (inner, other) = (self.0, other.0); + (inner.svm_family, inner.svm_cid, inner.svm_port, inner.svm_len) + == (other.svm_family, other.svm_cid, other.svm_port, inner.svm_len) + } } impl Eq for VsockAddr {} impl Hash for VsockAddr { + #[cfg(any(target_os = "android", target_os = "linux"))] fn hash(&self, s: &mut H) { let inner = self.0; (inner.svm_family, inner.svm_cid, inner.svm_port).hash(s); } + #[cfg(target_os = "macos")] + fn hash(&self, s: &mut H) { + let inner = self.0; + (inner.svm_family, inner.svm_cid, inner.svm_port, inner.svm_len).hash(s); + } } /// VSOCK Address @@ -2342,6 +2355,10 @@ pub mod vsock { addr.svm_cid = cid; addr.svm_port = port; + #[cfg(target_os = "macos")] + { + addr.svm_len = std::mem::size_of::() as u8; + } VsockAddr(addr) } diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index c16e33467c..aec21d983d 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -62,7 +62,7 @@ pub use crate::sys::socket::addr::netlink::NetlinkAddr; #[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"))] +#[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] pub use crate::sys::socket::addr::vsock::VsockAddr; #[cfg(all(feature = "uio", not(target_os = "redox")))] diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index ad7b457ebf..0759dc609a 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -2122,6 +2122,49 @@ pub fn test_vsock() { assert_eq!(addr3.as_ref().svm_port, addr1.port()); } +#[cfg(target_os = "macos")] +#[test] +pub fn test_vsock() { + use nix::sys::socket::SockaddrLike; + use nix::sys::socket::{AddressFamily, VsockAddr}; + use std::mem; + + let port: u32 = 3000; + + // macOS doesn't have a VMADDR_CID_LOCAL, so test with host again + let addr_host = VsockAddr::new(libc::VMADDR_CID_HOST, port); + assert_eq!(addr_host.cid(), libc::VMADDR_CID_HOST); + assert_eq!(addr_host.port(), port); + + let addr_any = VsockAddr::new(libc::VMADDR_CID_ANY, libc::VMADDR_PORT_ANY); + assert_eq!(addr_any.cid(), libc::VMADDR_CID_ANY); + assert_eq!(addr_any.port(), libc::VMADDR_PORT_ANY); + + assert_ne!(addr_host, addr_any); + assert_ne!(calculate_hash(&addr_host), calculate_hash(&addr_any)); + + let addr1 = VsockAddr::new(libc::VMADDR_CID_HOST, port); + let addr2 = VsockAddr::new(libc::VMADDR_CID_HOST, port); + assert_eq!(addr1, addr2); + assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2)); + + let addr3 = unsafe { + VsockAddr::from_raw( + addr2.as_ref() as *const libc::sockaddr_vm as *const libc::sockaddr, + Some(mem::size_of::().try_into().unwrap()), + ) + } + .unwrap(); + assert_eq!( + addr3.as_ref().svm_family, + AddressFamily::Vsock as libc::sa_family_t + ); + let cid = addr3.as_ref().svm_cid; + let port = addr3.as_ref().svm_port; + assert_eq!(cid, addr1.cid()); + assert_eq!(port, addr1.port()); +} + // Disable the test on emulated platforms because it fails in Cirrus-CI. Lack // of QEMU support is suspected. #[cfg_attr(qemu, ignore)]