From 452f5608e7736a6eef3b80f4a91fd29ba3398d16 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Thu, 24 Dec 2020 18:05:43 -0500 Subject: [PATCH] Add Fuchsia support and CI In general, feature support is identical to Linux. --- .github/workflows/main.yml | 2 +- src/lib.rs | 2 + src/socket.rs | 6 +++ src/sys/unix.rs | 92 ++++++++++++++++++++------------------ tests/socket.rs | 16 ++++--- 5 files changed, 68 insertions(+), 50 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c7cb4a32..42888f3d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -49,7 +49,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - target: [x86_64-unknown-redox] + target: [x86_64-unknown-redox, x86_64-fuchsia] steps: - uses: actions/checkout@master - name: Install Rust diff --git a/src/lib.rs b/src/lib.rs index 3b25b2f7..0b79d7b1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -369,6 +369,7 @@ impl TcpKeepalive { feature = "all", any( target_os = "freebsd", + target_os = "fuchsia", target_os = "linux", target_os = "netbsd", target_vendor = "apple", @@ -390,6 +391,7 @@ impl TcpKeepalive { feature = "all", any( target_os = "freebsd", + target_os = "fuchsia", target_os = "linux", target_os = "netbsd", target_vendor = "apple", diff --git a/src/socket.rs b/src/socket.rs index 4e6c4eeb..25a65241 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -189,6 +189,7 @@ impl Socket { target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "fuchsia", target_os = "illumos", target_os = "linux", target_os = "netbsd", @@ -201,6 +202,7 @@ impl Socket { target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "fuchsia", target_os = "illumos", target_os = "linux", target_os = "netbsd", @@ -571,6 +573,7 @@ fn set_common_type(ty: Type) -> Type { target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "fuchsia", target_os = "illumos", target_os = "linux", target_os = "netbsd", @@ -595,6 +598,7 @@ fn set_common_flags(socket: Socket) -> io::Result { target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "fuchsia", target_os = "illumos", target_os = "linux", target_os = "netbsd", @@ -1208,6 +1212,7 @@ impl Socket { target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "fuchsia", target_os = "illumos", target_os = "linux", target_os = "netbsd", @@ -1232,6 +1237,7 @@ impl Socket { target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "fuchsia", target_os = "illumos", target_os = "linux", target_os = "netbsd", diff --git a/src/sys/unix.rs b/src/sys/unix.rs index e7888127..9366205f 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -7,7 +7,7 @@ // except according to those terms. use std::cmp::min; -#[cfg(all(feature = "all", target_os = "linux"))] +#[cfg(all(feature = "all", any(target_os = "fuchsia", target_os = "linux")))] use std::ffi::{CStr, CString}; #[cfg(not(target_os = "redox"))] use std::io::IoSlice; @@ -90,6 +90,7 @@ pub(crate) use libc::{ feature = "all", any( target_os = "freebsd", + target_os = "fuchsia", target_os = "linux", target_os = "netbsd", target_vendor = "apple", @@ -142,6 +143,7 @@ type IovLen = usize; all(target_os = "linux", target_env = "musl"), target_os = "dragonfly", target_os = "freebsd", + target_os = "fuchsia", target_os = "illumos", target_os = "netbsd", target_os = "openbsd", @@ -159,8 +161,8 @@ impl Domain { /// /// # Notes /// - /// This function is only available on Linux. - #[cfg(all(feature = "all", target_os = "linux"))] + /// This function is only available on Fuchsia and Linux. + #[cfg(all(feature = "all", any(target_os = "fuchsia", target_os = "linux")))] pub const PACKET: Domain = Domain(libc::AF_PACKET); } @@ -169,7 +171,7 @@ impl_debug!( libc::AF_INET, libc::AF_INET6, libc::AF_UNIX, - #[cfg(target_os = "linux")] + #[cfg(any(target_os = "fuchsia", target_os = "linux"))] libc::AF_PACKET, libc::AF_UNSPEC, // = 0. ); @@ -180,14 +182,15 @@ impl Type { /// /// # Notes /// - /// This function is only available on Android, DragonFlyBSD, FreeBSD, - /// Linux, NetBSD and OpenBSD. + /// This function is only available on Android, DragonFlyBSD, Fuchsia, + /// FreeBSD, Linux, NetBSD and OpenBSD. #[cfg(all( feature = "all", any( target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "fuchsia", target_os = "illumos", target_os = "linux", target_os = "netbsd", @@ -202,14 +205,15 @@ impl Type { /// /// # Notes /// - /// This function is only available on Android, DragonFlyBSD, FreeBSD, - /// Linux, NetBSD and OpenBSD. + /// This function is only available on Android, DragonFlyBSD, Fuchsia, + /// FreeBSD, Linux, NetBSD and OpenBSD. #[cfg(all( feature = "all", any( target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "fuchsia", target_os = "illumos", target_os = "linux", target_os = "netbsd", @@ -224,6 +228,7 @@ impl Type { target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "fuchsia", target_os = "illumos", target_os = "linux", target_os = "netbsd", @@ -248,6 +253,7 @@ impl_debug!( target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "fuchsia", target_os = "linux", target_os = "netbsd", target_os = "openbsd" @@ -257,6 +263,7 @@ impl_debug!( target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "fuchsia", target_os = "linux", target_os = "netbsd", target_os = "openbsd" @@ -519,15 +526,12 @@ fn recvmsg( } else { size_of::() as libc::socklen_t }; - let mut msg = libc::msghdr { - msg_name: msg_name.cast(), - msg_namelen, - msg_iov: bufs.as_mut_ptr().cast(), - msg_iovlen: min(bufs.len(), IovLen::MAX as usize) as IovLen, - msg_control: ptr::null_mut(), - msg_controllen: 0, - msg_flags: 0, - }; + // libc::msghdr contains unexported padding fields on Fuchsia. + let mut msg: libc::msghdr = unsafe { mem::zeroed() }; + msg.msg_name = msg_name.cast(); + msg.msg_namelen = msg_namelen; + msg.msg_iov = bufs.as_mut_ptr().cast(); + msg.msg_iovlen = min(bufs.len(), IovLen::MAX as usize) as IovLen; syscall!(recvmsg(fd, &mut msg, flags)) .map(|n| (n as usize, msg.msg_namelen, RecvFlags(msg.msg_flags))) } @@ -578,19 +582,16 @@ fn sendmsg( bufs: &[IoSlice<'_>], flags: c_int, ) -> io::Result { - let mut msg = libc::msghdr { - // Safety: we're creating a `*mut` pointer from a reference, which is UB - // once actually used. However the OS should not write to it in the - // `sendmsg` system call. - msg_name: (msg_name as *mut sockaddr_storage).cast(), - msg_namelen, - // Safety: Same as above about `*const` -> `*mut`. - msg_iov: bufs.as_ptr() as *mut _, - msg_iovlen: min(bufs.len(), IovLen::MAX as usize) as IovLen, - msg_control: ptr::null_mut(), - msg_controllen: 0, - msg_flags: 0, - }; + // libc::msghdr contains unexported padding fields on Fuchsia. + let mut msg: libc::msghdr = unsafe { mem::zeroed() }; + // Safety: we're creating a `*mut` pointer from a reference, which is UB + // once actually used. However the OS should not write to it in the + // `sendmsg` system call. + msg.msg_name = (msg_name as *mut sockaddr_storage).cast(); + msg.msg_namelen = msg_namelen; + // Safety: Same as above about `*const` -> `*mut`. + msg.msg_iov = bufs.as_ptr() as *mut _; + msg.msg_iovlen = min(bufs.len(), IovLen::MAX as usize) as IovLen; syscall!(sendmsg(fd, &mut msg, flags)).map(|n| n as usize) } @@ -651,6 +652,7 @@ pub(crate) fn set_tcp_keepalive(fd: Socket, keepalive: &TcpKeepalive) -> io::Res target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "fuchsia", target_os = "illumos", target_os = "linux", target_os = "netbsd", @@ -778,6 +780,7 @@ impl crate::Socket { target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "fuchsia", target_os = "illumos", target_os = "linux", target_os = "netbsd", @@ -792,6 +795,7 @@ impl crate::Socket { target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "fuchsia", target_os = "illumos", target_os = "linux", target_os = "netbsd", @@ -881,9 +885,9 @@ impl crate::Socket { /// This value gets the socket mark field for each packet sent through /// this socket. /// - /// This function is only available on Linux and requires the - /// `CAP_NET_ADMIN` capability. - #[cfg(all(feature = "all", target_os = "linux"))] + /// This function is only available on Fuchsia and Linux. On Linux it + /// requires the `CAP_NET_ADMIN` capability. + #[cfg(all(feature = "all", any(target_os = "fuchsia", target_os = "linux")))] pub fn mark(&self) -> io::Result { unsafe { getsockopt::(self.inner, libc::SOL_SOCKET, libc::SO_MARK).map(|mark| mark as u32) @@ -896,9 +900,9 @@ impl crate::Socket { /// this socket. Changing the mark can be used for mark-based routing /// without netfilter or for packet filtering. /// - /// This function is only available on Linux and requires the - /// `CAP_NET_ADMIN` capability. - #[cfg(all(feature = "all", target_os = "linux"))] + /// This function is only available on Fuchsia and Linux. On Linux it + /// requires the `CAP_NET_ADMIN` capability. + #[cfg(all(feature = "all", any(target_os = "fuchsia", target_os = "linux")))] pub fn set_mark(&self, mark: u32) -> io::Result<()> { unsafe { setsockopt::(self.inner, libc::SOL_SOCKET, libc::SO_MARK, mark as c_int) } } @@ -907,8 +911,8 @@ impl crate::Socket { /// /// This value gets the socket binded device's interface name. /// - /// This function is only available on Linux. - #[cfg(all(feature = "all", target_os = "linux"))] + /// This function is only available on Fuchsia and Linux. + #[cfg(all(feature = "all", any(target_os = "fuchsia", target_os = "linux")))] pub fn device(&self) -> io::Result> { // TODO: replace with `MaybeUninit::uninit_array` once stable. let mut buf: [MaybeUninit; libc::IFNAMSIZ] = @@ -952,8 +956,8 @@ impl crate::Socket { /// /// If `interface` is `None` or an empty string it removes the binding. /// - /// This function is only available on Linux. - #[cfg(all(feature = "all", target_os = "linux"))] + /// This function is only available on Fuchsia and Linux. + #[cfg(all(feature = "all", any(target_os = "fuchsia", target_os = "linux")))] pub fn bind_device(&self, interface: Option<&CStr>) -> io::Result<()> { let (value, len) = if let Some(interface) = interface { (interface.as_ptr(), interface.to_bytes_with_nul().len()) @@ -1014,10 +1018,10 @@ impl crate::Socket { /// /// For more information about this option, see [`set_freebind`]. /// - /// This function is only available on Linux. + /// This function is only available on Fuchsia and Linux. /// /// [`set_freebind`]: Socket::set_freebind - #[cfg(all(feature = "all", target_os = "linux"))] + #[cfg(all(feature = "all", any(target_os = "fuchsia", target_os = "linux")))] pub fn freebind(&self) -> io::Result { unsafe { getsockopt::(self.inner, libc::SOL_SOCKET, libc::IP_FREEBIND) @@ -1033,8 +1037,8 @@ impl crate::Socket { /// dynamic IP address to be up at the time that the application is trying /// to bind to it. /// - /// This function is only available on Linux. - #[cfg(all(feature = "all", target_os = "linux"))] + /// This function is only available on Fuchsia and Linux. + #[cfg(all(feature = "all", any(target_os = "fuchsia", target_os = "linux")))] pub fn set_freebind(&self, reuse: bool) -> io::Result<()> { unsafe { setsockopt( diff --git a/tests/socket.rs b/tests/socket.rs index e0987d1d..049cbac4 100644 --- a/tests/socket.rs +++ b/tests/socket.rs @@ -1,4 +1,4 @@ -#[cfg(all(feature = "all", target_os = "linux"))] +#[cfg(all(feature = "all", any(target_os = "fuchsia", target_os = "linux")))] use std::ffi::CStr; #[cfg(any(windows, target_vendor = "apple"))] use std::io; @@ -50,7 +50,7 @@ fn domain_fmt_debug() { (Domain::IPV6, "AF_INET6"), #[cfg(unix)] (Domain::UNIX, "AF_UNIX"), - #[cfg(all(feature = "all", target_os = "linux"))] + #[cfg(all(feature = "all", any(target_os = "fuchsia", target_os = "linux")))] (Domain::PACKET, "AF_PACKET"), (0.into(), "AF_UNSPEC"), (500.into(), "500"), @@ -154,6 +154,7 @@ fn no_default_flags() { target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "fuchsia", target_os = "linux", target_os = "netbsd", target_os = "openbsd" @@ -202,6 +203,7 @@ fn set_cloexec() { target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "fuchsia", target_os = "linux", target_os = "netbsd", target_os = "openbsd" @@ -560,6 +562,7 @@ fn tcp_keepalive() { feature = "all", any( target_os = "freebsd", + target_os = "fuchsia", target_os = "linux", target_os = "netbsd", target_vendor = "apple", @@ -572,6 +575,7 @@ fn tcp_keepalive() { feature = "all", any( target_os = "freebsd", + target_os = "fuchsia", target_os = "linux", target_os = "netbsd", target_vendor = "apple", @@ -591,6 +595,7 @@ fn tcp_keepalive() { target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "fuchsia", target_os = "illumos", target_os = "linux", target_os = "netbsd", @@ -608,6 +613,7 @@ fn tcp_keepalive() { target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "fuchsia", target_os = "illumos", target_os = "linux", target_os = "netbsd", @@ -617,7 +623,7 @@ fn tcp_keepalive() { assert_eq!(socket.keepalive_retries().unwrap(), 10); } -#[cfg(all(feature = "all", target_os = "linux"))] +#[cfg(all(feature = "all", any(target_os = "fuchsia", target_os = "linux")))] #[test] fn device() { // Some common network interface on Linux. @@ -732,7 +738,7 @@ test!( mss, set_mss(256) ); -#[cfg(all(feature = "all", target_os = "linux"))] +#[cfg(all(feature = "all", any(target_os = "fuchsia", target_os = "linux")))] test!( #[ignore = "setting `SO_MARK` requires the `CAP_NET_ADMIN` capability (works when running as root)"] mark, @@ -744,7 +750,7 @@ test!( set_read_timeout(Some(Duration::from_secs(10))) ); test!(keepalive, set_keepalive(true)); -#[cfg(all(feature = "all", target_os = "linux"))] +#[cfg(all(feature = "all", any(target_os = "fuchsia", target_os = "linux")))] test!(freebind, set_freebind(true)); test!(IPv4 ttl, set_ttl(40));