@@ -258,6 +258,11 @@ impl<'a> Iterator for CmsgIterator<'a> {
258
258
slice:: from_raw_parts (
259
259
& cmsg. cmsg_data as * const _ as * const _ , 1 ) ) )
260
260
} ,
261
+ #[ cfg( not( all( target_arch = "x86" , target_os = "freebsd" ) ) ) ]
262
+ ( libc:: SOL_SOCKET , libc:: SCM_TIMESTAMP ) => unsafe {
263
+ Some ( ControlMessage :: ScmTimestamp (
264
+ & * ( & cmsg. cmsg_data as * const _ as * const _ ) ) )
265
+ } ,
261
266
( _, _) => unsafe {
262
267
Some ( ControlMessage :: Unknown ( UnknownCmsg (
263
268
& cmsg,
@@ -274,10 +279,77 @@ impl<'a> Iterator for CmsgIterator<'a> {
274
279
/// [Further reading](http://man7.org/linux/man-pages/man3/cmsg.3.html)
275
280
pub enum ControlMessage < ' a > {
276
281
/// A message of type SCM_RIGHTS, containing an array of file
277
- /// descriptors passed between processes. See the description in the
278
- /// "Ancillary messages" section of the
282
+ /// descriptors passed between processes.
283
+ ///
284
+ /// See the description in the "Ancillary messages" section of the
279
285
/// [unix(7) man page](http://man7.org/linux/man-pages/man7/unix.7.html).
280
286
ScmRights ( & ' a [ RawFd ] ) ,
287
+ /// A message of type SCM_TIMESTAMP, containing the time the packet
288
+ /// was received by the kernel.
289
+ ///
290
+ /// See the kernel's explanation in "SO_TIMESTAMP" of
291
+ /// [networking/timestamping](https://www.kernel.org/doc/Documentation/networking/timestamping.txt).
292
+ ///
293
+ /// # Examples
294
+ ///
295
+ /// ```
296
+ /// use nix::sys::socket::*;
297
+ /// use nix::sys::uio::IoVec;
298
+ /// use nix::sys::time::*;
299
+ /// use std::time::*;
300
+ ///
301
+ /// // Set up
302
+ /// let message1 = "Ohayō!".as_bytes();
303
+ /// let message2 = "Jā ne".as_bytes();
304
+ /// let in_socket = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None).unwrap();
305
+ /// setsockopt(in_socket, sockopt::ReceiveTimestamp, &true).unwrap();
306
+ /// bind(in_socket, &SockAddr::new_inet(InetAddr::new(IpAddr::new_v4(127, 0, 0, 1), 0))).unwrap();
307
+ /// let address = if let Ok(address) = getsockname(in_socket) { address } else { unreachable!() };
308
+ ///
309
+ /// // Send both
310
+ /// assert!(Ok(message1.len()) == sendmsg(in_socket, &[IoVec::from_slice(message1)], &[], MsgFlags::empty(), Some(&address)));
311
+ /// let time = SystemTime::now();
312
+ /// std::thread::sleep(Duration::from_millis(250));
313
+ /// assert!(Ok(message2.len()) == sendmsg(in_socket, &[IoVec::from_slice(message2)], &[], MsgFlags::empty(), Some(&address)));
314
+ /// let delay = time.elapsed().unwrap();
315
+ ///
316
+ /// // Receive the first
317
+ /// let mut buffer1 = vec![0u8; message1.len() + message2.len()];
318
+ /// let mut time1: CmsgSpace<TimeVal> = CmsgSpace::new();
319
+ /// let received1 = recvmsg(in_socket, &[IoVec::from_mut_slice(&mut buffer1)], Some(&mut time1), MsgFlags::empty()).unwrap();
320
+ /// let mut time1 = if let Some(ControlMessage::ScmTimestamp(&time1)) = received1.cmsgs().next() { time1 } else { panic!("Unexpected or no control message") };
321
+ ///
322
+ /// // Receive the second
323
+ /// let mut buffer2 = vec![0u8; message1.len() + message2.len()];
324
+ /// let mut time2: CmsgSpace<TimeVal> = CmsgSpace::new();
325
+ /// let received2 = recvmsg(in_socket, &[IoVec::from_mut_slice(&mut buffer2)], Some(&mut time2), MsgFlags::empty()).unwrap();
326
+ /// let mut time2 = if let Some(ControlMessage::ScmTimestamp(&time2)) = received2.cmsgs().next() { time2 } else { panic!("Unexpected or no control message") };
327
+ ///
328
+ /// // Swap if needed; UDP is unordered
329
+ /// match (received1.bytes, received2.bytes, message1.len(), message2.len()) {
330
+ /// (l1, l2, m1, m2) if l1 == m1 && l2 == m2 => {},
331
+ /// (l2, l1, m1, m2) if l1 == m1 && l2 == m2 => {
332
+ /// std::mem::swap(&mut time1, &mut time2);
333
+ /// std::mem::swap(&mut buffer1, &mut buffer2);
334
+ /// },
335
+ /// _ => panic!("Wrong packets"),
336
+ /// };
337
+ ///
338
+ /// // Compare results
339
+ /// assert!(message1 == &buffer1[0..(message1.len())], "{:?} == {:?}", message1, buffer1);
340
+ /// assert!(message2 == &buffer2[0..(message2.len())], "{:?} == {:?}", message2, buffer2);
341
+ /// let time = time2 - time1;
342
+ /// let time = Duration::new(time.num_seconds() as u64, time.num_nanoseconds() as u32);
343
+ /// let difference = if delay < time { time - delay } else { delay - time };
344
+ /// assert!(difference.subsec_nanos() < 15_000, "{}ns < 15ms", difference.subsec_nanos());
345
+ /// assert!(difference.as_secs() == 0);
346
+ /// println!("{:?} @ {:?}, {:?} @ {:?}, {:?}", buffer1, time1, buffer2, time2, delay);
347
+ ///
348
+ /// // Close socket
349
+ /// nix::unistd::close(in_socket).unwrap();
350
+ /// ```
351
+ #[ cfg( not( all( target_arch = "x86" , target_os = "freebsd" ) ) ) ]
352
+ ScmTimestamp ( & ' a :: sys:: time:: TimeVal ) ,
281
353
#[ doc( hidden) ]
282
354
Unknown ( UnknownCmsg < ' a > ) ,
283
355
}
@@ -303,6 +375,10 @@ impl<'a> ControlMessage<'a> {
303
375
ControlMessage :: ScmRights ( fds) => {
304
376
mem:: size_of_val ( fds)
305
377
} ,
378
+ #[ cfg( not( all( target_arch = "x86" , target_os = "freebsd" ) ) ) ]
379
+ ControlMessage :: ScmTimestamp ( t) => {
380
+ mem:: size_of_val ( t)
381
+ } ,
306
382
ControlMessage :: Unknown ( UnknownCmsg ( _, bytes) ) => {
307
383
mem:: size_of_val ( bytes)
308
384
}
@@ -333,6 +409,26 @@ impl<'a> ControlMessage<'a> {
333
409
334
410
copy_bytes ( fds, buf) ;
335
411
} ,
412
+ #[ cfg( not( all( target_arch = "x86" , target_os = "freebsd" ) ) ) ]
413
+ ControlMessage :: ScmTimestamp ( t) => {
414
+ let cmsg = cmsghdr {
415
+ cmsg_len : self . len ( ) as type_of_cmsg_len ,
416
+ cmsg_level : libc:: SOL_SOCKET ,
417
+ cmsg_type : libc:: SCM_TIMESTAMP ,
418
+ cmsg_data : [ ] ,
419
+ } ;
420
+ copy_bytes ( & cmsg, buf) ;
421
+
422
+ let padlen = cmsg_align ( mem:: size_of_val ( & cmsg) ) -
423
+ mem:: size_of_val ( & cmsg) ;
424
+
425
+ let mut tmpbuf = & mut [ ] [ ..] ;
426
+ mem:: swap ( & mut tmpbuf, buf) ;
427
+ let ( _padding, mut remainder) = tmpbuf. split_at_mut ( padlen) ;
428
+ mem:: swap ( buf, & mut remainder) ;
429
+
430
+ copy_bytes ( t, buf) ;
431
+ } ,
336
432
ControlMessage :: Unknown ( UnknownCmsg ( orig_cmsg, bytes) ) => {
337
433
copy_bytes ( orig_cmsg, buf) ;
338
434
copy_bytes ( bytes, buf) ;
0 commit comments