From 6c7418ac9d508a8594d77100004ad31a42771075 Mon Sep 17 00:00:00 2001 From: Conrad Kramer Date: Fri, 25 Nov 2016 00:06:22 -0500 Subject: [PATCH 1/5] Fix typo in documentation --- src/sys/ioctl/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sys/ioctl/mod.rs b/src/sys/ioctl/mod.rs index 4d4d10720a..387024f4c5 100644 --- a/src/sys/ioctl/mod.rs +++ b/src/sys/ioctl/mod.rs @@ -90,7 +90,7 @@ //! How do I get the magic numbers? //! =============================== //! -//! For Linux, look at your system's headers. For example, `/usr/include/linxu/input.h` has a lot +//! For Linux, look at your system's headers. For example, `/usr/include/linux/input.h` has a lot //! of lines defining macros which use `_IOR`, `_IOW`, `_IOC`, and `_IORW`. These macros //! correspond to the `ior!`, `iow!`, `ioc!`, and `iorw!` macros defined in this crate. //! Additionally, there is the `ioctl!` macro for creating a wrapper around `ioctl` that is From cfcd249acd6b079534ee085e3469b0720e17e1c9 Mon Sep 17 00:00:00 2001 From: Conrad Kramer Date: Fri, 25 Nov 2016 00:06:58 -0500 Subject: [PATCH 2/5] Change the readwrite buf ioctl call to use a *mut pointer --- src/sys/ioctl/platform/linux.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sys/ioctl/platform/linux.rs b/src/sys/ioctl/platform/linux.rs index 603112241e..3719fd0c87 100644 --- a/src/sys/ioctl/platform/linux.rs +++ b/src/sys/ioctl/platform/linux.rs @@ -141,7 +141,7 @@ macro_rules! ioctl { ); (readwrite buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => ( pub unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int, - val: *const $ty, + val: *mut $ty, len: usize) -> $crate::Result<$crate::sys::ioctl::libc::c_int> { convert_ioctl_res!($crate::sys::ioctl::ioctl(fd, iorw!($ioty, $nr, len) as $crate::sys::ioctl::libc::c_ulong, val)) From bfb91506316a98500e0b1ed8a2a847831cf0cccb Mon Sep 17 00:00:00 2001 From: Conrad Kramer Date: Fri, 25 Nov 2016 00:10:15 -0500 Subject: [PATCH 3/5] Add ioctl support for BSD --- CHANGELOG.md | 4 + src/sys/ioctl/mod.rs | 105 ++++++++++++++++++------ src/sys/ioctl/platform/bsd.rs | 36 ++++++++ src/sys/ioctl/platform/dragonfly.rs | 0 src/sys/ioctl/platform/freebsd.rs | 0 src/sys/ioctl/platform/ios.rs | 0 src/sys/ioctl/platform/linux.rs | 72 ---------------- src/sys/ioctl/platform/macos.rs | 0 src/sys/ioctl/platform/netbsd.rs | 0 src/sys/ioctl/platform/openbsd.rs | 0 src/sys/mod.rs | 2 +- test/sys/test_ioctl.rs | 123 ++++++++++++++++++++-------- 12 files changed, 206 insertions(+), 136 deletions(-) create mode 100644 src/sys/ioctl/platform/bsd.rs delete mode 100644 src/sys/ioctl/platform/dragonfly.rs delete mode 100644 src/sys/ioctl/platform/freebsd.rs delete mode 100644 src/sys/ioctl/platform/ios.rs delete mode 100644 src/sys/ioctl/platform/macos.rs delete mode 100644 src/sys/ioctl/platform/netbsd.rs delete mode 100644 src/sys/ioctl/platform/openbsd.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 6dd85e1c98..232128da36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Added +- Added support for `ioctl` calls on BSD platforms + ([#478](https://github.com/nix-rust/nix/pull/478)) - Added struct `TimeSpec` ([#475](https://github.com/nix-rust/nix/pull/475)) - Added complete definitions for all kqueue-related constants on all supported @@ -24,6 +26,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ([#457](https://github.com/nix-rust/nix/pull/457)) ### Changed +- Removed the `bad` keyword from the `ioctl!` macro + ([#478](https://github.com/nix-rust/nix/pull/478)) - Changed `TimeVal` into an opaque Newtype ([#475](https://github.com/nix-rust/nix/pull/475)) - `kill`'s signature, defined in `::nix::sys::signal`, changed, so that the diff --git a/src/sys/ioctl/mod.rs b/src/sys/ioctl/mod.rs index 387024f4c5..a04e9d39f4 100644 --- a/src/sys/ioctl/mod.rs +++ b/src/sys/ioctl/mod.rs @@ -104,33 +104,13 @@ #[macro_use] mod platform; -#[cfg(target_os = "macos")] -#[path = "platform/macos.rs"] -#[macro_use] -mod platform; - -#[cfg(target_os = "ios")] -#[path = "platform/ios.rs"] -#[macro_use] -mod platform; - -#[cfg(target_os = "freebsd")] -#[path = "platform/freebsd.rs"] -#[macro_use] -mod platform; - -#[cfg(target_os = "netbsd")] -#[path = "platform/netbsd.rs"] -#[macro_use] -mod platform; - -#[cfg(target_os = "openbsd")] -#[path = "platform/openbsd.rs"] -#[macro_use] -mod platform; - -#[cfg(target_os = "dragonfly")] -#[path = "platform/dragonfly.rs"] +#[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "netbsd", + target_os = "openbsd", + target_os = "freebsd", + target_os = "dragonfly"))] +#[path = "platform/bsd.rs"] #[macro_use] mod platform; @@ -145,3 +125,74 @@ extern "C" { /// A hack to get the macros to work nicely. #[doc(hidden)] pub use ::libc as libc; + +/// Convert raw ioctl return value to a Nix result +#[macro_export] +macro_rules! convert_ioctl_res { + ($w:expr) => ( + { + $crate::Errno::result($w) + } + ); +} + +#[macro_export] +macro_rules! ioctl { + ($name:ident with $nr:expr) => ( + pub unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int, + data: *mut u8) + -> $crate::Result<$crate::sys::ioctl::libc::c_int> { + convert_ioctl_res!($crate::sys::ioctl::ioctl(fd, $nr as $crate::sys::ioctl::libc::c_ulong, data)) + } + ); + (none $name:ident with $ioty:expr, $nr:expr) => ( + pub unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int) + -> $crate::Result<$crate::sys::ioctl::libc::c_int> { + convert_ioctl_res!($crate::sys::ioctl::ioctl(fd, io!($ioty, $nr) as $crate::sys::ioctl::libc::c_ulong)) + } + ); + (read $name:ident with $ioty:expr, $nr:expr; $ty:ty) => ( + pub unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int, + val: *mut $ty) + -> $crate::Result<$crate::sys::ioctl::libc::c_int> { + convert_ioctl_res!($crate::sys::ioctl::ioctl(fd, ior!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::libc::c_ulong, val)) + } + ); + (write $name:ident with $ioty:expr, $nr:expr; $ty:ty) => ( + pub unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int, + val: *const $ty) + -> $crate::Result<$crate::sys::ioctl::libc::c_int> { + convert_ioctl_res!($crate::sys::ioctl::ioctl(fd, iow!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::libc::c_ulong, val)) + } + ); + (readwrite $name:ident with $ioty:expr, $nr:expr; $ty:ty) => ( + pub unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int, + val: *mut $ty) + -> $crate::Result<$crate::sys::ioctl::libc::c_int> { + convert_ioctl_res!($crate::sys::ioctl::ioctl(fd, iorw!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::libc::c_ulong, val)) + } + ); + (read buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => ( + pub unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int, + val: *mut $ty, + len: usize) + -> $crate::Result<$crate::sys::ioctl::libc::c_int> { + convert_ioctl_res!($crate::sys::ioctl::ioctl(fd, ior!($ioty, $nr, len) as $crate::sys::ioctl::libc::c_ulong, val)) + } + ); + (write buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => ( + pub unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int, + val: *const $ty, + len: usize) -> $crate::Result<$crate::sys::ioctl::libc::c_int> { + convert_ioctl_res!($crate::sys::ioctl::ioctl(fd, iow!($ioty, $nr, len) as $crate::sys::ioctl::libc::c_ulong, val)) + } + ); + (readwrite buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => ( + pub unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int, + val: *mut $ty, + len: usize) + -> $crate::Result<$crate::sys::ioctl::libc::c_int> { + convert_ioctl_res!($crate::sys::ioctl::ioctl(fd, iorw!($ioty, $nr, len) as $crate::sys::ioctl::libc::c_ulong, val)) + } + ); +} diff --git a/src/sys/ioctl/platform/bsd.rs b/src/sys/ioctl/platform/bsd.rs new file mode 100644 index 0000000000..57b4d637ca --- /dev/null +++ b/src/sys/ioctl/platform/bsd.rs @@ -0,0 +1,36 @@ +mod consts { + pub const VOID: u32 = 0x20000000; + pub const OUT: u32 = 0x40000000; + pub const IN: u32 = 0x80000000; + pub const INOUT: u32 = (IN|OUT); + pub const IOCPARM_MASK: u32 = 0x1fff; +} + +pub use self::consts::*; + +#[macro_export] +macro_rules! ioc { + ($inout:expr, $group:expr, $num:expr, $len:expr) => ( + $inout | (($len as u32 & $crate::sys::ioctl::IOCPARM_MASK) << 16) | (($group as u32) << 8) | ($num as u32) + ) +} + +#[macro_export] +macro_rules! io { + ($g:expr, $n:expr) => (ioc!($crate::sys::ioctl::VOID, $g, $n, 0)) +} + +#[macro_export] +macro_rules! ior { + ($g:expr, $n:expr, $len:expr) => (ioc!($crate::sys::ioctl::OUT, $g, $n, $len)) +} + +#[macro_export] +macro_rules! iow { + ($g:expr, $n:expr, $len:expr) => (ioc!($crate::sys::ioctl::IN, $g, $n, $len)) +} + +#[macro_export] +macro_rules! iorw { + ($g:expr, $n:expr, $len:expr) => (ioc!($crate::sys::ioctl::INOUT, $g, $n, $len)) +} diff --git a/src/sys/ioctl/platform/dragonfly.rs b/src/sys/ioctl/platform/dragonfly.rs deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/sys/ioctl/platform/freebsd.rs b/src/sys/ioctl/platform/freebsd.rs deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/sys/ioctl/platform/ios.rs b/src/sys/ioctl/platform/ios.rs deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/sys/ioctl/platform/linux.rs b/src/sys/ioctl/platform/linux.rs index 3719fd0c87..aacea45936 100644 --- a/src/sys/ioctl/platform/linux.rs +++ b/src/sys/ioctl/platform/linux.rs @@ -77,78 +77,6 @@ macro_rules! iorw { ($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::READ | $crate::sys::ioctl::WRITE, $ty, $nr, $sz)) } -/// Convert raw ioctl return value to a Nix result -#[macro_export] -macro_rules! convert_ioctl_res { - ($w:expr) => ( - { - $crate::Errno::result($w) - } - ); -} - -/// Declare a wrapper function around an ioctl. -#[macro_export] -macro_rules! ioctl { - (bad $name:ident with $nr:expr) => ( - pub unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int, - data: *mut u8) - -> $crate::Result<$crate::sys::ioctl::libc::c_int> { - convert_ioctl_res!($crate::sys::ioctl::ioctl(fd, $nr as $crate::sys::ioctl::libc::c_ulong, data)) - } - ); - (none $name:ident with $ioty:expr, $nr:expr) => ( - pub unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int) - -> $crate::Result<$crate::sys::ioctl::libc::c_int> { - convert_ioctl_res!($crate::sys::ioctl::ioctl(fd, io!($ioty, $nr) as $crate::sys::ioctl::libc::c_ulong)) - } - ); - (read $name:ident with $ioty:expr, $nr:expr; $ty:ty) => ( - pub unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int, - val: *mut $ty) - -> $crate::Result<$crate::sys::ioctl::libc::c_int> { - convert_ioctl_res!($crate::sys::ioctl::ioctl(fd, ior!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::libc::c_ulong, val)) - } - ); - (write $name:ident with $ioty:expr, $nr:expr; $ty:ty) => ( - pub unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int, - val: *const $ty) - -> $crate::Result<$crate::sys::ioctl::libc::c_int> { - convert_ioctl_res!($crate::sys::ioctl::ioctl(fd, iow!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::libc::c_ulong, val)) - } - ); - (readwrite $name:ident with $ioty:expr, $nr:expr; $ty:ty) => ( - pub unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int, - val: *mut $ty) - -> $crate::Result<$crate::sys::ioctl::libc::c_int> { - convert_ioctl_res!($crate::sys::ioctl::ioctl(fd, iorw!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::libc::c_ulong, val)) - } - ); - (read buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => ( - pub unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int, - val: *mut $ty, - len: usize) - -> $crate::Result<$crate::sys::ioctl::libc::c_int> { - convert_ioctl_res!($crate::sys::ioctl::ioctl(fd, ior!($ioty, $nr, len) as $crate::sys::ioctl::libc::c_ulong, val)) - } - ); - (write buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => ( - pub unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int, - val: *const $ty, - len: usize) -> $crate::Result<$crate::sys::ioctl::libc::c_int> { - convert_ioctl_res!($crate::sys::ioctl::ioctl(fd, iow!($ioty, $nr, len) as $crate::sys::ioctl::libc::c_ulong, val)) - } - ); - (readwrite buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => ( - pub unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int, - val: *mut $ty, - len: usize) - -> $crate::Result<$crate::sys::ioctl::libc::c_int> { - convert_ioctl_res!($crate::sys::ioctl::ioctl(fd, iorw!($ioty, $nr, len) as $crate::sys::ioctl::libc::c_ulong, val)) - } - ); -} - /// Extracts the "direction" (read/write/none) from an encoded ioctl command. #[inline(always)] pub fn ioc_dir(nr: u32) -> u8 { diff --git a/src/sys/ioctl/platform/macos.rs b/src/sys/ioctl/platform/macos.rs deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/sys/ioctl/platform/netbsd.rs b/src/sys/ioctl/platform/netbsd.rs deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/sys/ioctl/platform/openbsd.rs b/src/sys/ioctl/platform/openbsd.rs deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/sys/mod.rs b/src/sys/mod.rs index 793bc70e05..706614dce4 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -12,7 +12,7 @@ pub mod eventfd; #[cfg(target_os = "linux")] pub mod memfd; -#[cfg(not(any(target_os = "ios", target_os = "freebsd", target_os = "dragonfly")))] +#[macro_use] pub mod ioctl; #[cfg(any(target_os = "linux", target_os = "android"))] diff --git a/test/sys/test_ioctl.rs b/test/sys/test_ioctl.rs index 94eca4471f..1d9fbcc834 100644 --- a/test/sys/test_ioctl.rs +++ b/test/sys/test_ioctl.rs @@ -1,9 +1,7 @@ #![allow(dead_code)] -#![cfg(target_os = "linux")] // no ioctl support for osx yet - // Simple tests to ensure macro generated fns compile -ioctl!(bad do_bad with 0x1234); +ioctl!(do_bad with 0x1234); ioctl!(none do_none with 0, 0); ioctl!(read read_test with 0, 0; u32); ioctl!(write write_test with 0, 0; u64); @@ -15,44 +13,97 @@ ioctl!(readwrite buf readwritebuf_test with 0, 0; u32); // See C code for source of values for op calculations: // https://gist.github.com/posborne/83ea6880770a1aef332e -#[test] -fn test_op_none() { - assert_eq!(io!(b'q', 10), 0x0000710A); - assert_eq!(io!(b'a', 255), 0x000061FF); -} +#[cfg(any(target_os = "linux", target_os = "android"))] +mod linux { + #[test] + fn test_op_none() { + assert_eq!(io!(b'q', 10), 0x0000710A); + assert_eq!(io!(b'a', 255), 0x000061FF); + } -#[test] -fn test_op_write() { - assert_eq!(iow!(b'z', 10, 1), 0x40017A0A); - assert_eq!(iow!(b'z', 10, 512), 0x42007A0A); -} + #[test] + fn test_op_write() { + assert_eq!(iow!(b'z', 10, 1), 0x40017A0A); + assert_eq!(iow!(b'z', 10, 512), 0x42007A0A); + } -#[cfg(target_pointer_width = "64")] -#[test] -fn test_op_write_64() { - assert_eq!(iow!(b'z', 10, (1 as u64) << 32), 0x40007A0A); -} + #[cfg(target_pointer_width = "64")] + #[test] + fn test_op_write_64() { + assert_eq!(iow!(b'z', 10, (1 as u64) << 32), 0x40007A0A); + } -#[test] -fn test_op_read() { - assert_eq!(ior!(b'z', 10, 1), 0x80017A0A); - assert_eq!(ior!(b'z', 10, 512), 0x82007A0A); -} + #[test] + fn test_op_read() { + assert_eq!(ior!(b'z', 10, 1), 0x80017A0A); + assert_eq!(ior!(b'z', 10, 512), 0x82007A0A); + } -#[cfg(target_pointer_width = "64")] -#[test] -fn test_op_read_64() { - assert_eq!(ior!(b'z', 10, (1 as u64) << 32), 0x80007A0A); -} + #[cfg(target_pointer_width = "64")] + #[test] + fn test_op_read_64() { + assert_eq!(ior!(b'z', 10, (1 as u64) << 32), 0x80007A0A); + } + + #[test] + fn test_op_read_write() { + assert_eq!(iorw!(b'z', 10, 1), 0xC0017A0A); + assert_eq!(iorw!(b'z', 10, 512), 0xC2007A0A); + } -#[test] -fn test_op_read_write() { - assert_eq!(iorw!(b'z', 10, 1), 0xC0017A0A); - assert_eq!(iorw!(b'z', 10, 512), 0xC2007A0A); + #[cfg(target_pointer_width = "64")] + #[test] + fn test_op_read_write_64() { + assert_eq!(iorw!(b'z', 10, (1 as u64) << 32), 0xC0007A0A); + } } -#[cfg(target_pointer_width = "64")] -#[test] -fn test_op_read_write_64() { - assert_eq!(iorw!(b'z', 10, (1 as u64) << 32), 0xC0007A0A); +#[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "netbsd", + target_os = "openbsd", + target_os = "freebsd", + target_os = "dragonfly"))] +mod bsd { + #[test] + fn test_op_none() { + assert_eq!(io!(b'q', 10), 0x2000710A); + assert_eq!(io!(b'a', 255), 0x200061FF); + } + + #[test] + fn test_op_write() { + assert_eq!(iow!(b'z', 10, 1), 0x80017A0A); + assert_eq!(iow!(b'z', 10, 512), 0x82007A0A); + } + + #[cfg(target_pointer_width = "64")] + #[test] + fn test_op_write_64() { + assert_eq!(iow!(b'z', 10, (1 as u64) << 32), 0x80007A0A); + } + + #[test] + fn test_op_read() { + assert_eq!(ior!(b'z', 10, 1), 0x40017A0A); + assert_eq!(ior!(b'z', 10, 512), 0x42007A0A); + } + + #[cfg(target_pointer_width = "64")] + #[test] + fn test_op_read_64() { + assert_eq!(ior!(b'z', 10, (1 as u64) << 32), 0x40007A0A); + } + + #[test] + fn test_op_read_write() { + assert_eq!(iorw!(b'z', 10, 1), 0xC0017A0A); + assert_eq!(iorw!(b'z', 10, 512), 0xC2007A0A); + } + + #[cfg(target_pointer_width = "64")] + #[test] + fn test_op_read_write_64() { + assert_eq!(iorw!(b'z', 10, (1 as u64) << 32), 0xC0007A0A); + } } From 954232c8919eab1583f7849c53199c9615e83204 Mon Sep 17 00:00:00 2001 From: Conrad Kramer Date: Fri, 25 Nov 2016 00:11:51 -0500 Subject: [PATCH 4/5] Add support for system control sockets for XNU --- CHANGELOG.md | 2 + src/sys/socket/addr.rs | 122 ++++++++++++++++++++++++++++++++++++++- src/sys/socket/consts.rs | 7 +++ test/sys/test_socket.rs | 17 ++++++ 4 files changed, 147 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 232128da36..54f4fac474 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Added +- Added support for XNU system control sockets + ([#478](https://github.com/nix-rust/nix/pull/478)) - Added support for `ioctl` calls on BSD platforms ([#478](https://github.com/nix-rust/nix/pull/478)) - Added struct `TimeSpec` diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 756ae345b5..5f8b130a90 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -7,6 +7,10 @@ use std::path::Path; use std::os::unix::ffi::OsStrExt; #[cfg(any(target_os = "linux", target_os = "android"))] use ::sys::socket::addr::netlink::NetlinkAddr; +#[cfg(any(target_os = "macos", target_os = "ios"))] +use std::os::unix::io::RawFd; +#[cfg(any(target_os = "macos", target_os = "ios"))] +use ::sys::socket::addr::sys_control::SysControlAddr; // TODO: uncomment out IpAddr functions: rust-lang/rfcs#988 @@ -26,6 +30,8 @@ pub enum AddressFamily { Netlink = consts::AF_NETLINK, #[cfg(any(target_os = "linux", target_os = "android"))] Packet = consts::AF_PACKET, + #[cfg(any(target_os = "macos", target_os = "ios"))] + System = consts::AF_SYSTEM, } #[derive(Copy)] @@ -475,7 +481,9 @@ pub enum SockAddr { Inet(InetAddr), Unix(UnixAddr), #[cfg(any(target_os = "linux", target_os = "android"))] - Netlink(NetlinkAddr) + Netlink(NetlinkAddr), + #[cfg(any(target_os = "macos", target_os = "ios"))] + SysControl(SysControlAddr), } impl SockAddr { @@ -492,6 +500,11 @@ impl SockAddr { SockAddr::Netlink(NetlinkAddr::new(pid, groups)) } + #[cfg(any(target_os = "macos", target_os = "ios"))] + pub fn new_sys_control(sockfd: RawFd, name: &str, unit: u32) -> Result { + SysControlAddr::from_name(sockfd, name, unit).map(|a| SockAddr::SysControl(a)) + } + pub fn family(&self) -> AddressFamily { match *self { SockAddr::Inet(InetAddr::V4(..)) => AddressFamily::Inet, @@ -499,6 +512,8 @@ impl SockAddr { SockAddr::Unix(..) => AddressFamily::Unix, #[cfg(any(target_os = "linux", target_os = "android"))] SockAddr::Netlink(..) => AddressFamily::Netlink, + #[cfg(any(target_os = "macos", target_os = "ios"))] + SockAddr::SysControl(..) => AddressFamily::System, } } @@ -513,6 +528,8 @@ impl SockAddr { SockAddr::Unix(UnixAddr(ref addr, len)) => (mem::transmute(addr), (len + offset_of!(libc::sockaddr_un, sun_path)) as libc::socklen_t), #[cfg(any(target_os = "linux", target_os = "android"))] SockAddr::Netlink(NetlinkAddr(ref sa)) => (mem::transmute(sa), mem::size_of::() as libc::socklen_t), + #[cfg(any(target_os = "macos", target_os = "ios"))] + SockAddr::SysControl(SysControlAddr(ref sa)) => (mem::transmute(sa), mem::size_of::() as libc::socklen_t), } } } @@ -545,6 +562,8 @@ impl hash::Hash for SockAddr { SockAddr::Unix(ref a) => a.hash(s), #[cfg(any(target_os = "linux", target_os = "android"))] SockAddr::Netlink(ref a) => a.hash(s), + #[cfg(any(target_os = "macos", target_os = "ios"))] + SockAddr::SysControl(ref a) => a.hash(s), } } } @@ -562,6 +581,8 @@ impl fmt::Display for SockAddr { SockAddr::Unix(ref unix) => unix.fmt(f), #[cfg(any(target_os = "linux", target_os = "android"))] SockAddr::Netlink(ref nl) => nl.fmt(f), + #[cfg(any(target_os = "macos", target_os = "ios"))] + SockAddr::SysControl(ref sc) => sc.fmt(f), } } } @@ -620,3 +641,102 @@ pub mod netlink { } } } + +#[cfg(any(target_os = "macos", target_os = "ios"))] +pub mod sys_control { + use ::sys::socket::consts; + use ::sys::socket::addr::{AddressFamily}; + use libc::{c_uchar, uint16_t, uint32_t}; + use std::{fmt, mem}; + use std::hash::{Hash, Hasher}; + use std::os::unix::io::RawFd; + use {Errno, Error, Result}; + + #[repr(C)] + pub struct ctl_ioc_info { + pub ctl_id: uint32_t, + pub ctl_name: [c_uchar; MAX_KCTL_NAME], + } + + const CTL_IOC_MAGIC: u8 = 'N' as u8; + const CTL_IOC_INFO: u8 = 3; + const MAX_KCTL_NAME: usize = 96; + + ioctl!(readwrite ctl_info with CTL_IOC_MAGIC, CTL_IOC_INFO; ctl_ioc_info); + + #[repr(C)] + #[derive(Copy, Clone)] + pub struct sockaddr_ctl { + pub sc_len: c_uchar, + pub sc_family: c_uchar, + pub ss_sysaddr: uint16_t, + pub sc_id: uint32_t, + pub sc_unit: uint32_t, + pub sc_reserved: [uint32_t; 5], + } + + #[derive(Copy, Clone)] + pub struct SysControlAddr(pub sockaddr_ctl); + + // , PartialEq, Eq, Debug, Hash + impl PartialEq for SysControlAddr { + fn eq(&self, other: &Self) -> bool { + let (inner, other) = (self.0, other.0); + (inner.sc_id, inner.sc_unit) == + (other.sc_id, other.sc_unit) + } + } + + impl Eq for SysControlAddr {} + + impl Hash for SysControlAddr { + fn hash(&self, s: &mut H) { + let inner = self.0; + (inner.sc_id, inner.sc_unit).hash(s); + } + } + + + impl SysControlAddr { + pub fn new(id: u32, unit: u32) -> SysControlAddr { + let addr = sockaddr_ctl { + sc_len: mem::size_of::() as c_uchar, + sc_family: AddressFamily::System as c_uchar, + ss_sysaddr: consts::AF_SYS_CONTROL as uint16_t, + sc_id: id, + sc_unit: unit, + sc_reserved: [0; 5] + }; + + SysControlAddr(addr) + } + + pub fn from_name(sockfd: RawFd, name: &str, unit: u32) -> Result { + if name.len() > MAX_KCTL_NAME { + return Err(Error::Sys(Errno::ENAMETOOLONG)); + } + + let mut ctl_name = [0; MAX_KCTL_NAME]; + ctl_name[..name.len()].clone_from_slice(name.as_bytes()); + let mut info = ctl_ioc_info { ctl_id: 0, ctl_name: ctl_name }; + + unsafe { try!(ctl_info(sockfd, &mut info)); } + + Ok(SysControlAddr::new(info.ctl_id, unit)) + } + + pub fn id(&self) -> u32 { + self.0.sc_id + } + + pub fn unit(&self) -> u32 { + self.0.sc_unit + } + } + + impl fmt::Display for SysControlAddr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "id: {} unit: {}", self.id(), self.unit()) + } + } +} diff --git a/src/sys/socket/consts.rs b/src/sys/socket/consts.rs index 63eaf28a01..3c5efdf72f 100644 --- a/src/sys/socket/consts.rs +++ b/src/sys/socket/consts.rs @@ -132,6 +132,11 @@ mod os { pub const AF_INET6: c_int = 28; #[cfg(any(target_os = "macos", target_os = "ios"))] pub const AF_INET6: c_int = 30; + #[cfg(any(target_os = "macos", target_os = "ios"))] + pub const AF_SYSTEM: c_int = 32; + + #[cfg(any(target_os = "macos", target_os = "ios"))] + pub const AF_SYS_CONTROL: c_int = 2; pub const SOCK_STREAM: c_int = 1; pub const SOCK_DGRAM: c_int = 2; @@ -144,6 +149,8 @@ mod os { pub const IPPROTO_IPV6: c_int = 41; pub const IPPROTO_TCP: c_int = 6; pub const IPPROTO_UDP: c_int = 17; + #[cfg(any(target_os = "macos", target_os = "ios"))] + pub const SYSPROTO_CONTROL: c_int = 2; pub const SO_ACCEPTCONN: c_int = 0x0002; pub const SO_BROADCAST: c_int = 0x0020; diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 9f4b42785f..b5465aa0b6 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -180,3 +180,20 @@ pub fn test_unixdomain() { assert_eq!(&buf[..], b"hello"); } + +// Test creating and using named system control sockets +#[cfg(any(target_os = "macos", target_os = "ios"))] +#[test] +pub fn test_syscontrol() { + use nix::{Errno, Error}; + use nix::sys::socket::{AddressFamily, SockType, SockFlag}; + use nix::sys::socket::{socket, SockAddr}; + use nix::sys::socket::SYSPROTO_CONTROL; + + let fd = socket(AddressFamily::System, SockType::Datagram, SockFlag::empty(), SYSPROTO_CONTROL).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(Error::Sys(Errno::ENOENT))); + + // requires root privileges + // connect(fd, &sockaddr).expect("connect failed"); +} From ef257e055688cd088c1a27034742412caa7e208a Mon Sep 17 00:00:00 2001 From: Conrad Kramer Date: Fri, 16 Dec 2016 00:12:43 -0800 Subject: [PATCH 5/5] Fix build on iOS platform --- src/sys/event.rs | 55 +++++++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/src/sys/event.rs b/src/sys/event.rs index 0ada5bd60d..405f38fcb8 100644 --- a/src/sys/event.rs +++ b/src/sys/event.rs @@ -19,7 +19,8 @@ pub struct KEvent { } #[cfg(any(target_os = "openbsd", target_os = "freebsd", - target_os = "dragonfly", target_os = "macos"))] + target_os = "dragonfly", target_os = "macos", + target_os = "ios"))] type type_of_udata = *mut ::c_void; #[cfg(any(target_os = "netbsd"))] type type_of_udata = intptr_t; @@ -33,23 +34,24 @@ pub enum EventFilter { EVFILT_AIO = libc::EVFILT_AIO, #[cfg(target_os = "dragonfly")] EVFILT_EXCEPT = libc::EVFILT_EXCEPT, - #[cfg(any(target_os = "macos", + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "dragonfly", target_os = "freebsd"))] EVFILT_FS = libc::EVFILT_FS, #[cfg(target_os = "freebsd")] EVFILT_LIO = libc::EVFILT_LIO, - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "macos", target_os = "ios"))] EVFILT_MACHPORT = libc::EVFILT_MACHPORT, EVFILT_PROC = libc::EVFILT_PROC, EVFILT_READ = libc::EVFILT_READ, EVFILT_SIGNAL = libc::EVFILT_SIGNAL, EVFILT_TIMER = libc::EVFILT_TIMER, #[cfg(any(target_os = "macos", + target_os = "ios", target_os = "dragonfly", target_os = "freebsd"))] EVFILT_USER = libc::EVFILT_USER, - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "macos", target_os = "ios"))] EVFILT_VM = libc::EVFILT_VM, EVFILT_VNODE = libc::EVFILT_VNODE, EVFILT_WRITE = libc::EVFILT_WRITE, @@ -70,7 +72,8 @@ pub enum EventFilter { EVFILT_TIMER = libc::EVFILT_TIMER, } -#[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "dragonfly"))] +#[cfg(any(target_os = "macos", target_os = "ios", + target_os = "freebsd", target_os = "dragonfly"))] pub type type_of_event_flag = u16; #[cfg(any(target_os = "netbsd", target_os = "openbsd"))] pub type type_of_event_flag = u32; @@ -86,15 +89,15 @@ libc_bitflags!{ EV_ENABLE, EV_EOF, EV_ERROR, - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "macos", target_os = "ios"))] EV_FLAG0, EV_FLAG1, #[cfg(target_os = "dragonfly")] EV_NODATA, EV_ONESHOT, - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "macos", target_os = "ios"))] EV_OOBAND, - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "macos", target_os = "ios"))] EV_POLL, #[cfg(not(target_os = "openbsd"))] EV_RECEIPT, @@ -104,7 +107,7 @@ libc_bitflags!{ bitflags!( flags FilterFlag: u32 { - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "macos", target_os = "ios"))] const NOTE_ABSOLUTE = libc::NOTE_ABSOLUTE, const NOTE_ATTRIB = libc::NOTE_ATTRIB, const NOTE_CHILD = libc::NOTE_CHILD, @@ -113,32 +116,38 @@ bitflags!( const NOTE_EOF = libc::NOTE_EOF, const NOTE_EXEC = libc::NOTE_EXEC, const NOTE_EXIT = libc::NOTE_EXIT, - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "macos", target_os = "ios"))] const NOTE_EXIT_REPARENTED = libc::NOTE_EXIT_REPARENTED, - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "macos", target_os = "ios"))] const NOTE_EXITSTATUS = libc::NOTE_EXITSTATUS, const NOTE_EXTEND = libc::NOTE_EXTEND, - #[cfg(any(target_os = "macos", + #[cfg(any(target_os = "macos", + target_os = "ios", target_os = "freebsd", target_os = "dragonfly"))] const NOTE_FFAND = libc::NOTE_FFAND, #[cfg(any(target_os = "macos", + target_os = "ios", target_os = "freebsd", target_os = "dragonfly"))] const NOTE_FFCOPY = libc::NOTE_FFCOPY, #[cfg(any(target_os = "macos", + target_os = "ios", target_os = "freebsd", target_os = "dragonfly"))] const NOTE_FFCTRLMASK = libc::NOTE_FFCTRLMASK, #[cfg(any(target_os = "macos", + target_os = "ios", target_os = "freebsd", target_os = "dragonfly"))] const NOTE_FFLAGSMASK = libc::NOTE_FFLAGSMASK, #[cfg(any(target_os = "macos", + target_os = "ios", target_os = "freebsd", target_os = "dragonfly"))] const NOTE_FFNOP = libc::NOTE_FFNOP, #[cfg(any(target_os = "macos", + target_os = "ios", target_os = "freebsd", target_os = "dragonfly"))] const NOTE_FFOR = libc::NOTE_FFOR, @@ -147,39 +156,40 @@ bitflags!( const NOTE_LOWAT = libc::NOTE_LOWAT, #[cfg(target_os = "freebsd")] const NOTE_MSECONDS = libc::NOTE_MSECONDS, - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "macos", target_os = "ios"))] const NOTE_NONE = libc::NOTE_NONE, - #[cfg(any(target_os = "macos", target_os = "freebsd"))] + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] const NOTE_NSECONDS = libc::NOTE_NSECONDS, #[cfg(target_os = "dragonfly")] const NOTE_OOB = libc::NOTE_OOB, const NOTE_PCTRLMASK = libc::NOTE_PCTRLMASK, const NOTE_PDATAMASK = libc::NOTE_PDATAMASK, - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "macos", target_os = "ios"))] const NOTE_REAP = libc::NOTE_REAP, const NOTE_RENAME = libc::NOTE_RENAME, const NOTE_REVOKE = libc::NOTE_REVOKE, - #[cfg(any(target_os = "macos", target_os = "freebsd"))] + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] const NOTE_SECONDS = libc::NOTE_SECONDS, - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "macos", target_os = "ios"))] const NOTE_SIGNAL = libc::NOTE_SIGNAL, const NOTE_TRACK = libc::NOTE_TRACK, const NOTE_TRACKERR = libc::NOTE_TRACKERR, #[cfg(any(target_os = "macos", + target_os = "ios", target_os = "freebsd", target_os = "dragonfly"))] const NOTE_TRIGGER = libc::NOTE_TRIGGER, #[cfg(target_os = "openbsd")] const NOTE_TRUNCATE = libc::NOTE_TRUNCATE, - #[cfg(any(target_os = "macos", target_os = "freebsd"))] + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] const NOTE_USECONDS = libc::NOTE_USECONDS, - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "macos", target_os = "ios"))] const NOTE_VM_ERROR = libc::NOTE_VM_ERROR, - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "macos", target_os = "ios"))] const NOTE_VM_PRESSURE = libc::NOTE_VM_PRESSURE, - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "macos", target_os = "ios"))] const NOTE_VM_PRESSURE_SUDDEN_TERMINATE = libc::NOTE_VM_PRESSURE_SUDDEN_TERMINATE, - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "macos", target_os = "ios"))] const NOTE_VM_PRESSURE_TERMINATE = libc::NOTE_VM_PRESSURE_TERMINATE, const NOTE_WRITE = libc::NOTE_WRITE, } @@ -251,6 +261,7 @@ pub fn kevent(kq: RawFd, } #[cfg(any(target_os = "macos", + target_os = "ios", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))]