From 307404ee1ca2aed5e9e95edad28d4da1ad4e9b66 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Mon, 12 Oct 2020 11:17:26 -0700 Subject: [PATCH 1/8] Update to cfg-if 1.0 --- Cargo.toml | 2 +- test/test_unistd.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 31c3d71c19..d3b94664a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ exclude = [ [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/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); From b3c859c2c1e0155bbfc4dc766c05010fa92998e9 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 9 Nov 2020 16:51:00 -0500 Subject: [PATCH 2/8] Suppress af_alg_iv "deprecation" See https://github.com/rust-lang/libc/issues/1501 in which this type's trait implementations are being removed; the change is being announced via this deprecation. --- src/sys/socket/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 5e5fb8d370..3bb9607428 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) => { From 7738a48b25e14bee43ef5c177acd49fda0ee5324 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 10 Nov 2020 17:17:19 -0500 Subject: [PATCH 3/8] Suppress time_t musl "deprecation" See https://github.com/rust-lang/libc/issues/1848 in which this type is changing from i32 to i64; the change is being announced via this deprecation. --- src/sys/time.rs | 9 +++++++++ 1 file changed, 9 insertions(+) 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 } From 7a088cc2624551caf9e815f9319f4554f299b4fe Mon Sep 17 00:00:00 2001 From: myfreeweb Date: Tue, 17 Nov 2020 23:33:38 +0300 Subject: [PATCH 4/8] Add docs.rs target list ref: https://blog.rust-lang.org/2020/03/15/docs-rs-opt-into-fewer-targets.html --- Cargo.toml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index d3b94664a5..b3904dd1d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,19 @@ 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" From ed1fa9bf282b2bf03e2c23315a2bef1e9be8412b Mon Sep 17 00:00:00 2001 From: Toby DiPasquale Date: Wed, 25 Nov 2020 02:47:27 -0500 Subject: [PATCH 5/8] Fix recvmmsg(2) implementation There were two problems discovered with the `recvmmsg(2)` implementation that this changeset attempts to fix: 1. As mentioned in nix-rust/issues/1325, `recvmmsg(2)` can return fewer messages than requested, and 2. Passing the return value of `recvmmsg(2)` as the number of bytes in the messages received is incorrect. This changeset incorporates the proposed fix from nix-rust/issues/1325, as well as passing the correct value (`mmsghdr.msg_len`) for the number of bytes in a given message. --- src/sys/socket/mod.rs | 5 +-- test/sys/test_socket.rs | 70 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 3bb9607428..a4f599c130 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -1217,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/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 From 95aa8d2cfd5d09795ca4fc7cd38b8f0ef27e0cf8 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 28 Nov 2020 17:49:13 -0700 Subject: [PATCH 6/8] [skip ci] update CHANGELOG for PR #1341 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e018ab20df..322edde243 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Added ### Changed ### Fixed + +- Fixed bugs in `recvmmsg`. + (#[1341](https://github.com/nix-rust/nix/pull/1341)) + ### Removed ## [0.19.0] - 6 October 2020 From 7ed5d0c43d6479979740b3e425a7b92539df60fb Mon Sep 17 00:00:00 2001 From: Laurence Tratt Date: Sun, 18 Oct 2020 21:58:41 +0100 Subject: [PATCH 7/8] KEEPCNT/KEEPINTVL aren't available on OpenBSD. Without this commit, nix doesn't currently compile on OpenBSD. Some keepalive settings can be set globally, but not per-socket (see e.g. https://bugzilla.mozilla.org/show_bug.cgi?id=970550 for some digging into this). Since it seems that NetBSD and DragonflyBSD have these settings, it makes more sense to only exclude them on OpenBSD rather than include them on (pretty much every) other operating systems. --- src/sys/socket/sockopt.rs | 2 ++ 1 file changed, 2 insertions(+) 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); From 453d22ffb07bdb6c33b513498230045ddd85de22 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 28 Nov 2020 18:04:25 -0700 Subject: [PATCH 8/8] Release v0.19.1 --- CHANGELOG.md | 6 ++++-- Cargo.toml | 2 +- README.md | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 322edde243..77f38c3d51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,12 +7,14 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Added ### Changed ### Fixed +### Removed + +## [0.19.1] - 28 November 2020 +### Fixed - Fixed bugs in `recvmmsg`. (#[1341](https://github.com/nix-rust/nix/pull/1341)) -### Removed - ## [0.19.0] - 6 October 2020 ### Added - Added Netlink protocol families to the `SockProtocol` enum diff --git a/Cargo.toml b/Cargo.toml index b3904dd1d8..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" 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