diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6a2d3c30..88b6bf1b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -57,9 +57,8 @@ jobs: strategy: matrix: # TODO: add the following targets, currently broken. - # "x86_64-fuchsia" # "x86_64-unknown-redox" - target: ["aarch64-apple-ios", "aarch64-linux-android", "x86_64-apple-darwin", "x86_64-pc-windows-msvc", "x86_64-sun-solaris", "x86_64-unknown-freebsd", "x86_64-unknown-illumos", "x86_64-unknown-linux-gnu", "x86_64-unknown-netbsd"] + target: ["aarch64-apple-ios", "aarch64-linux-android", "x86_64-apple-darwin", "x86_64-fuchsia", "x86_64-pc-windows-msvc", "x86_64-sun-solaris", "x86_64-unknown-freebsd", "x86_64-unknown-illumos", "x86_64-unknown-linux-gnu", "x86_64-unknown-netbsd"] steps: - uses: actions/checkout@master - name: Install Rust diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 7a185a5d..cac33d0b 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -7,11 +7,6 @@ // except according to those terms. use std::cmp::min; -#[cfg(all( - feature = "all", - any(target_os = "android", target_os = "fuchsia", target_os = "linux") -))] -use std::ffi::{CStr, CString}; #[cfg(not(target_os = "redox"))] use std::io::IoSlice; use std::marker::PhantomData; @@ -942,11 +937,19 @@ impl crate::Socket { feature = "all", any(target_os = "android", target_os = "fuchsia", target_os = "linux") ))] - pub fn device(&self) -> io::Result> { + pub fn device(&self) -> io::Result>> { + use std::convert::TryInto as _; + + // TODO(https://github.com/rust-lang/libc/pull/2010): Remove this. + #[cfg(target_os = "fuchsia")] + const IFNAMSIZ: libc::size_t = 16; + + #[cfg(not(target_os = "fuchsia"))] + const IFNAMSIZ: libc::size_t = libc::IFNAMSIZ; + // TODO: replace with `MaybeUninit::uninit_array` once stable. - let mut buf: [MaybeUninit; libc::IFNAMSIZ] = - unsafe { MaybeUninit::<[MaybeUninit; libc::IFNAMSIZ]>::uninit().assume_init() }; - let mut len = buf.len() as libc::socklen_t; + let mut buf: MaybeUninit<[u8; IFNAMSIZ]> = MaybeUninit::uninit(); + let mut len = IFNAMSIZ.try_into().unwrap(); unsafe { syscall!(getsockopt( self.inner, @@ -959,21 +962,13 @@ impl crate::Socket { if len == 0 { Ok(None) } else { - // Allocate a buffer for `CString` with the length including the - // null terminator. - let len = len as usize; - let mut name = Vec::with_capacity(len); - // TODO: use `MaybeUninit::slice_assume_init_ref` once stable. // Safety: `len` bytes are writen by the OS, this includes a null // terminator. However we don't copy the null terminator because // `CString::from_vec_unchecked` adds its own null terminator. - let buf = unsafe { slice::from_raw_parts(buf.as_ptr().cast(), len - 1) }; - name.extend_from_slice(buf); - - // Safety: the OS initialised the string for us, which shouldn't - // include any null bytes. - Ok(Some(unsafe { CString::from_vec_unchecked(name) })) + Ok(Some( + unsafe { buf.assume_init() }[..len.try_into().unwrap()].into(), + )) } } @@ -990,9 +985,9 @@ impl crate::Socket { feature = "all", any(target_os = "android", target_os = "fuchsia", target_os = "linux") ))] - pub fn bind_device(&self, interface: Option<&CStr>) -> io::Result<()> { + pub fn bind_device(&self, interface: Option<&[u8]>) -> io::Result<()> { let (value, len) = if let Some(interface) = interface { - (interface.as_ptr(), interface.to_bytes_with_nul().len()) + (interface.as_ptr(), interface.len()) } else { (ptr::null(), 0) }; @@ -1058,9 +1053,15 @@ impl crate::Socket { any(target_os = "android", target_os = "fuchsia", target_os = "linux") ))] pub fn freebind(&self) -> io::Result { + // TODO(https://github.com/rust-lang/libc/pull/2011): Remove this. + #[cfg(target_os = "fuchsia")] + const IP_FREEBIND: c_int = 15; + + #[cfg(not(target_os = "fuchsia"))] + const IP_FREEBIND: c_int = libc::IP_FREEBIND; + unsafe { - getsockopt::(self.inner, libc::SOL_SOCKET, libc::IP_FREEBIND) - .map(|reuse| reuse != 0) + getsockopt::(self.inner, libc::SOL_SOCKET, IP_FREEBIND).map(|reuse| reuse != 0) } } @@ -1078,14 +1079,14 @@ impl crate::Socket { any(target_os = "android", target_os = "fuchsia", target_os = "linux") ))] pub fn set_freebind(&self, reuse: bool) -> io::Result<()> { - unsafe { - setsockopt( - self.inner, - libc::SOL_SOCKET, - libc::IP_FREEBIND, - reuse as c_int, - ) - } + // TODO(https://github.com/rust-lang/libc/pull/2011): Remove this. + #[cfg(target_os = "fuchsia")] + const IP_FREEBIND: c_int = 15; + + #[cfg(not(target_os = "fuchsia"))] + const IP_FREEBIND: c_int = libc::IP_FREEBIND; + + unsafe { setsockopt(self.inner, libc::SOL_SOCKET, IP_FREEBIND, reuse as c_int) } } } diff --git a/tests/socket.rs b/tests/socket.rs index 7dad160b..d8f33967 100644 --- a/tests/socket.rs +++ b/tests/socket.rs @@ -1,5 +1,3 @@ -#[cfg(all(feature = "all", any(target_os = "fuchsia", target_os = "linux")))] -use std::ffi::CStr; #[cfg(any(windows, target_vendor = "apple"))] use std::io; #[cfg(not(target_os = "redox"))] @@ -633,13 +631,13 @@ fn tcp_keepalive() { #[test] fn device() { // Some common network interface on Linux. - const INTERFACES: &[&str] = &["lo\0", "lo0\0", "eth0\0", "wlan0\0"]; + const INTERFACES: &[&str] = &["lo", "lo0", "eth0", "wlan0"]; let socket = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap(); assert_eq!(socket.device().unwrap(), None); for interface in INTERFACES.iter() { - let interface = CStr::from_bytes_with_nul(interface.as_bytes()).unwrap(); + let interface = interface.as_bytes(); if let Err(err) = socket.bind_device(Some(interface)) { // Network interface is not available try another. if matches!(err.raw_os_error(), Some(libc::ENODEV) | Some(libc::EPERM)) {