@@ -9,6 +9,7 @@ use libc::{self, c_void, c_int, socklen_t, size_t, pid_t, uid_t, gid_t};
9
9
use std:: { mem, ptr, slice} ;
10
10
use std:: os:: unix:: io:: RawFd ;
11
11
use sys:: uio:: IoVec ;
12
+ use sys:: time:: TimeVal ;
12
13
13
14
mod addr;
14
15
mod ffi;
@@ -245,6 +246,10 @@ impl<'a> Iterator for CmsgIterator<'a> {
245
246
slice:: from_raw_parts (
246
247
& cmsg. cmsg_data as * const _ as * const _ , 1 ) ) )
247
248
} ,
249
+ ( libc:: SOL_SOCKET , libc:: SCM_TIMESTAMP ) => unsafe {
250
+ Some ( ControlMessage :: ScmTimestamp (
251
+ & * ( & cmsg. cmsg_data as * const _ as * const _ ) ) )
252
+ } ,
248
253
( _, _) => unsafe {
249
254
Some ( ControlMessage :: Unknown ( UnknownCmsg (
250
255
& cmsg,
@@ -261,10 +266,71 @@ impl<'a> Iterator for CmsgIterator<'a> {
261
266
/// [Further reading](http://man7.org/linux/man-pages/man3/cmsg.3.html)
262
267
pub enum ControlMessage < ' a > {
263
268
/// A message of type SCM_RIGHTS, containing an array of file
264
- /// descriptors passed between processes. See the description in the
265
- /// "Ancillary messages" section of the
269
+ /// descriptors passed between processes.
270
+ ///
271
+ /// See the description in the "Ancillary messages" section of the
266
272
/// [unix(7) man page](http://man7.org/linux/man-pages/man7/unix.7.html).
267
273
ScmRights ( & ' a [ RawFd ] ) ,
274
+ /// A message of type SCM_TIMESTAMP, containing the time the packet
275
+ /// was received by the kernel.
276
+ ///
277
+ /// See the kernel's explanation in "SO_TIMESTAMP" of
278
+ /// [networking/timestamping](https://www.kernel.org/doc/Documentation/networking/timestamping.txt).
279
+ ///
280
+ /// # Example
281
+ ///
282
+ /// ```
283
+ /// use nix::sys::socket::*;
284
+ /// use nix::sys::uio::IoVec;
285
+ /// use nix::sys::time::*;
286
+ ///
287
+ /// // Set up
288
+ /// let delay = 250;
289
+ /// let message1 = "Ohayō!".as_bytes();
290
+ /// let message2 = "Jā ne".as_bytes();
291
+ /// let in_socket = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None).unwrap();
292
+ /// setsockopt(in_socket, sockopt::ReceiveTimestamp, &true).unwrap();
293
+ /// bind(in_socket, &SockAddr::new_inet(InetAddr::new(IpAddr::new_v4(127, 0, 0, 1), 0))).unwrap();
294
+ /// let address = if let Ok(address) = getsockname(in_socket) { address } else { unreachable!() };
295
+ ///
296
+ /// // Send both
297
+ /// assert!(Ok(message1.len()) == sendmsg(in_socket, &[IoVec::from_slice(message1)], &[], MsgFlags::empty(), Some(&address)));
298
+ /// std::thread::sleep(std::time::Duration::from_millis(delay as u64));
299
+ /// assert!(Ok(message2.len()) == sendmsg(in_socket, &[IoVec::from_slice(message2)], &[], MsgFlags::empty(), Some(&address)));
300
+ ///
301
+ /// // Receive the first
302
+ /// let mut buffer1 = vec![0u8; message1.len() + message2.len()];
303
+ /// let mut time1: CmsgSpace<TimeVal> = CmsgSpace::new();
304
+ /// let received1 = recvmsg(in_socket, &[IoVec::from_mut_slice(&mut buffer1)], Some(&mut time1), MsgFlags::empty()).unwrap();
305
+ /// let mut time1 = if let Some(ControlMessage::ScmTimestamp(&time1)) = received1.cmsgs().next() { time1 } else { panic!("Unexpected or no control message") };
306
+ ///
307
+ /// // Receive the second
308
+ /// let mut buffer2 = vec![0u8; message1.len() + message2.len()];
309
+ /// let mut time2: CmsgSpace<TimeVal> = CmsgSpace::new();
310
+ /// let received2 = recvmsg(in_socket, &[IoVec::from_mut_slice(&mut buffer2)], Some(&mut time2), MsgFlags::empty()).unwrap();
311
+ /// let mut time2 = if let Some(ControlMessage::ScmTimestamp(&time2)) = received2.cmsgs().next() { time2 } else { panic!("Unexpected or no control message") };
312
+ ///
313
+ /// // Swap if needed, UDP is unordered
314
+ /// match (received1.bytes, received2.bytes, message1.len(), message2.len()) {
315
+ /// (l1, l2, m1, m2) if l1 == m1 && l2 == m2 => {},
316
+ /// (l2, l1, m1, m2) if l1 == m1 && l2 == m2 =>
317
+ /// std::mem::swap(&mut (&mut time1, &mut buffer1), &mut(&mut time2, &mut buffer2)),
318
+ /// _ => panic!("Wrong packets"),
319
+ /// };
320
+ ///
321
+ /// // Compare results
322
+ /// assert!(message1 == &buffer1[0..(message1.len())], "{:?} == {:?}", message1, buffer1);
323
+ /// assert!(message2 == &buffer2[0..(message2.len())], "{:?} == {:?}", message2, buffer2);
324
+ /// let time = time2 - time1;
325
+ /// assert!(time.num_milliseconds() < delay + 10, "{} < {}", time.num_milliseconds(), delay + 10);
326
+ /// assert!(time.num_milliseconds() > delay - 10, "{} < {}", time.num_milliseconds(), delay - 10);
327
+ /// assert!(time.num_seconds() == 0);
328
+ /// println!("{:?} @ {:?}, {:?} @ {:?}", buffer1, time1, buffer2, time2);
329
+ ///
330
+ /// // Close socket
331
+ /// nix::unistd::close(in_socket).unwrap();
332
+ /// ```
333
+ ScmTimestamp ( & ' a TimeVal ) ,
268
334
#[ doc( hidden) ]
269
335
Unknown ( UnknownCmsg < ' a > ) ,
270
336
}
@@ -290,6 +356,9 @@ impl<'a> ControlMessage<'a> {
290
356
ControlMessage :: ScmRights ( fds) => {
291
357
mem:: size_of_val ( fds)
292
358
} ,
359
+ ControlMessage :: ScmTimestamp ( t) => {
360
+ mem:: size_of_val ( t)
361
+ } ,
293
362
ControlMessage :: Unknown ( UnknownCmsg ( _, bytes) ) => {
294
363
mem:: size_of_val ( bytes)
295
364
}
@@ -320,6 +389,25 @@ impl<'a> ControlMessage<'a> {
320
389
321
390
copy_bytes ( fds, buf) ;
322
391
} ,
392
+ ControlMessage :: ScmTimestamp ( t) => {
393
+ let cmsg = cmsghdr {
394
+ cmsg_len : self . len ( ) as type_of_cmsg_len ,
395
+ cmsg_level : libc:: SOL_SOCKET ,
396
+ cmsg_type : libc:: SCM_TIMESTAMP ,
397
+ cmsg_data : [ ] ,
398
+ } ;
399
+ copy_bytes ( & cmsg, buf) ;
400
+
401
+ let padlen = cmsg_align ( mem:: size_of_val ( & cmsg) ) -
402
+ mem:: size_of_val ( & cmsg) ;
403
+
404
+ let mut tmpbuf = & mut [ ] [ ..] ;
405
+ mem:: swap ( & mut tmpbuf, buf) ;
406
+ let ( _padding, mut remainder) = tmpbuf. split_at_mut ( padlen) ;
407
+ mem:: swap ( buf, & mut remainder) ;
408
+
409
+ copy_bytes ( t, buf) ;
410
+ } ,
323
411
ControlMessage :: Unknown ( UnknownCmsg ( orig_cmsg, bytes) ) => {
324
412
copy_bytes ( orig_cmsg, buf) ;
325
413
copy_bytes ( bytes, buf) ;
0 commit comments