@@ -12,6 +12,9 @@ use std::{
12
12
time:: Instant ,
13
13
} ;
14
14
15
+ #[ cfg( target_os = "linux" ) ]
16
+ use std:: time:: Duration ;
17
+
15
18
use socket2:: SockRef ;
16
19
17
20
use super :: {
@@ -96,6 +99,11 @@ impl UdpSocketState {
96
99
unsafe { libc:: CMSG_SPACE ( mem:: size_of :: < libc:: in6_pktinfo > ( ) as _ ) as usize } ;
97
100
}
98
101
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
+
99
107
assert ! (
100
108
CMSG_LEN
101
109
>= unsafe { libc:: CMSG_SPACE ( mem:: size_of:: <libc:: c_int>( ) as _) as usize }
@@ -257,6 +265,18 @@ impl UdpSocketState {
257
265
self . may_fragment
258
266
}
259
267
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
+
260
280
/// Returns true if we previously got an EINVAL error from `sendmsg` syscall.
261
281
fn sendmsg_einval ( & self ) -> bool {
262
282
self . sendmsg_einval . load ( Ordering :: Relaxed )
@@ -543,7 +563,7 @@ fn recv(io: SockRef<'_>, bufs: &mut [IoSliceMut<'_>], meta: &mut [RecvMeta]) ->
543
563
Ok ( 1 )
544
564
}
545
565
546
- const CMSG_LEN : usize = 88 ;
566
+ const CMSG_LEN : usize = 96 ;
547
567
548
568
fn prepare_msg (
549
569
transmit : & Transmit < ' _ > ,
@@ -681,6 +701,8 @@ fn decode_recv(
681
701
let mut dst_ip = None ;
682
702
#[ allow( unused_mut) ] // only mutable on Linux
683
703
let mut stride = len;
704
+ #[ allow( unused_mut) ] // only mutable on Linux
705
+ let mut timestamp = None ;
684
706
685
707
let cmsg_iter = unsafe { cmsg:: Iter :: new ( hdr) } ;
686
708
for cmsg in cmsg_iter {
@@ -725,6 +747,11 @@ fn decode_recv(
725
747
( libc:: SOL_UDP , gro:: UDP_GRO ) => unsafe {
726
748
stride = cmsg:: decode :: < libc:: c_int , libc:: cmsghdr > ( cmsg) as usize ;
727
749
} ,
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
+ }
728
755
_ => { }
729
756
}
730
757
}
@@ -759,6 +786,7 @@ fn decode_recv(
759
786
addr,
760
787
ecn : EcnCodepoint :: from_bits ( ecn_bits) ,
761
788
dst_ip,
789
+ timestamp,
762
790
}
763
791
}
764
792
@@ -907,6 +935,8 @@ fn set_socket_option(
907
935
}
908
936
}
909
937
938
+ #[ allow( dead_code) ]
939
+ const OPTION_OFF : libc:: c_int = 0 ;
910
940
const OPTION_ON : libc:: c_int = 1 ;
911
941
912
942
#[ cfg( not( any( target_os = "linux" , target_os = "android" ) ) ) ]
0 commit comments