Skip to content

Commit

Permalink
Merge #1564
Browse files Browse the repository at this point in the history
1564: Add support for the SO_TXTIME sockopt and SCM_TXTIME control message r=asomers a=ghedo



Co-authored-by: Alessandro Ghedini <[email protected]>
  • Loading branch information
bors[bot] and ghedo authored Dec 30, 2021
2 parents c77a872 + a982985 commit b9eb197
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ This project adheres to [Semantic Versioning](https://semver.org/).
(#[1547](https://github.com/nix-rust/nix/pull/1547))
- Added getter methods to `MqAttr` struct
(#[1619](https://github.com/nix-rust/nix/pull/1619))
- Added the `TxTime` sockopt and control message.
(#[1564](https://github.com/nix-rust/nix/pull/1564))

### Changed
### Fixed
Expand Down
22 changes: 22 additions & 0 deletions src/sys/socket/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1056,6 +1056,14 @@ pub enum ControlMessage<'a> {
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
RxqOvfl(&'a u32),

/// Configure the transmission time of packets.
///
/// For further information, please refer to the
/// [`tc-etf(8)`](https://man7.org/linux/man-pages/man8/tc-etf.8.html) man
/// page.
#[cfg(target_os = "linux")]
TxTime(&'a u64),
}

// An opaque structure used to prevent cmsghdr from being a public type
Expand Down Expand Up @@ -1153,6 +1161,10 @@ impl<'a> ControlMessage<'a> {
ControlMessage::RxqOvfl(drop_count) => {
drop_count as *const _ as *const u8
},
#[cfg(target_os = "linux")]
ControlMessage::TxTime(tx_time) => {
tx_time as *const _ as *const u8
},
};
unsafe {
ptr::copy_nonoverlapping(
Expand Down Expand Up @@ -1208,6 +1220,10 @@ impl<'a> ControlMessage<'a> {
ControlMessage::RxqOvfl(drop_count) => {
mem::size_of_val(drop_count)
},
#[cfg(target_os = "linux")]
ControlMessage::TxTime(tx_time) => {
mem::size_of_val(tx_time)
},
}
}

Expand Down Expand Up @@ -1237,6 +1253,8 @@ impl<'a> ControlMessage<'a> {
ControlMessage::Ipv6PacketInfo(_) => libc::IPPROTO_IPV6,
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
ControlMessage::RxqOvfl(_) => libc::SOL_SOCKET,
#[cfg(target_os = "linux")]
ControlMessage::TxTime(_) => libc::SOL_SOCKET,
}
}

Expand Down Expand Up @@ -1279,6 +1297,10 @@ impl<'a> ControlMessage<'a> {
ControlMessage::RxqOvfl(_) => {
libc::SO_RXQ_OVFL
},
#[cfg(target_os = "linux")]
ControlMessage::TxTime(_) => {
libc::SCM_TXTIME
},
}
}

Expand Down
5 changes: 5 additions & 0 deletions src/sys/socket/sockopt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,11 @@ sockopt_impl!(
#[allow(missing_docs)]
// Not documented by Linux!
UdpGroSegment, Both, libc::IPPROTO_UDP, libc::UDP_GRO, bool);
#[cfg(target_os = "linux")]
sockopt_impl!(
/// Configures the behavior of time-based transmission of packets, for use
/// with the `TxTime` control message.
TxTime, Both, libc::SOL_SOCKET, libc::SO_TXTIME, libc::sock_txtime);
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
sockopt_impl!(
/// Indicates that an unsigned 32-bit value ancillary message (cmsg) should
Expand Down
57 changes: 57 additions & 0 deletions test/sys/test_socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1997,3 +1997,60 @@ mod linux_errqueue {
assert_eq!(ext_err.ee_info, 0);
}
}

// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack
// of QEMU support is suspected.
#[cfg_attr(qemu, ignore)]
#[cfg(target_os = "linux")]
#[test]
pub fn test_txtime() {
use nix::sys::socket::{
bind, recvmsg, sendmsg, setsockopt, socket, sockopt, ControlMessage,
MsgFlags, SockFlag, SockType,
};
use nix::sys::time::TimeValLike;
use nix::time::{ClockId, clock_gettime};

require_kernel_version!(test_txtime, ">= 5.8");

let std_sa = SocketAddr::from_str("127.0.0.1:6790").unwrap();
let inet_addr = InetAddr::from_std(&std_sa);
let sock_addr = SockAddr::new_inet(inet_addr);

let ssock = socket(
AddressFamily::Inet,
SockType::Datagram,
SockFlag::empty(),
None,
)
.expect("send socket failed");

let txtime_cfg = libc::sock_txtime {
clockid: libc::CLOCK_MONOTONIC,
flags: 0,
};
setsockopt(ssock, sockopt::TxTime, &txtime_cfg).unwrap();

let rsock = socket(
AddressFamily::Inet,
SockType::Datagram,
SockFlag::empty(),
None,
)
.unwrap();
bind(rsock, &sock_addr).unwrap();

let sbuf = [0u8; 2048];
let iov1 = [nix::sys::uio::IoVec::from_slice(&sbuf)];

let now = clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap();
let delay = std::time::Duration::from_secs(1).into();
let txtime = (now + delay).num_nanoseconds() as u64;

let cmsg = ControlMessage::TxTime(&txtime);
sendmsg(ssock, &iov1, &[cmsg], MsgFlags::empty(), Some(&sock_addr)).unwrap();

let mut rbuf = [0u8; 2048];
let iov2 = [nix::sys::uio::IoVec::from_mut_slice(&mut rbuf)];
recvmsg(rsock, &iov2, None, MsgFlags::empty()).unwrap();
}

0 comments on commit b9eb197

Please sign in to comment.