@@ -12,6 +12,9 @@ use std::{
1212 time:: Instant ,
1313} ;
1414
15+ #[ cfg( target_os = "linux" ) ]
16+ use std:: time:: Duration ;
17+
1518use socket2:: SockRef ;
1619
1720use 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
548568fn 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 ;
910940const OPTION_ON : libc:: c_int = 1 ;
911941
912942#[ cfg( not( any( target_os = "linux" , target_os = "android" ) ) ) ]
0 commit comments