diff --git a/CHANGELOG.md b/CHANGELOG.md index e018ab20df..77f38c3d51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed ### Removed +## [0.19.1] - 28 November 2020 +### Fixed + +- Fixed bugs in `recvmmsg`. + (#[1341](https://github.com/nix-rust/nix/pull/1341)) + ## [0.19.0] - 6 October 2020 ### Added - Added Netlink protocol families to the `SockProtocol` enum diff --git a/Cargo.toml b/Cargo.toml index 31c3d71c19..da9050b36b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "nix" description = "Rust friendly bindings to *nix APIs" edition = "2018" -version = "0.19.0" +version = "0.19.1" authors = ["The nix-rust Project Developers"] repository = "https://github.com/nix-rust/nix" license = "MIT" @@ -16,10 +16,23 @@ exclude = [ "/bors.toml" ] +[package.metadata.docs.rs] +targets = [ + "x86_64-unknown-linux-gnu", + "aarch64-linux-android", + "x86_64-apple-darwin", + "aarch64-apple-ios", + "x86_64-unknown-freebsd", + "x86_64-unknown-openbsd", + "x86_64-unknown-netbsd", + "x86_64-unknown-dragonfly", + "x86_64-unknown-redox" +] + [dependencies] libc = { version = "0.2.78", features = [ "extra_traits" ] } bitflags = "1.1" -cfg-if = "0.1.10" +cfg-if = "1.0" [target.'cfg(target_os = "dragonfly")'.build-dependencies] cc = "1" diff --git a/README.md b/README.md index bd015d1d81..8059a5c5a0 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ To use `nix`, add this to your `Cargo.toml`: ```toml [dependencies] -nix = "0.19.0" +nix = "0.19.1" ``` ## Contributing diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 5e5fb8d370..a4f599c130 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -847,12 +847,13 @@ impl<'a> ControlMessage<'a> { } #[cfg(any(target_os = "android", target_os = "linux"))] ControlMessage::AlgSetIv(iv) => { + #[allow(deprecated)] // https://github.com/rust-lang/libc/issues/1501 let af_alg_iv = libc::af_alg_iv { ivlen: iv.len() as u32, iv: [0u8; 0], }; - let size = mem::size_of::(); + let size = mem::size_of_val(&af_alg_iv); unsafe { ptr::copy_nonoverlapping( @@ -915,7 +916,7 @@ impl<'a> ControlMessage<'a> { } #[cfg(any(target_os = "android", target_os = "linux"))] ControlMessage::AlgSetIv(iv) => { - mem::size_of::() + iv.len() + mem::size_of_val(&iv) + iv.len() }, #[cfg(any(target_os = "android", target_os = "linux"))] ControlMessage::AlgSetOp(op) => { @@ -1216,17 +1217,18 @@ pub fn recvmmsg<'a, I>( let ret = unsafe { libc::recvmmsg(fd, output.as_mut_ptr(), output.len() as _, flags.bits() as _, timeout) }; - let r = Errno::result(ret)?; + let _ = Errno::result(ret)?; Ok(output .into_iter() + .take(ret as usize) .zip(addresses.iter().map(|addr| unsafe{addr.assume_init()})) .zip(results.into_iter()) .map(|((mmsghdr, address), (msg_controllen, cmsg_buffer))| { unsafe { read_mhdr( mmsghdr.msg_hdr, - r as isize, + mmsghdr.msg_len as isize, msg_controllen, address, cmsg_buffer diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index e41a472a27..5b7b4feafb 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -252,7 +252,9 @@ sockopt_impl!(Both, TcpKeepAlive, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE, u32); target_os = "linux", target_os = "nacl"))] sockopt_impl!(Both, TcpKeepIdle, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, u32); +#[cfg(not(target_os = "openbsd"))] sockopt_impl!(Both, TcpKeepCount, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, u32); +#[cfg(not(target_os = "openbsd"))] sockopt_impl!(Both, TcpKeepInterval, libc::IPPROTO_TCP, libc::TCP_KEEPINTVL, u32); sockopt_impl!(Both, RcvBuf, libc::SOL_SOCKET, libc::SO_RCVBUF, usize); sockopt_impl!(Both, SndBuf, libc::SOL_SOCKET, libc::SO_SNDBUF, usize); diff --git a/src/sys/time.rs b/src/sys/time.rs index 269b425316..bdcfe3c9b6 100644 --- a/src/sys/time.rs +++ b/src/sys/time.rs @@ -2,6 +2,7 @@ use std::{cmp, fmt, ops}; use std::time::Duration; use std::convert::From; use libc::{c_long, timespec, timeval}; +#[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 pub use libc::{time_t, suseconds_t}; pub trait TimeValLike: Sized { @@ -69,6 +70,7 @@ impl From for TimeSpec { impl From for TimeSpec { fn from(duration: Duration) -> Self { + #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 TimeSpec(timespec { tv_sec: duration.as_secs() as time_t, tv_nsec: duration.subsec_nanos() as c_long @@ -117,6 +119,7 @@ impl TimeValLike for TimeSpec { fn seconds(seconds: i64) -> TimeSpec { assert!(seconds >= TS_MIN_SECONDS && seconds <= TS_MAX_SECONDS, "TimeSpec out of bounds; seconds={}", seconds); + #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 TimeSpec(timespec {tv_sec: seconds as time_t, tv_nsec: 0 }) } @@ -143,6 +146,7 @@ impl TimeValLike for TimeSpec { let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC); assert!(secs >= TS_MIN_SECONDS && secs <= TS_MAX_SECONDS, "TimeSpec out of bounds"); + #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 TimeSpec(timespec {tv_sec: secs as time_t, tv_nsec: nanos as c_long }) } @@ -179,6 +183,7 @@ impl TimeSpec { } } + #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 pub fn tv_sec(&self) -> time_t { self.0.tv_sec } @@ -315,6 +320,7 @@ impl TimeValLike for TimeVal { fn seconds(seconds: i64) -> TimeVal { assert!(seconds >= TV_MIN_SECONDS && seconds <= TV_MAX_SECONDS, "TimeVal out of bounds; seconds={}", seconds); + #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 TimeVal(timeval {tv_sec: seconds as time_t, tv_usec: 0 }) } @@ -332,6 +338,7 @@ impl TimeValLike for TimeVal { let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); assert!(secs >= TV_MIN_SECONDS && secs <= TV_MAX_SECONDS, "TimeVal out of bounds"); + #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 TimeVal(timeval {tv_sec: secs as time_t, tv_usec: micros as suseconds_t }) } @@ -344,6 +351,7 @@ impl TimeValLike for TimeVal { let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); assert!(secs >= TV_MIN_SECONDS && secs <= TV_MAX_SECONDS, "TimeVal out of bounds"); + #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 TimeVal(timeval {tv_sec: secs as time_t, tv_usec: micros as suseconds_t }) } @@ -380,6 +388,7 @@ impl TimeVal { } } + #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 pub fn tv_sec(&self) -> time_t { self.0.tv_sec } diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs index 1003598efb..c5abb7badd 100644 --- a/test/sys/test_socket.rs +++ b/test/sys/test_socket.rs @@ -437,6 +437,76 @@ mod recvfrom { send_thread.join().unwrap(); } + + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "netbsd", + ))] + #[test] + pub fn udp_recvmmsg_dontwait_short_read() { + use nix::sys::uio::IoVec; + use nix::sys::socket::{MsgFlags, recvmmsg}; + + 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 rsock = socket(AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None + ).unwrap(); + bind(rsock, &sock_addr).unwrap(); + let ssock = socket( + AddressFamily::Inet, + SockType::Datagram, + SockFlag::empty(), + None, + ).expect("send socket failed"); + + let send_thread = thread::spawn(move || { + for _ in 0..NUM_MESSAGES_SENT { + sendto(ssock, &DATA[..], &sock_addr, MsgFlags::empty()).unwrap(); + } + }); + // Ensure we've sent all the messages before continuing so `recvmmsg` + // will return right away + send_thread.join().unwrap(); + + let mut msgs = std::collections::LinkedList::new(); + + // Buffers to receive >`NUM_MESSAGES_SENT` messages to ensure `recvmmsg` + // will return when there are fewer than requested messages in the + // kernel buffers when using `MSG_DONTWAIT`. + let mut receive_buffers = [[0u8; 32]; NUM_MESSAGES_SENT + 2]; + let iovs: Vec<_> = receive_buffers.iter_mut().map(|buf| { + [IoVec::from_mut_slice(&mut buf[..])] + }).collect(); + + for iov in &iovs { + msgs.push_back(RecvMmsgData { + iov: iov, + cmsg_buffer: None, + }) + }; + + let res = 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!(DATA.len(), bytes); + } + + for buf in &receive_buffers[..NUM_MESSAGES_SENT] { + assert_eq!(&buf[..DATA.len()], DATA); + } + } } // Test error handling of our recvmsg wrapper diff --git a/test/test_unistd.rs b/test/test_unistd.rs index c7a75fbe63..a4b8a91668 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -377,7 +377,7 @@ cfg_if!{ "./sh", AtFlags::empty()); execve_test_factory!(test_execveat_absolute, execveat, File::open("/").unwrap().into_raw_fd(), "/system/bin/sh", AtFlags::empty()); - } else if #[cfg(all(target_os = "linux"), any(target_arch ="x86_64", target_arch ="x86"))] { + } else if #[cfg(all(target_os = "linux", any(target_arch ="x86_64", target_arch ="x86")))] { use nix::fcntl::AtFlags; execve_test_factory!(test_execveat_empty, execveat, File::open("/bin/sh").unwrap().into_raw_fd(), "", AtFlags::AT_EMPTY_PATH);