@@ -6,6 +6,7 @@ use features;
6
6
use libc:: { self , c_void, c_int, socklen_t, size_t, pid_t, uid_t, gid_t} ;
7
7
use std:: { mem, ptr, slice} ;
8
8
use std:: os:: unix:: io:: RawFd ;
9
+ use sys:: time:: TimeVal ;
9
10
use sys:: uio:: IoVec ;
10
11
11
12
mod addr;
@@ -277,6 +278,10 @@ impl<'a> Iterator for CmsgIterator<'a> {
277
278
slice:: from_raw_parts (
278
279
& cmsg. cmsg_data as * const _ as * const _ , 1 ) ) )
279
280
} ,
281
+ ( libc:: SOL_SOCKET , libc:: SCM_TIMESTAMP ) => unsafe {
282
+ Some ( ControlMessage :: ScmTimestamp (
283
+ & * ( & cmsg. cmsg_data as * const _ as * const _ ) ) )
284
+ } ,
280
285
( _, _) => unsafe {
281
286
Some ( ControlMessage :: Unknown ( UnknownCmsg (
282
287
& cmsg,
@@ -292,11 +297,80 @@ impl<'a> Iterator for CmsgIterator<'a> {
292
297
/// be added to this enum; do not exhaustively pattern-match it.
293
298
/// [Further reading](http://man7.org/linux/man-pages/man3/cmsg.3.html)
294
299
pub enum ControlMessage < ' a > {
295
- /// A message of type SCM_RIGHTS, containing an array of file
296
- /// descriptors passed between processes. See the description in the
297
- /// "Ancillary messages" section of the
300
+ /// A message of type `SCM_RIGHTS`, containing an array of file
301
+ /// descriptors passed between processes.
302
+ ///
303
+ /// See the description in the "Ancillary messages" section of the
298
304
/// [unix(7) man page](http://man7.org/linux/man-pages/man7/unix.7.html).
299
305
ScmRights ( & ' a [ RawFd ] ) ,
306
+ /// A message of type `SCM_TIMESTAMP`, containing the time the
307
+ /// packet was received by the kernel.
308
+ ///
309
+ /// See the kernel's explanation in "SO_TIMESTAMP" of
310
+ /// [networking/timestamping](https://www.kernel.org/doc/Documentation/networking/timestamping.txt).
311
+ ///
312
+ /// # Examples
313
+ ///
314
+ // Disable this test on FreeBSD i386
315
+ // https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=222039
316
+ #[ cfg_attr( not( all( target_os = "freebsd" , target_arch = "x86" ) ) , doc = " ```" ) ]
317
+ #[ cfg_attr( all( target_os = "freebsd" , target_arch = "x86" ) , doc = " ```no_run" ) ]
318
+ /// use nix::sys::socket::*;
319
+ /// use nix::sys::uio::IoVec;
320
+ /// use nix::sys::time::*;
321
+ /// use std::time::*;
322
+ ///
323
+ /// // Set up
324
+ /// let message1 = "Ohayō!".as_bytes();
325
+ /// let message2 = "Jā ne".as_bytes();
326
+ /// let in_socket = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None).unwrap();
327
+ /// setsockopt(in_socket, sockopt::ReceiveTimestamp, &true).unwrap();
328
+ /// bind(in_socket, &SockAddr::new_inet(InetAddr::new(IpAddr::new_v4(127, 0, 0, 1), 0))).unwrap();
329
+ /// let address = if let Ok(address) = getsockname(in_socket) { address } else { unreachable!() };
330
+ ///
331
+ /// // Send both
332
+ /// assert!(Ok(message1.len()) == sendmsg(in_socket, &[IoVec::from_slice(message1)], &[], MsgFlags::empty(), Some(&address)));
333
+ /// let time = SystemTime::now();
334
+ /// std::thread::sleep(Duration::from_millis(250));
335
+ /// assert!(Ok(message2.len()) == sendmsg(in_socket, &[IoVec::from_slice(message2)], &[], MsgFlags::empty(), Some(&address)));
336
+ /// let delay = time.elapsed().unwrap();
337
+ ///
338
+ /// // Receive the first
339
+ /// let mut buffer1 = vec![0u8; message1.len() + message2.len()];
340
+ /// let mut time1: CmsgSpace<TimeVal> = CmsgSpace::new();
341
+ /// let received1 = recvmsg(in_socket, &[IoVec::from_mut_slice(&mut buffer1)], Some(&mut time1), MsgFlags::empty()).unwrap();
342
+ /// let mut time1 = if let Some(ControlMessage::ScmTimestamp(&time1)) = received1.cmsgs().next() { time1 } else { panic!("Unexpected or no control message") };
343
+ ///
344
+ /// // Receive the second
345
+ /// let mut buffer2 = vec![0u8; message1.len() + message2.len()];
346
+ /// let mut time2: CmsgSpace<TimeVal> = CmsgSpace::new();
347
+ /// let received2 = recvmsg(in_socket, &[IoVec::from_mut_slice(&mut buffer2)], Some(&mut time2), MsgFlags::empty()).unwrap();
348
+ /// let mut time2 = if let Some(ControlMessage::ScmTimestamp(&time2)) = received2.cmsgs().next() { time2 } else { panic!("Unexpected or no control message") };
349
+ ///
350
+ /// // Swap if needed; UDP is unordered
351
+ /// match (received1.bytes, received2.bytes, message1.len(), message2.len()) {
352
+ /// (l1, l2, m1, m2) if l1 == m1 && l2 == m2 => {},
353
+ /// (l2, l1, m1, m2) if l1 == m1 && l2 == m2 => {
354
+ /// std::mem::swap(&mut time1, &mut time2);
355
+ /// std::mem::swap(&mut buffer1, &mut buffer2);
356
+ /// },
357
+ /// _ => panic!("Wrong packets"),
358
+ /// };
359
+ ///
360
+ /// // Compare results
361
+ /// println!("{:?} @ {:?}, {:?} @ {:?}, {:?}", buffer1, time1, buffer2, time2, delay);
362
+ /// assert!(message1 == &buffer1[0..(message1.len())], "{:?} == {:?}", message1, buffer1);
363
+ /// assert!(message2 == &buffer2[0..(message2.len())], "{:?} == {:?}", message2, buffer2);
364
+ /// let time = time2 - time1;
365
+ /// let time = Duration::new(time.num_seconds() as u64, time.num_nanoseconds() as u32);
366
+ /// let difference = if delay < time { time - delay } else { delay - time };
367
+ /// assert!(difference.subsec_nanos() < 5_000_000, "{}ns < 5ms", difference.subsec_nanos());
368
+ /// assert!(difference.as_secs() == 0);
369
+ ///
370
+ /// // Close socket
371
+ /// nix::unistd::close(in_socket).unwrap();
372
+ /// ```
373
+ ScmTimestamp ( & ' a TimeVal ) ,
300
374
#[ doc( hidden) ]
301
375
Unknown ( UnknownCmsg < ' a > ) ,
302
376
}
@@ -322,6 +396,9 @@ impl<'a> ControlMessage<'a> {
322
396
ControlMessage :: ScmRights ( fds) => {
323
397
mem:: size_of_val ( fds)
324
398
} ,
399
+ ControlMessage :: ScmTimestamp ( t) => {
400
+ mem:: size_of_val ( t)
401
+ } ,
325
402
ControlMessage :: Unknown ( UnknownCmsg ( _, bytes) ) => {
326
403
mem:: size_of_val ( bytes)
327
404
}
@@ -352,6 +429,25 @@ impl<'a> ControlMessage<'a> {
352
429
353
430
copy_bytes ( fds, buf) ;
354
431
} ,
432
+ ControlMessage :: ScmTimestamp ( t) => {
433
+ let cmsg = cmsghdr {
434
+ cmsg_len : self . len ( ) as type_of_cmsg_len ,
435
+ cmsg_level : libc:: SOL_SOCKET ,
436
+ cmsg_type : libc:: SCM_TIMESTAMP ,
437
+ cmsg_data : [ ] ,
438
+ } ;
439
+ copy_bytes ( & cmsg, buf) ;
440
+
441
+ let padlen = cmsg_align ( mem:: size_of_val ( & cmsg) ) -
442
+ mem:: size_of_val ( & cmsg) ;
443
+
444
+ let mut tmpbuf = & mut [ ] [ ..] ;
445
+ mem:: swap ( & mut tmpbuf, buf) ;
446
+ let ( _padding, mut remainder) = tmpbuf. split_at_mut ( padlen) ;
447
+ mem:: swap ( buf, & mut remainder) ;
448
+
449
+ copy_bytes ( t, buf) ;
450
+ } ,
355
451
ControlMessage :: Unknown ( UnknownCmsg ( orig_cmsg, bytes) ) => {
356
452
copy_bytes ( orig_cmsg, buf) ;
357
453
copy_bytes ( bytes, buf) ;
0 commit comments