Skip to content

Commit 1f7b647

Browse files
committed
Adding packet receipt timestamp collection into RecvMeta for linux
1 parent 2ba600b commit 1f7b647

File tree

5 files changed

+48
-2
lines changed

5 files changed

+48
-2
lines changed

quinn-udp/src/cmsg/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,11 @@ impl<M: MsgHdr> Drop for Encoder<'_, M> {
8383
/// `cmsg` must refer to a native cmsg containing a payload of type `T`
8484
pub(crate) unsafe fn decode<T: Copy, C: CMsgHdr>(cmsg: &impl CMsgHdr) -> T {
8585
assert!(mem::align_of::<T>() <= mem::align_of::<C>());
86-
debug_assert_eq!(cmsg.len(), C::cmsg_len(mem::size_of::<T>()));
86+
debug_assert_eq!(
87+
cmsg.len(),
88+
C::cmsg_len(mem::size_of::<T>()),
89+
"cmsg truncated -- you might need to raise the CMSG_LEN constant for this platform"
90+
);
8791
ptr::read(cmsg.cmsg_data() as *const T)
8892
}
8993

quinn-udp/src/fallback.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ impl UdpSocketState {
7272
addr: addr.as_socket().unwrap(),
7373
ecn: None,
7474
dst_ip: None,
75+
#[cfg(not(wasm_browser))]
76+
timestamp: None,
7577
};
7678
Ok(1)
7779
}

quinn-udp/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,13 @@ pub struct RecvMeta {
115115
/// Populated on platforms: Windows, Linux, Android (API level > 25),
116116
/// FreeBSD, OpenBSD, NetBSD, macOS, and iOS.
117117
pub dst_ip: Option<IpAddr>,
118+
/// A timestamp for when the given packet was received by the operating system.
119+
/// Controlled by the `set_recv_timestamping` option on the source socket where available.
120+
///
121+
/// Populated on platforms with varying clock sources, as follows:
122+
/// - Linux: `CLOCK_REALTIME` (see `SO_TIMESTAMPNS` in `man 7 socket` for more information)
123+
#[cfg(not(wasm_browser))]
124+
pub timestamp: Option<Duration>,
118125
}
119126

120127
impl Default for RecvMeta {
@@ -126,6 +133,8 @@ impl Default for RecvMeta {
126133
stride: 0,
127134
ecn: None,
128135
dst_ip: None,
136+
#[cfg(not(wasm_browser))]
137+
timestamp: None,
129138
}
130139
}
131140
}

quinn-udp/src/unix.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ use std::{
1212
time::Instant,
1313
};
1414

15+
#[cfg(target_os = "linux")]
16+
use std::time::Duration;
17+
1518
use socket2::SockRef;
1619

1720
use super::{
@@ -96,6 +99,11 @@ impl UdpSocketState {
9699
unsafe { libc::CMSG_SPACE(mem::size_of::<libc::in6_pktinfo>() as _) as usize };
97100
}
98101

102+
if cfg!(target_os = "linux") {
103+
cmsg_platform_space +=
104+
unsafe { libc::CMSG_SPACE(mem::size_of::<libc::timeval>() as _) as usize };
105+
}
106+
99107
assert!(
100108
CMSG_LEN
101109
>= unsafe { libc::CMSG_SPACE(mem::size_of::<libc::c_int>() as _) as usize }
@@ -257,6 +265,18 @@ impl UdpSocketState {
257265
self.may_fragment
258266
}
259267

268+
/// Sets the socket to receive packet receipt timestamps from the operating system.
269+
/// These can be accessed via [`RecvMeta::timestamp`] on packets when enabled.
270+
#[cfg(target_os = "linux")]
271+
pub fn set_recv_timestamping(&self, sock: UdpSockRef<'_>, enabled: bool) -> io::Result<()> {
272+
let enabled = match enabled {
273+
true => OPTION_ON,
274+
false => OPTION_OFF,
275+
};
276+
277+
set_socket_option(&*sock.0, libc::SOL_SOCKET, libc::SO_TIMESTAMPNS, enabled)
278+
}
279+
260280
/// Returns true if we previously got an EINVAL error from `sendmsg` syscall.
261281
fn sendmsg_einval(&self) -> bool {
262282
self.sendmsg_einval.load(Ordering::Relaxed)
@@ -543,7 +563,7 @@ fn recv(io: SockRef<'_>, bufs: &mut [IoSliceMut<'_>], meta: &mut [RecvMeta]) ->
543563
Ok(1)
544564
}
545565

546-
const CMSG_LEN: usize = 88;
566+
const CMSG_LEN: usize = 96;
547567

548568
fn prepare_msg(
549569
transmit: &Transmit<'_>,
@@ -681,6 +701,8 @@ fn decode_recv(
681701
let mut dst_ip = None;
682702
#[allow(unused_mut)] // only mutable on Linux
683703
let mut stride = len;
704+
#[allow(unused_mut)] // only mutable on Linux
705+
let mut timestamp = None;
684706

685707
let cmsg_iter = unsafe { cmsg::Iter::new(hdr) };
686708
for cmsg in cmsg_iter {
@@ -725,6 +747,11 @@ fn decode_recv(
725747
(libc::SOL_UDP, gro::UDP_GRO) => unsafe {
726748
stride = cmsg::decode::<libc::c_int, libc::cmsghdr>(cmsg) as usize;
727749
},
750+
#[cfg(target_os = "linux")]
751+
(libc::SOL_SOCKET, libc::SCM_TIMESTAMPNS) => {
752+
let tv = unsafe { cmsg::decode::<libc::timespec, libc::cmsghdr>(cmsg) };
753+
timestamp = Some(Duration::new(tv.tv_sec as u64, tv.tv_nsec as u32));
754+
}
728755
_ => {}
729756
}
730757
}
@@ -759,6 +786,7 @@ fn decode_recv(
759786
addr,
760787
ecn: EcnCodepoint::from_bits(ecn_bits),
761788
dst_ip,
789+
timestamp,
762790
}
763791
}
764792

@@ -907,6 +935,8 @@ fn set_socket_option(
907935
}
908936
}
909937

938+
#[allow(dead_code)]
939+
const OPTION_OFF: libc::c_int = 0;
910940
const OPTION_ON: libc::c_int = 1;
911941

912942
#[cfg(not(any(target_os = "linux", target_os = "android")))]

quinn-udp/src/windows.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ impl UdpSocketState {
267267
addr: addr.unwrap(),
268268
ecn: EcnCodepoint::from_bits(ecn_bits as u8),
269269
dst_ip,
270+
timestamp: None,
270271
};
271272
Ok(1)
272273
}

0 commit comments

Comments
 (0)