1#[cfg(any(target_os = "linux", target_os = "android"))]
2use crate::*;
3use libc::c_char;
4use nix::sys::socket::{getsockname, AddressFamily, UnixAddr};
5use std::collections::hash_map::DefaultHasher;
6use std::hash::{Hash, Hasher};
7use std::net::{SocketAddrV4, SocketAddrV6};
8use std::os::unix::io::{AsRawFd, RawFd};
9use std::path::Path;
10use std::slice;
11use std::str::FromStr;
12
13#[cfg(target_os = "linux")]
14#[cfg_attr(qemu, ignore)]
15#[test]
16pub fn test_timestamping() {
17 use nix::sys::socket::{
18 recvmsg, sendmsg, setsockopt, socket, sockopt::Timestamping,
19 ControlMessageOwned, MsgFlags, SockFlag, SockType, SockaddrIn,
20 TimestampingFlag,
21 };
22 use std::io::{IoSlice, IoSliceMut};
23
24 let sock_addr = SockaddrIn::from_str("127.0.0.1:6790").unwrap();
25
26 let ssock = socket(
27 AddressFamily::Inet,
28 SockType::Datagram,
29 SockFlag::empty(),
30 None,
31 )
32 .expect("send socket failed");
33
34 let rsock = socket(
35 AddressFamily::Inet,
36 SockType::Datagram,
37 SockFlag::empty(),
38 None,
39 )
40 .unwrap();
41 nix::sys::socket::bind(rsock.as_raw_fd(), &sock_addr).unwrap();
42
43 setsockopt(&rsock, Timestamping, &TimestampingFlag::all()).unwrap();
44
45 let sbuf = [0u8; 2048];
46 let mut rbuf = [0u8; 2048];
47 let flags = MsgFlags::empty();
48 let iov1 = [IoSlice::new(&sbuf)];
49 let mut iov2 = [IoSliceMut::new(&mut rbuf)];
50
51 let mut cmsg = cmsg_space!(nix::sys::socket::Timestamps);
52 sendmsg(ssock.as_raw_fd(), &iov1, &[], flags, Some(&sock_addr)).unwrap();
53 let recv =
54 recvmsg::<()>(rsock.as_raw_fd(), &mut iov2, Some(&mut cmsg), flags)
55 .unwrap();
56
57 let mut ts = None;
58 for c in recv.cmsgs() {
59 if let ControlMessageOwned::ScmTimestampsns(timestamps) = c {
60 ts = Some(timestamps.system);
61 }
62 }
63 let ts = ts.expect("ScmTimestampns is present");
64 let sys_time =
65 ::nix::time::clock_gettime(::nix::time::ClockId::CLOCK_REALTIME)
66 .unwrap();
67 let diff = if ts > sys_time {
68 ts - sys_time
69 } else {
70 sys_time - ts
71 };
72 assert!(std::time::Duration::from(diff).as_secs() < 60);
73}
74
75#[test]
76pub fn test_path_to_sock_addr() {
77 let path = "/foo/bar";
78 let actual = Path::new(path);
79 let addr = UnixAddr::new(actual).unwrap();
80
81 let expect: &[c_char] = unsafe {
82 slice::from_raw_parts(path.as_ptr() as *const c_char, path.len())
83 };
84 assert_eq!(unsafe { &(*addr.as_ptr()).sun_path[..8] }, expect);
85
86 assert_eq!(addr.path(), Some(actual));
87}
88
89fn calculate_hash<T: Hash>(t: &T) -> u64 {
90 let mut s = DefaultHasher::new();
91 t.hash(&mut s);
92 s.finish()
93}
94
95#[test]
96pub fn test_addr_equality_path() {
97 let path = "/foo/bar";
98 let actual = Path::new(path);
99 let addr1 = UnixAddr::new(actual).unwrap();
100 let mut addr2 = addr1;
101
102 unsafe { (*addr2.as_mut_ptr()).sun_path[10] = 127 };
103
104 assert_eq!(addr1, addr2);
105 assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2));
106}
107
108#[cfg(any(target_os = "android", target_os = "linux"))]
109#[test]
110pub fn test_abstract_sun_path_too_long() {
111 let name = String::from("nix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0testttttnix\0abstract\0test\0make\0sure\0this\0is\0long\0enough");
112 let addr = UnixAddr::new_abstract(name.as_bytes());
113 addr.expect_err("assertion failed");
114}
115
116#[cfg(any(target_os = "android", target_os = "linux"))]
117#[test]
118pub fn test_addr_equality_abstract() {
119 let name = String::from("nix\0abstract\0test");
120 let addr1 = UnixAddr::new_abstract(name.as_bytes()).unwrap();
121 let mut addr2 = addr1;
122
123 assert_eq!(addr1, addr2);
124 assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2));
125
126 unsafe { (*addr2.as_mut_ptr()).sun_path[17] = 127 };
127 assert_ne!(addr1, addr2);
128 assert_ne!(calculate_hash(&addr1), calculate_hash(&addr2));
129}
130
131// Test getting/setting abstract addresses (without unix socket creation)
132#[cfg(any(target_os = "android", target_os = "linux"))]
133#[test]
134pub fn test_abstract_uds_addr() {
135 let empty = String::new();
136 let addr = UnixAddr::new_abstract(empty.as_bytes()).unwrap();
137 let sun_path: [u8; 0] = [];
138 assert_eq!(addr.as_abstract(), Some(&sun_path[..]));
139
140 let name = String::from("nix\0abstract\0test");
141 let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap();
142 let sun_path = [
143 110u8, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101,
144 115, 116,
145 ];
146 assert_eq!(addr.as_abstract(), Some(&sun_path[..]));
147 assert_eq!(addr.path(), None);
148
149 // Internally, name is null-prefixed (abstract namespace)
150 assert_eq!(unsafe { (*addr.as_ptr()).sun_path[0] }, 0);
151}
152
153// Test getting an unnamed address (without unix socket creation)
154#[cfg(any(target_os = "android", target_os = "linux"))]
155#[test]
156pub fn test_unnamed_uds_addr() {
157 use crate::nix::sys::socket::SockaddrLike;
158
159 let addr = UnixAddr::new_unnamed();
160
161 assert!(addr.is_unnamed());
162 assert_eq!(addr.len(), 2);
163 assert!(addr.path().is_none());
164 assert_eq!(addr.path_len(), 0);
165
166 assert!(addr.as_abstract().is_none());
167}
168
169#[test]
170pub fn test_getsockname() {
171 use nix::sys::socket::bind;
172 use nix::sys::socket::{socket, AddressFamily, SockFlag, SockType};
173
174 let tempdir = tempfile::tempdir().unwrap();
175 let sockname = tempdir.path().join("sock");
176 let sock = socket(
177 AddressFamily::Unix,
178 SockType::Stream,
179 SockFlag::empty(),
180 None,
181 )
182 .expect("socket failed");
183 let sockaddr = UnixAddr::new(&sockname).unwrap();
184 bind(sock.as_raw_fd(), &sockaddr).expect("bind failed");
185 assert_eq!(
186 sockaddr,
187 getsockname(sock.as_raw_fd()).expect("getsockname failed")
188 );
189}
190
191#[test]
192pub fn test_socketpair() {
193 use nix::sys::socket::{socketpair, AddressFamily, SockFlag, SockType};
194 use nix::unistd::{read, write};
195
196 let (fd1, fd2) = socketpair(
197 AddressFamily::Unix,
198 SockType::Stream,
199 None,
200 SockFlag::empty(),
201 )
202 .unwrap();
203 write(fd1.as_raw_fd(), b"hello").unwrap();
204 let mut buf = [0; 5];
205 read(fd2.as_raw_fd(), &mut buf).unwrap();
206
207 assert_eq!(&buf[..], b"hello");
208}
209
210#[test]
211pub fn test_recvmsg_sockaddr_un() {
212 use nix::sys::socket::{
213 self, bind, socket, AddressFamily, MsgFlags, SockFlag, SockType,
214 };
215
216 let tempdir = tempfile::tempdir().unwrap();
217 let sockname = tempdir.path().join("sock");
218 let sock = socket(
219 AddressFamily::Unix,
220 SockType::Datagram,
221 SockFlag::empty(),
222 None,
223 )
224 .expect("socket failed");
225 let sockaddr = UnixAddr::new(&sockname).unwrap();
226 bind(sock.as_raw_fd(), &sockaddr).expect("bind failed");
227
228 // Send a message
229 let send_buffer = "hello".as_bytes();
230 if let Err(e) = socket::sendmsg(
231 sock.as_raw_fd(),
232 &[std::io::IoSlice::new(send_buffer)],
233 &[],
234 MsgFlags::empty(),
235 Some(&sockaddr),
236 ) {
237 crate::skip!("Couldn't send ({e:?}), so skipping test");
238 }
239
240 // Receive the message
241 let mut recv_buffer = [0u8; 32];
242 let mut iov = [std::io::IoSliceMut::new(&mut recv_buffer)];
243 let received =
244 socket::recvmsg(sock.as_raw_fd(), &mut iov, None, MsgFlags::empty())
245 .unwrap();
246 // Check the address in the received message
247 assert_eq!(sockaddr, received.address.unwrap());
248}
249
250#[test]
251pub fn test_std_conversions() {
252 use nix::sys::socket::*;
253
254 let std_sa = SocketAddrV4::from_str("127.0.0.1:6789").unwrap();
255 let sock_addr = SockaddrIn::from(std_sa);
256 assert_eq!(std_sa, sock_addr.into());
257
258 let std_sa = SocketAddrV6::from_str("[::1]:6000").unwrap();
259 let sock_addr: SockaddrIn6 = SockaddrIn6::from(std_sa);
260 assert_eq!(std_sa, sock_addr.into());
261}
262
263mod recvfrom {
264 use super::*;
265 use nix::sys::socket::*;
266 use nix::{errno::Errno, Result};
267 use std::thread;
268
269 const MSG: &[u8] = b"Hello, World!";
270
271 fn sendrecv<Fs, Fr>(
272 rsock: RawFd,
273 ssock: RawFd,
274 f_send: Fs,
275 mut f_recv: Fr,
276 ) -> Option<SockaddrStorage>
277 where
278 Fs: Fn(RawFd, &[u8], MsgFlags) -> Result<usize> + Send + 'static,
279 Fr: FnMut(usize, Option<SockaddrStorage>),
280 {
281 let mut buf: [u8; 13] = [0u8; 13];
282 let mut l = 0;
283 let mut from = None;
284
285 let send_thread = thread::spawn(move || {
286 let mut l = 0;
287 while l < std::mem::size_of_val(MSG) {
288 l += f_send(ssock, &MSG[l..], MsgFlags::empty()).unwrap();
289 }
290 });
291
292 while l < std::mem::size_of_val(MSG) {
293 let (len, from_) = recvfrom(rsock, &mut buf[l..]).unwrap();
294 f_recv(len, from_);
295 from = from_;
296 l += len;
297 }
298 assert_eq!(&buf, MSG);
299 send_thread.join().unwrap();
300 from
301 }
302
303 #[test]
304 pub fn stream() {
305 let (fd2, fd1) = socketpair(
306 AddressFamily::Unix,
307 SockType::Stream,
308 None,
309 SockFlag::empty(),
310 )
311 .unwrap();
312 // Ignore from for stream sockets
313 let _ = sendrecv(fd1.as_raw_fd(), fd2.as_raw_fd(), send, |_, _| {});
314 }
315
316 #[test]
317 pub fn udp() {
318 let std_sa = SocketAddrV4::from_str("127.0.0.1:6789").unwrap();
319 let sock_addr = SockaddrIn::from(std_sa);
320 let rsock = socket(
321 AddressFamily::Inet,
322 SockType::Datagram,
323 SockFlag::empty(),
324 None,
325 )
326 .unwrap();
327 bind(rsock.as_raw_fd(), &sock_addr).unwrap();
328 let ssock = socket(
329 AddressFamily::Inet,
330 SockType::Datagram,
331 SockFlag::empty(),
332 None,
333 )
334 .expect("send socket failed");
335 let from = sendrecv(
336 rsock.as_raw_fd(),
337 ssock.as_raw_fd(),
338 move |s, m, flags| sendto(s.as_raw_fd(), m, &sock_addr, flags),
339 |_, _| {},
340 );
341 // UDP sockets should set the from address
342 assert_eq!(AddressFamily::Inet, from.unwrap().family().unwrap());
343 }
344
345 #[cfg(target_os = "linux")]
346 mod udp_offload {
347 use super::*;
348 use nix::sys::socket::sockopt::{UdpGroSegment, UdpGsoSegment};
349 use std::io::IoSlice;
350
351 #[test]
352 // Disable the test under emulation because it fails in Cirrus-CI. Lack
353 // of QEMU support is suspected.
354 #[cfg_attr(qemu, ignore)]
355 pub fn gso() {
356 require_kernel_version!(udp_offload::gso, ">= 4.18");
357
358 // In this test, we send the data and provide a GSO segment size.
359 // Since we are sending the buffer of size 13, six UDP packets
360 // with size 2 and two UDP packet with size 1 will be sent.
361 let segment_size: u16 = 2;
362
363 let sock_addr = SockaddrIn::new(127, 0, 0, 1, 6791);
364 let rsock = socket(
365 AddressFamily::Inet,
366 SockType::Datagram,
367 SockFlag::empty(),
368 None,
369 )
370 .unwrap();
371
372 setsockopt(&rsock, UdpGsoSegment, &(segment_size as _))
373 .expect("setsockopt UDP_SEGMENT failed");
374
375 bind(rsock.as_raw_fd(), &sock_addr).unwrap();
376 let ssock = socket(
377 AddressFamily::Inet,
378 SockType::Datagram,
379 SockFlag::empty(),
380 None,
381 )
382 .expect("send socket failed");
383
384 let mut num_packets_received: i32 = 0;
385
386 sendrecv(
387 rsock.as_raw_fd(),
388 ssock.as_raw_fd(),
389 move |s, m, flags| {
390 let iov = [IoSlice::new(m)];
391 let cmsg = ControlMessage::UdpGsoSegments(&segment_size);
392 sendmsg(
393 s.as_raw_fd(),
394 &iov,
395 &[cmsg],
396 flags,
397 Some(&sock_addr),
398 )
399 },
400 {
401 let num_packets_received_ref = &mut num_packets_received;
402
403 move |len, _| {
404 // check that we receive UDP packets with payload size
405 // less or equal to segment size
406 assert!(len <= segment_size as usize);
407 *num_packets_received_ref += 1;
408 }
409 },
410 );
411
412 // Buffer size is 13, we will receive six packets of size 2,
413 // and one packet of size 1.
414 assert_eq!(7, num_packets_received);
415 }
416
417 #[test]
418 // Disable the test on emulated platforms because it fails in Cirrus-CI.
419 // Lack of QEMU support is suspected.
420 #[cfg_attr(qemu, ignore)]
421 pub fn gro() {
422 require_kernel_version!(udp_offload::gro, ">= 5.3");
423
424 // It's hard to guarantee receiving GRO packets. Just checking
425 // that `setsockopt` doesn't fail with error
426
427 let rsock = socket(
428 AddressFamily::Inet,
429 SockType::Datagram,
430 SockFlag::empty(),
431 None,
432 )
433 .unwrap();
434
435 setsockopt(&rsock, UdpGroSegment, &true)
436 .expect("setsockopt UDP_GRO failed");
437 }
438 }
439
440 #[cfg(any(
441 target_os = "linux",
442 target_os = "android",
443 target_os = "freebsd",
444 target_os = "netbsd",
445 ))]
446 #[test]
447 pub fn udp_sendmmsg() {
448 use std::io::IoSlice;
449
450 let std_sa = SocketAddrV4::from_str("127.0.0.1:6793").unwrap();
451 let std_sa2 = SocketAddrV4::from_str("127.0.0.1:6794").unwrap();
452 let sock_addr = SockaddrIn::from(std_sa);
453 let sock_addr2 = SockaddrIn::from(std_sa2);
454
455 let rsock = socket(
456 AddressFamily::Inet,
457 SockType::Datagram,
458 SockFlag::empty(),
459 None,
460 )
461 .unwrap();
462 bind(rsock.as_raw_fd(), &sock_addr).unwrap();
463 let ssock = socket(
464 AddressFamily::Inet,
465 SockType::Datagram,
466 SockFlag::empty(),
467 None,
468 )
469 .expect("send socket failed");
470
471 let from = sendrecv(
472 rsock.as_raw_fd(),
473 ssock.as_raw_fd(),
474 move |s, m, flags| {
475 let batch_size = 15;
476 let mut iovs = Vec::with_capacity(1 + batch_size);
477 let mut addrs = Vec::with_capacity(1 + batch_size);
478 let mut data = MultiHeaders::preallocate(1 + batch_size, None);
479 let iov = IoSlice::new(m);
480 // first chunk:
481 iovs.push([iov]);
482 addrs.push(Some(sock_addr));
483
484 for _ in 0..batch_size {
485 iovs.push([iov]);
486 addrs.push(Some(sock_addr2));
487 }
488
489 let res = sendmmsg(s, &mut data, &iovs, addrs, [], flags)?;
490 let mut sent_messages = 0;
491 let mut sent_bytes = 0;
492 for item in res {
493 sent_messages += 1;
494 sent_bytes += item.bytes;
495 }
496 //
497 assert_eq!(sent_messages, iovs.len());
498 assert_eq!(sent_bytes, sent_messages * m.len());
499 Ok(sent_messages)
500 },
501 |_, _| {},
502 );
503 // UDP sockets should set the from address
504 assert_eq!(AddressFamily::Inet, from.unwrap().family().unwrap());
505 }
506
507 #[cfg(any(
508 target_os = "linux",
509 target_os = "android",
510 target_os = "freebsd",
511 target_os = "netbsd",
512 ))]
513 #[test]
514 pub fn udp_recvmmsg() {
515 use nix::sys::socket::{recvmmsg, MsgFlags};
516 use std::io::IoSliceMut;
517
518 const NUM_MESSAGES_SENT: usize = 2;
519 const DATA: [u8; 2] = [1, 2];
520
521 let inet_addr = SocketAddrV4::from_str("127.0.0.1:6798").unwrap();
522 let sock_addr = SockaddrIn::from(inet_addr);
523
524 let rsock = socket(
525 AddressFamily::Inet,
526 SockType::Datagram,
527 SockFlag::empty(),
528 None,
529 )
530 .unwrap();
531 bind(rsock.as_raw_fd(), &sock_addr).unwrap();
532 let ssock = socket(
533 AddressFamily::Inet,
534 SockType::Datagram,
535 SockFlag::empty(),
536 None,
537 )
538 .expect("send socket failed");
539
540 let send_thread = thread::spawn(move || {
541 for _ in 0..NUM_MESSAGES_SENT {
542 sendto(
543 ssock.as_raw_fd(),
544 &DATA[..],
545 &sock_addr,
546 MsgFlags::empty(),
547 )
548 .unwrap();
549 }
550 });
551
552 let mut msgs = std::collections::LinkedList::new();
553
554 // Buffers to receive exactly `NUM_MESSAGES_SENT` messages
555 let mut receive_buffers = [[0u8; 32]; NUM_MESSAGES_SENT];
556 msgs.extend(
557 receive_buffers
558 .iter_mut()
559 .map(|buf| [IoSliceMut::new(&mut buf[..])]),
560 );
561
562 let mut data =
563 MultiHeaders::<SockaddrIn>::preallocate(msgs.len(), None);
564
565 let res: Vec<RecvMsg<SockaddrIn>> = recvmmsg(
566 rsock.as_raw_fd(),
567 &mut data,
568 msgs.iter(),
569 MsgFlags::empty(),
570 None,
571 )
572 .expect("recvmmsg")
573 .collect();
574 assert_eq!(res.len(), DATA.len());
575
576 for RecvMsg { address, bytes, .. } in res.into_iter() {
577 assert_eq!(AddressFamily::Inet, address.unwrap().family().unwrap());
578 assert_eq!(DATA.len(), bytes);
579 }
580
581 for buf in &receive_buffers {
582 assert_eq!(&buf[..DATA.len()], DATA);
583 }
584
585 send_thread.join().unwrap();
586 }
587
588 #[cfg(any(
589 target_os = "linux",
590 target_os = "android",
591 target_os = "freebsd",
592 target_os = "netbsd",
593 ))]
594 #[test]
595 pub fn udp_recvmmsg_dontwait_short_read() {
596 use nix::sys::socket::{recvmmsg, MsgFlags};
597 use std::io::IoSliceMut;
598
599 const NUM_MESSAGES_SENT: usize = 2;
600 const DATA: [u8; 4] = [1, 2, 3, 4];
601
602 let inet_addr = SocketAddrV4::from_str("127.0.0.1:6799").unwrap();
603 let sock_addr = SockaddrIn::from(inet_addr);
604
605 let rsock = socket(
606 AddressFamily::Inet,
607 SockType::Datagram,
608 SockFlag::empty(),
609 None,
610 )
611 .unwrap();
612 bind(rsock.as_raw_fd(), &sock_addr).unwrap();
613 let ssock = socket(
614 AddressFamily::Inet,
615 SockType::Datagram,
616 SockFlag::empty(),
617 None,
618 )
619 .expect("send socket failed");
620
621 let send_thread = thread::spawn(move || {
622 for _ in 0..NUM_MESSAGES_SENT {
623 sendto(
624 ssock.as_raw_fd(),
625 &DATA[..],
626 &sock_addr,
627 MsgFlags::empty(),
628 )
629 .unwrap();
630 }
631 });
632 // Ensure we've sent all the messages before continuing so `recvmmsg`
633 // will return right away
634 send_thread.join().unwrap();
635
636 let mut msgs = std::collections::LinkedList::new();
637
638 // Buffers to receive >`NUM_MESSAGES_SENT` messages to ensure `recvmmsg`
639 // will return when there are fewer than requested messages in the
640 // kernel buffers when using `MSG_DONTWAIT`.
641 let mut receive_buffers = [[0u8; 32]; NUM_MESSAGES_SENT + 2];
642 msgs.extend(
643 receive_buffers
644 .iter_mut()
645 .map(|buf| [IoSliceMut::new(&mut buf[..])]),
646 );
647
648 let mut data = MultiHeaders::<SockaddrIn>::preallocate(
649 NUM_MESSAGES_SENT + 2,
650 None,
651 );
652
653 let res: Vec<RecvMsg<SockaddrIn>> = recvmmsg(
654 rsock.as_raw_fd(),
655 &mut data,
656 msgs.iter(),
657 MsgFlags::MSG_DONTWAIT,
658 None,
659 )
660 .expect("recvmmsg")
661 .collect();
662 assert_eq!(res.len(), NUM_MESSAGES_SENT);
663
664 for RecvMsg { address, bytes, .. } in res.into_iter() {
665 assert_eq!(AddressFamily::Inet, address.unwrap().family().unwrap());
666 assert_eq!(DATA.len(), bytes);
667 }
668
669 for buf in &receive_buffers[..NUM_MESSAGES_SENT] {
670 assert_eq!(&buf[..DATA.len()], DATA);
671 }
672 }
673
674 #[test]
675 pub fn udp_inet6() {
676 let addr = std::net::Ipv6Addr::from_str("::1").unwrap();
677 let rport = 6789;
678 let rstd_sa = SocketAddrV6::new(addr, rport, 0, 0);
679 let raddr = SockaddrIn6::from(rstd_sa);
680 let sport = 6790;
681 let sstd_sa = SocketAddrV6::new(addr, sport, 0, 0);
682 let saddr = SockaddrIn6::from(sstd_sa);
683 let rsock = socket(
684 AddressFamily::Inet6,
685 SockType::Datagram,
686 SockFlag::empty(),
687 None,
688 )
689 .expect("receive socket failed");
690 match bind(rsock.as_raw_fd(), &raddr) {
691 Err(Errno::EADDRNOTAVAIL) => {
692 println!("IPv6 not available, skipping test.");
693 return;
694 }
695 Err(e) => panic!("bind: {e}"),
696 Ok(()) => (),
697 }
698 let ssock = socket(
699 AddressFamily::Inet6,
700 SockType::Datagram,
701 SockFlag::empty(),
702 None,
703 )
704 .expect("send socket failed");
705 bind(ssock.as_raw_fd(), &saddr).unwrap();
706 let from = sendrecv(
707 rsock.as_raw_fd(),
708 ssock.as_raw_fd(),
709 move |s, m, flags| sendto(s.as_raw_fd(), m, &raddr, flags),
710 |_, _| {},
711 );
712 assert_eq!(AddressFamily::Inet6, from.unwrap().family().unwrap());
713 let osent_addr = from.unwrap();
714 let sent_addr = osent_addr.as_sockaddr_in6().unwrap();
715 assert_eq!(sent_addr.ip(), addr);
716 assert_eq!(sent_addr.port(), sport);
717 }
718}
719
720// Test error handling of our recvmsg wrapper
721#[test]
722pub fn test_recvmsg_ebadf() {
723 use nix::errno::Errno;
724 use nix::sys::socket::{recvmsg, MsgFlags};
725 use std::io::IoSliceMut;
726
727 let mut buf = [0u8; 5];
728 let mut iov = [IoSliceMut::new(&mut buf[..])];
729
730 let fd = -1; // Bad file descriptor
731 let r = recvmsg::<()>(fd.as_raw_fd(), &mut iov, None, MsgFlags::empty());
732
733 assert_eq!(r.err().unwrap(), Errno::EBADF);
734}
735
736// Disable the test on emulated platforms due to a bug in QEMU versions <
737// 2.12.0. https://bugs.launchpad.net/qemu/+bug/1701808
738#[cfg_attr(qemu, ignore)]
739#[test]
740pub fn test_scm_rights() {
741 use nix::sys::socket::{
742 recvmsg, sendmsg, socketpair, AddressFamily, ControlMessage,
743 ControlMessageOwned, MsgFlags, SockFlag, SockType,
744 };
745 use nix::unistd::{close, pipe, read, write};
746 use std::io::{IoSlice, IoSliceMut};
747
748 let (fd1, fd2) = socketpair(
749 AddressFamily::Unix,
750 SockType::Stream,
751 None,
752 SockFlag::empty(),
753 )
754 .unwrap();
755 let (r, w) = pipe().unwrap();
756 let mut received_r: Option<RawFd> = None;
757
758 {
759 let iov = [IoSlice::new(b"hello")];
760 let fds = [r];
761 let cmsg = ControlMessage::ScmRights(&fds);
762 assert_eq!(
763 sendmsg::<()>(
764 fd1.as_raw_fd(),
765 &iov,
766 &[cmsg],
767 MsgFlags::empty(),
768 None
769 )
770 .unwrap(),
771 5
772 );
773 close(r).unwrap();
774 }
775
776 {
777 let mut buf = [0u8; 5];
778
779 let mut iov = [IoSliceMut::new(&mut buf[..])];
780 let mut cmsgspace = cmsg_space!([RawFd; 1]);
781 let msg = recvmsg::<()>(
782 fd2.as_raw_fd(),
783 &mut iov,
784 Some(&mut cmsgspace),
785 MsgFlags::empty(),
786 )
787 .unwrap();
788
789 for cmsg in msg.cmsgs() {
790 if let ControlMessageOwned::ScmRights(fd) = cmsg {
791 assert_eq!(received_r, None);
792 assert_eq!(fd.len(), 1);
793 received_r = Some(fd[0]);
794 } else {
795 panic!("unexpected cmsg");
796 }
797 }
798 assert_eq!(msg.bytes, 5);
799 assert!(!msg
800 .flags
801 .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
802 }
803
804 let received_r = received_r.expect("Did not receive passed fd");
805 // Ensure that the received file descriptor works
806 write(w.as_raw_fd(), b"world").unwrap();
807 let mut buf = [0u8; 5];
808 read(received_r.as_raw_fd(), &mut buf).unwrap();
809 assert_eq!(&buf[..], b"world");
810 close(received_r).unwrap();
811 close(w).unwrap();
812}
813
814// Disable the test on emulated platforms due to not enabled support of AF_ALG in QEMU from rust cross
815#[cfg(any(target_os = "linux", target_os = "android"))]
816#[cfg_attr(qemu, ignore)]
817#[test]
818pub fn test_af_alg_cipher() {
819 use nix::sys::socket::sockopt::AlgSetKey;
820 use nix::sys::socket::{
821 accept, bind, sendmsg, setsockopt, socket, AddressFamily, AlgAddr,
822 ControlMessage, MsgFlags, SockFlag, SockType,
823 };
824 use nix::unistd::read;
825 use std::io::IoSlice;
826
827 skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1352");
828 // Travis's seccomp profile blocks AF_ALG
829 // https://docs.docker.com/engine/security/seccomp/
830 skip_if_seccomp!(test_af_alg_cipher);
831
832 let alg_type = "skcipher";
833 let alg_name = "ctr-aes-aesni";
834 // 256-bits secret key
835 let key = vec![0u8; 32];
836 // 16-bytes IV
837 let iv_len = 16;
838 let iv = vec![1u8; iv_len];
839 // 256-bytes plain payload
840 let payload_len = 256;
841 let payload = vec![2u8; payload_len];
842
843 let sock = socket(
844 AddressFamily::Alg,
845 SockType::SeqPacket,
846 SockFlag::empty(),
847 None,
848 )
849 .expect("socket failed");
850
851 let sockaddr = AlgAddr::new(alg_type, alg_name);
852 bind(sock.as_raw_fd(), &sockaddr).expect("bind failed");
853
854 assert_eq!(sockaddr.alg_name().to_string_lossy(), alg_name);
855 assert_eq!(sockaddr.alg_type().to_string_lossy(), alg_type);
856
857 setsockopt(&sock, AlgSetKey::default(), &key).expect("setsockopt");
858 let session_socket = accept(sock.as_raw_fd()).expect("accept failed");
859
860 let msgs = [
861 ControlMessage::AlgSetOp(&libc::ALG_OP_ENCRYPT),
862 ControlMessage::AlgSetIv(iv.as_slice()),
863 ];
864 let iov = IoSlice::new(&payload);
865 sendmsg::<()>(
866 session_socket.as_raw_fd(),
867 &[iov],
868 &msgs,
869 MsgFlags::empty(),
870 None,
871 )
872 .expect("sendmsg encrypt");
873
874 // allocate buffer for encrypted data
875 let mut encrypted = vec![0u8; payload_len];
876 let num_bytes =
877 read(session_socket.as_raw_fd(), &mut encrypted).expect("read encrypt");
878 assert_eq!(num_bytes, payload_len);
879
880 let iov = IoSlice::new(&encrypted);
881
882 let iv = vec![1u8; iv_len];
883
884 let msgs = [
885 ControlMessage::AlgSetOp(&libc::ALG_OP_DECRYPT),
886 ControlMessage::AlgSetIv(iv.as_slice()),
887 ];
888 sendmsg::<()>(
889 session_socket.as_raw_fd(),
890 &[iov],
891 &msgs,
892 MsgFlags::empty(),
893 None,
894 )
895 .expect("sendmsg decrypt");
896
897 // allocate buffer for decrypted data
898 let mut decrypted = vec![0u8; payload_len];
899 let num_bytes =
900 read(session_socket.as_raw_fd(), &mut decrypted).expect("read decrypt");
901
902 assert_eq!(num_bytes, payload_len);
903 assert_eq!(decrypted, payload);
904}
905
906// Disable the test on emulated platforms due to not enabled support of AF_ALG
907// in QEMU from rust cross
908#[cfg(any(target_os = "linux", target_os = "android"))]
909#[cfg_attr(qemu, ignore)]
910#[test]
911pub fn test_af_alg_aead() {
912 use libc::{ALG_OP_DECRYPT, ALG_OP_ENCRYPT};
913 use nix::fcntl::{fcntl, FcntlArg, OFlag};
914 use nix::sys::socket::sockopt::{AlgSetAeadAuthSize, AlgSetKey};
915 use nix::sys::socket::{
916 accept, bind, sendmsg, setsockopt, socket, AddressFamily, AlgAddr,
917 ControlMessage, MsgFlags, SockFlag, SockType,
918 };
919 use nix::unistd::read;
920 use std::io::IoSlice;
921
922 skip_if_cirrus!("Fails for an unknown reason Cirrus CI. Bug #1352");
923 // Travis's seccomp profile blocks AF_ALG
924 // https://docs.docker.com/engine/security/seccomp/
925 skip_if_seccomp!(test_af_alg_aead);
926
927 let auth_size = 4usize;
928 let assoc_size = 16u32;
929
930 let alg_type = "aead";
931 let alg_name = "gcm(aes)";
932 // 256-bits secret key
933 let key = vec![0u8; 32];
934 // 12-bytes IV
935 let iv_len = 12;
936 let iv = vec![1u8; iv_len];
937 // 256-bytes plain payload
938 let payload_len = 256;
939 let mut payload =
940 vec![2u8; payload_len + (assoc_size as usize) + auth_size];
941
942 for i in 0..assoc_size {
943 payload[i as usize] = 10;
944 }
945
946 let len = payload.len();
947
948 for i in 0..auth_size {
949 payload[len - 1 - i] = 0;
950 }
951
952 let sock = socket(
953 AddressFamily::Alg,
954 SockType::SeqPacket,
955 SockFlag::empty(),
956 None,
957 )
958 .expect("socket failed");
959
960 let sockaddr = AlgAddr::new(alg_type, alg_name);
961 bind(sock.as_raw_fd(), &sockaddr).expect("bind failed");
962
963 setsockopt(&sock, AlgSetAeadAuthSize, &auth_size)
964 .expect("setsockopt AlgSetAeadAuthSize");
965 setsockopt(&sock, AlgSetKey::default(), &key)
966 .expect("setsockopt AlgSetKey");
967 let session_socket = accept(sock.as_raw_fd()).expect("accept failed");
968
969 let msgs = [
970 ControlMessage::AlgSetOp(&ALG_OP_ENCRYPT),
971 ControlMessage::AlgSetIv(iv.as_slice()),
972 ControlMessage::AlgSetAeadAssoclen(&assoc_size),
973 ];
974
975 let iov = IoSlice::new(&payload);
976 sendmsg::<()>(
977 session_socket.as_raw_fd(),
978 &[iov],
979 &msgs,
980 MsgFlags::empty(),
981 None,
982 )
983 .expect("sendmsg encrypt");
984
985 // allocate buffer for encrypted data
986 let mut encrypted =
987 vec![0u8; (assoc_size as usize) + payload_len + auth_size];
988 let num_bytes =
989 read(session_socket.as_raw_fd(), &mut encrypted).expect("read encrypt");
990 assert_eq!(num_bytes, payload_len + auth_size + (assoc_size as usize));
991
992 for i in 0..assoc_size {
993 encrypted[i as usize] = 10;
994 }
995
996 let iov = IoSlice::new(&encrypted);
997
998 let iv = vec![1u8; iv_len];
999
1000 let session_socket = accept(sock.as_raw_fd()).expect("accept failed");
1001
1002 let msgs = [
1003 ControlMessage::AlgSetOp(&ALG_OP_DECRYPT),
1004 ControlMessage::AlgSetIv(iv.as_slice()),
1005 ControlMessage::AlgSetAeadAssoclen(&assoc_size),
1006 ];
1007 sendmsg::<()>(
1008 session_socket.as_raw_fd(),
1009 &[iov],
1010 &msgs,
1011 MsgFlags::empty(),
1012 None,
1013 )
1014 .expect("sendmsg decrypt");
1015
1016 // allocate buffer for decrypted data
1017 let mut decrypted =
1018 vec![0u8; payload_len + (assoc_size as usize) + auth_size];
1019 // Starting with kernel 4.9, the interface changed slightly such that the
1020 // authentication tag memory is only needed in the output buffer for encryption
1021 // and in the input buffer for decryption.
1022 // Do not block on read, as we may have fewer bytes than buffer size
1023 fcntl(session_socket, FcntlArg::F_SETFL(OFlag::O_NONBLOCK))
1024 .expect("fcntl non_blocking");
1025 let num_bytes =
1026 read(session_socket.as_raw_fd(), &mut decrypted).expect("read decrypt");
1027
1028 assert!(num_bytes >= payload_len + (assoc_size as usize));
1029 assert_eq!(
1030 decrypted[(assoc_size as usize)..(payload_len + (assoc_size as usize))],
1031 payload[(assoc_size as usize)..payload_len + (assoc_size as usize)]
1032 );
1033}
1034
1035// Verify `ControlMessage::Ipv4PacketInfo` for `sendmsg`.
1036// This creates a (udp) socket bound to localhost, then sends a message to
1037// itself but uses Ipv4PacketInfo to force the source address to be localhost.
1038//
1039// This would be a more interesting test if we could assume that the test host
1040// has more than one IP address (since we could select a different address to
1041// test from).
1042#[cfg(any(target_os = "linux", target_os = "macos", target_os = "netbsd"))]
1043#[test]
1044pub fn test_sendmsg_ipv4packetinfo() {
1045 use cfg_if::cfg_if;
1046 use nix::sys::socket::{
1047 bind, sendmsg, socket, AddressFamily, ControlMessage, MsgFlags,
1048 SockFlag, SockType, SockaddrIn,
1049 };
1050 use std::io::IoSlice;
1051
1052 let sock = socket(
1053 AddressFamily::Inet,
1054 SockType::Datagram,
1055 SockFlag::empty(),
1056 None,
1057 )
1058 .expect("socket failed");
1059
1060 let sock_addr = SockaddrIn::new(127, 0, 0, 1, 4000);
1061
1062 bind(sock.as_raw_fd(), &sock_addr).expect("bind failed");
1063
1064 let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
1065 let iov = [IoSlice::new(&slice)];
1066
1067 cfg_if! {
1068 if #[cfg(target_os = "netbsd")] {
1069 let pi = libc::in_pktinfo {
1070 ipi_ifindex: 0, /* Unspecified interface */
1071 ipi_addr: libc::in_addr { s_addr: 0 },
1072 };
1073 } else {
1074 let pi = libc::in_pktinfo {
1075 ipi_ifindex: 0, /* Unspecified interface */
1076 ipi_addr: libc::in_addr { s_addr: 0 },
1077 ipi_spec_dst: sock_addr.as_ref().sin_addr,
1078 };
1079 }
1080 }
1081
1082 let cmsg = [ControlMessage::Ipv4PacketInfo(&pi)];
1083
1084 sendmsg(
1085 sock.as_raw_fd(),
1086 &iov,
1087 &cmsg,
1088 MsgFlags::empty(),
1089 Some(&sock_addr),
1090 )
1091 .expect("sendmsg");
1092}
1093
1094// Verify `ControlMessage::Ipv6PacketInfo` for `sendmsg`.
1095// This creates a (udp) socket bound to ip6-localhost, then sends a message to
1096// itself but uses Ipv6PacketInfo to force the source address to be
1097// ip6-localhost.
1098//
1099// This would be a more interesting test if we could assume that the test host
1100// has more than one IP address (since we could select a different address to
1101// test from).
1102#[cfg(any(
1103 target_os = "linux",
1104 target_os = "macos",
1105 target_os = "netbsd",
1106 target_os = "freebsd"
1107))]
1108#[test]
1109pub fn test_sendmsg_ipv6packetinfo() {
1110 use nix::errno::Errno;
1111 use nix::sys::socket::{
1112 bind, sendmsg, socket, AddressFamily, ControlMessage, MsgFlags,
1113 SockFlag, SockType, SockaddrIn6,
1114 };
1115 use std::io::IoSlice;
1116
1117 let sock = socket(
1118 AddressFamily::Inet6,
1119 SockType::Datagram,
1120 SockFlag::empty(),
1121 None,
1122 )
1123 .expect("socket failed");
1124
1125 let std_sa = SocketAddrV6::from_str("[::1]:6000").unwrap();
1126 let sock_addr: SockaddrIn6 = SockaddrIn6::from(std_sa);
1127
1128 if let Err(Errno::EADDRNOTAVAIL) = bind(sock.as_raw_fd(), &sock_addr) {
1129 println!("IPv6 not available, skipping test.");
1130 return;
1131 }
1132
1133 let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
1134 let iov = [IoSlice::new(&slice)];
1135
1136 let pi = libc::in6_pktinfo {
1137 ipi6_ifindex: 0, /* Unspecified interface */
1138 ipi6_addr: sock_addr.as_ref().sin6_addr,
1139 };
1140
1141 let cmsg = [ControlMessage::Ipv6PacketInfo(&pi)];
1142
1143 sendmsg::<SockaddrIn6>(
1144 sock.as_raw_fd(),
1145 &iov,
1146 &cmsg,
1147 MsgFlags::empty(),
1148 Some(&sock_addr),
1149 )
1150 .expect("sendmsg");
1151}
1152
1153// Verify that ControlMessage::Ipv4SendSrcAddr works for sendmsg. This
1154// creates a UDP socket bound to all local interfaces (0.0.0.0). It then
1155// sends message to itself at 127.0.0.1 while explicitly specifying
1156// 127.0.0.1 as the source address through an Ipv4SendSrcAddr
1157// (IP_SENDSRCADDR) control message.
1158//
1159// Note that binding to 0.0.0.0 is *required* on FreeBSD; sendmsg
1160// returns EINVAL otherwise. (See FreeBSD's ip(4) man page.)
1161#[cfg(any(
1162 target_os = "netbsd",
1163 target_os = "freebsd",
1164 target_os = "openbsd",
1165 target_os = "dragonfly",
1166))]
1167#[test]
1168pub fn test_sendmsg_ipv4sendsrcaddr() {
1169 use nix::sys::socket::{
1170 bind, sendmsg, socket, AddressFamily, ControlMessage, MsgFlags,
1171 SockFlag, SockType, SockaddrIn,
1172 };
1173 use std::io::IoSlice;
1174
1175 let sock = socket(
1176 AddressFamily::Inet,
1177 SockType::Datagram,
1178 SockFlag::empty(),
1179 None,
1180 )
1181 .expect("socket failed");
1182
1183 let unspec_sock_addr = SockaddrIn::new(0, 0, 0, 0, 0);
1184 bind(sock.as_raw_fd(), &unspec_sock_addr).expect("bind failed");
1185 let bound_sock_addr: SockaddrIn = getsockname(sock.as_raw_fd()).unwrap();
1186 let localhost_sock_addr: SockaddrIn =
1187 SockaddrIn::new(127, 0, 0, 1, bound_sock_addr.port());
1188
1189 let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
1190 let iov = [IoSlice::new(&slice)];
1191 let cmsg = [ControlMessage::Ipv4SendSrcAddr(
1192 &localhost_sock_addr.as_ref().sin_addr,
1193 )];
1194
1195 sendmsg(
1196 sock.as_raw_fd(),
1197 &iov,
1198 &cmsg,
1199 MsgFlags::empty(),
1200 Some(&localhost_sock_addr),
1201 )
1202 .expect("sendmsg");
1203}
1204
1205/// Tests that passing multiple fds using a single `ControlMessage` works.
1206// Disable the test on emulated platforms due to a bug in QEMU versions <
1207// 2.12.0. https://bugs.launchpad.net/qemu/+bug/1701808
1208#[cfg_attr(qemu, ignore)]
1209#[test]
1210fn test_scm_rights_single_cmsg_multiple_fds() {
1211 use nix::sys::socket::{
1212 recvmsg, sendmsg, ControlMessage, ControlMessageOwned, MsgFlags,
1213 };
1214 use std::io::{IoSlice, IoSliceMut};
1215 use std::os::unix::io::{AsRawFd, RawFd};
1216 use std::os::unix::net::UnixDatagram;
1217 use std::thread;
1218
1219 let (send, receive) = UnixDatagram::pair().unwrap();
1220 let thread = thread::spawn(move || {
1221 let mut buf = [0u8; 8];
1222 let mut iovec = [IoSliceMut::new(&mut buf)];
1223
1224 let mut space = cmsg_space!([RawFd; 2]);
1225 let msg = recvmsg::<()>(
1226 receive.as_raw_fd(),
1227 &mut iovec,
1228 Some(&mut space),
1229 MsgFlags::empty(),
1230 )
1231 .unwrap();
1232 assert!(!msg
1233 .flags
1234 .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
1235
1236 let mut cmsgs = msg.cmsgs();
1237 match cmsgs.next() {
1238 Some(ControlMessageOwned::ScmRights(fds)) => {
1239 assert_eq!(
1240 fds.len(),
1241 2,
1242 "unexpected fd count (expected 2 fds, got {})",
1243 fds.len()
1244 );
1245 }
1246 _ => panic!(),
1247 }
1248 assert!(cmsgs.next().is_none(), "unexpected control msg");
1249
1250 assert_eq!(msg.bytes, 8);
1251 assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]);
1252 });
1253
1254 let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
1255 let iov = [IoSlice::new(&slice)];
1256 let fds = [libc::STDIN_FILENO, libc::STDOUT_FILENO]; // pass stdin and stdout
1257 let cmsg = [ControlMessage::ScmRights(&fds)];
1258 sendmsg::<()>(send.as_raw_fd(), &iov, &cmsg, MsgFlags::empty(), None)
1259 .unwrap();
1260 thread.join().unwrap();
1261}
1262
1263// Verify `sendmsg` builds a valid `msghdr` when passing an empty
1264// `cmsgs` argument. This should result in a msghdr with a nullptr
1265// msg_control field and a msg_controllen of 0 when calling into the
1266// raw `sendmsg`.
1267#[test]
1268pub fn test_sendmsg_empty_cmsgs() {
1269 use nix::sys::socket::{
1270 recvmsg, sendmsg, socketpair, AddressFamily, MsgFlags, SockFlag,
1271 SockType,
1272 };
1273 use std::io::{IoSlice, IoSliceMut};
1274
1275 let (fd1, fd2) = socketpair(
1276 AddressFamily::Unix,
1277 SockType::Stream,
1278 None,
1279 SockFlag::empty(),
1280 )
1281 .unwrap();
1282
1283 {
1284 let iov = [IoSlice::new(b"hello")];
1285 assert_eq!(
1286 sendmsg::<()>(fd1.as_raw_fd(), &iov, &[], MsgFlags::empty(), None)
1287 .unwrap(),
1288 5
1289 );
1290 }
1291
1292 {
1293 let mut buf = [0u8; 5];
1294 let mut iov = [IoSliceMut::new(&mut buf[..])];
1295
1296 let mut cmsgspace = cmsg_space!([RawFd; 1]);
1297 let msg = recvmsg::<()>(
1298 fd2.as_raw_fd(),
1299 &mut iov,
1300 Some(&mut cmsgspace),
1301 MsgFlags::empty(),
1302 )
1303 .unwrap();
1304
1305 for _ in msg.cmsgs() {
1306 panic!("unexpected cmsg");
1307 }
1308 assert!(!msg
1309 .flags
1310 .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
1311 assert_eq!(msg.bytes, 5);
1312 }
1313}
1314
1315#[cfg(any(
1316 target_os = "android",
1317 target_os = "linux",
1318 target_os = "freebsd",
1319 target_os = "dragonfly",
1320))]
1321#[test]
1322fn test_scm_credentials() {
1323 use nix::sys::socket::{
1324 recvmsg, sendmsg, socketpair, AddressFamily, ControlMessage,
1325 ControlMessageOwned, MsgFlags, SockFlag, SockType, UnixCredentials,
1326 };
1327 #[cfg(any(target_os = "android", target_os = "linux"))]
1328 use nix::sys::socket::{setsockopt, sockopt::PassCred};
1329 use nix::unistd::{getgid, getpid, getuid};
1330 use std::io::{IoSlice, IoSliceMut};
1331
1332 let (send, recv) = socketpair(
1333 AddressFamily::Unix,
1334 SockType::Stream,
1335 None,
1336 SockFlag::empty(),
1337 )
1338 .unwrap();
1339 #[cfg(any(target_os = "android", target_os = "linux"))]
1340 setsockopt(&recv, PassCred, &true).unwrap();
1341
1342 {
1343 let iov = [IoSlice::new(b"hello")];
1344 #[cfg(any(target_os = "android", target_os = "linux"))]
1345 let cred = UnixCredentials::new();
1346 #[cfg(any(target_os = "android", target_os = "linux"))]
1347 let cmsg = ControlMessage::ScmCredentials(&cred);
1348 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
1349 let cmsg = ControlMessage::ScmCreds;
1350 assert_eq!(
1351 sendmsg::<()>(
1352 send.as_raw_fd(),
1353 &iov,
1354 &[cmsg],
1355 MsgFlags::empty(),
1356 None
1357 )
1358 .unwrap(),
1359 5
1360 );
1361 }
1362
1363 {
1364 let mut buf = [0u8; 5];
1365 let mut iov = [IoSliceMut::new(&mut buf[..])];
1366
1367 let mut cmsgspace = cmsg_space!(UnixCredentials);
1368 let msg = recvmsg::<()>(
1369 recv.as_raw_fd(),
1370 &mut iov,
1371 Some(&mut cmsgspace),
1372 MsgFlags::empty(),
1373 )
1374 .unwrap();
1375 let mut received_cred = None;
1376
1377 for cmsg in msg.cmsgs() {
1378 let cred = match cmsg {
1379 #[cfg(any(target_os = "android", target_os = "linux"))]
1380 ControlMessageOwned::ScmCredentials(cred) => cred,
1381 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
1382 ControlMessageOwned::ScmCreds(cred) => cred,
1383 other => panic!("unexpected cmsg {other:?}"),
1384 };
1385 assert!(received_cred.is_none());
1386 assert_eq!(cred.pid(), getpid().as_raw());
1387 assert_eq!(cred.uid(), getuid().as_raw());
1388 assert_eq!(cred.gid(), getgid().as_raw());
1389 received_cred = Some(cred);
1390 }
1391 received_cred.expect("no creds received");
1392 assert_eq!(msg.bytes, 5);
1393 assert!(!msg
1394 .flags
1395 .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
1396 }
1397}
1398
1399/// Ensure that we can send `SCM_CREDENTIALS` and `SCM_RIGHTS` with a single
1400/// `sendmsg` call.
1401#[cfg(any(target_os = "android", target_os = "linux"))]
1402// qemu's handling of multiple cmsgs is bugged, ignore tests under emulation
1403// see https://bugs.launchpad.net/qemu/+bug/1781280
1404#[cfg_attr(qemu, ignore)]
1405#[test]
1406fn test_scm_credentials_and_rights() {
1407 let space = cmsg_space!(libc::ucred, RawFd);
1408 test_impl_scm_credentials_and_rights(space);
1409}
1410
1411/// Ensure that passing a an oversized control message buffer to recvmsg
1412/// still works.
1413#[cfg(any(target_os = "android", target_os = "linux"))]
1414// qemu's handling of multiple cmsgs is bugged, ignore tests under emulation
1415// see https://bugs.launchpad.net/qemu/+bug/1781280
1416#[cfg_attr(qemu, ignore)]
1417#[test]
1418fn test_too_large_cmsgspace() {
1419 let space = vec![0u8; 1024];
1420 test_impl_scm_credentials_and_rights(space);
1421}
1422
1423#[cfg(any(target_os = "android", target_os = "linux"))]
1424fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) {
1425 use libc::ucred;
1426 use nix::sys::socket::sockopt::PassCred;
1427 use nix::sys::socket::{
1428 recvmsg, sendmsg, setsockopt, socketpair, ControlMessage,
1429 ControlMessageOwned, MsgFlags, SockFlag, SockType,
1430 };
1431 use nix::unistd::{close, getgid, getpid, getuid, pipe, write};
1432 use std::io::{IoSlice, IoSliceMut};
1433
1434 let (send, recv) = socketpair(
1435 AddressFamily::Unix,
1436 SockType::Stream,
1437 None,
1438 SockFlag::empty(),
1439 )
1440 .unwrap();
1441 setsockopt(&recv, PassCred, &true).unwrap();
1442
1443 let (r, w) = pipe().unwrap();
1444 let mut received_r: Option<RawFd> = None;
1445
1446 {
1447 let iov = [IoSlice::new(b"hello")];
1448 let cred = ucred {
1449 pid: getpid().as_raw(),
1450 uid: getuid().as_raw(),
1451 gid: getgid().as_raw(),
1452 }
1453 .into();
1454 let fds = [r];
1455 let cmsgs = [
1456 ControlMessage::ScmCredentials(&cred),
1457 ControlMessage::ScmRights(&fds),
1458 ];
1459 assert_eq!(
1460 sendmsg::<()>(
1461 send.as_raw_fd(),
1462 &iov,
1463 &cmsgs,
1464 MsgFlags::empty(),
1465 None
1466 )
1467 .unwrap(),
1468 5
1469 );
1470 close(r).unwrap();
1471 }
1472
1473 {
1474 let mut buf = [0u8; 5];
1475 let mut iov = [IoSliceMut::new(&mut buf[..])];
1476 let msg = recvmsg::<()>(
1477 recv.as_raw_fd(),
1478 &mut iov,
1479 Some(&mut space),
1480 MsgFlags::empty(),
1481 )
1482 .unwrap();
1483 let mut received_cred = None;
1484
1485 assert_eq!(msg.cmsgs().count(), 2, "expected 2 cmsgs");
1486
1487 for cmsg in msg.cmsgs() {
1488 match cmsg {
1489 ControlMessageOwned::ScmRights(fds) => {
1490 assert_eq!(received_r, None, "already received fd");
1491 assert_eq!(fds.len(), 1);
1492 received_r = Some(fds[0]);
1493 }
1494 ControlMessageOwned::ScmCredentials(cred) => {
1495 assert!(received_cred.is_none());
1496 assert_eq!(cred.pid(), getpid().as_raw());
1497 assert_eq!(cred.uid(), getuid().as_raw());
1498 assert_eq!(cred.gid(), getgid().as_raw());
1499 received_cred = Some(cred);
1500 }
1501 _ => panic!("unexpected cmsg"),
1502 }
1503 }
1504 received_cred.expect("no creds received");
1505 assert_eq!(msg.bytes, 5);
1506 assert!(!msg
1507 .flags
1508 .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
1509 }
1510
1511 let received_r = received_r.expect("Did not receive passed fd");
1512 // Ensure that the received file descriptor works
1513 write(w.as_raw_fd(), b"world").unwrap();
1514 let mut buf = [0u8; 5];
1515 read(received_r.as_raw_fd(), &mut buf).unwrap();
1516 assert_eq!(&buf[..], b"world");
1517 close(received_r).unwrap();
1518 close(w).unwrap();
1519}
1520
1521// Test creating and using named unix domain sockets
1522#[test]
1523pub fn test_named_unixdomain() {
1524 use nix::sys::socket::{accept, bind, connect, listen, socket, UnixAddr};
1525 use nix::sys::socket::{SockFlag, SockType};
1526 use nix::unistd::{read, write};
1527 use std::thread;
1528
1529 let tempdir = tempfile::tempdir().unwrap();
1530 let sockname = tempdir.path().join("sock");
1531 let s1 = socket(
1532 AddressFamily::Unix,
1533 SockType::Stream,
1534 SockFlag::empty(),
1535 None,
1536 )
1537 .expect("socket failed");
1538 let sockaddr = UnixAddr::new(&sockname).unwrap();
1539 bind(s1.as_raw_fd(), &sockaddr).expect("bind failed");
1540 listen(&s1, 10).expect("listen failed");
1541
1542 let thr = thread::spawn(move || {
1543 let s2 = socket(
1544 AddressFamily::Unix,
1545 SockType::Stream,
1546 SockFlag::empty(),
1547 None,
1548 )
1549 .expect("socket failed");
1550 connect(s2.as_raw_fd(), &sockaddr).expect("connect failed");
1551 write(s2.as_raw_fd(), b"hello").expect("write failed");
1552 });
1553
1554 let s3 = accept(s1.as_raw_fd()).expect("accept failed");
1555
1556 let mut buf = [0; 5];
1557 read(s3.as_raw_fd(), &mut buf).unwrap();
1558 thr.join().unwrap();
1559
1560 assert_eq!(&buf[..], b"hello");
1561}
1562
1563// Test using unnamed unix domain addresses
1564#[cfg(any(target_os = "android", target_os = "linux"))]
1565#[test]
1566pub fn test_unnamed_unixdomain() {
1567 use nix::sys::socket::{getsockname, socketpair};
1568 use nix::sys::socket::{SockFlag, SockType};
1569
1570 let (fd_1, _fd_2) = socketpair(
1571 AddressFamily::Unix,
1572 SockType::Stream,
1573 None,
1574 SockFlag::empty(),
1575 )
1576 .expect("socketpair failed");
1577
1578 let addr_1: UnixAddr =
1579 getsockname(fd_1.as_raw_fd()).expect("getsockname failed");
1580 assert!(addr_1.is_unnamed());
1581}
1582
1583// Test creating and using unnamed unix domain addresses for autobinding sockets
1584#[cfg(any(target_os = "android", target_os = "linux"))]
1585#[test]
1586pub fn test_unnamed_unixdomain_autobind() {
1587 use nix::sys::socket::{bind, getsockname, socket};
1588 use nix::sys::socket::{SockFlag, SockType};
1589
1590 let fd = socket(
1591 AddressFamily::Unix,
1592 SockType::Stream,
1593 SockFlag::empty(),
1594 None,
1595 )
1596 .expect("socket failed");
1597
1598 // unix(7): "If a bind(2) call specifies addrlen as `sizeof(sa_family_t)`, or [...], then the
1599 // socket is autobound to an abstract address"
1600 bind(fd.as_raw_fd(), &UnixAddr::new_unnamed()).expect("bind failed");
1601
1602 let addr: UnixAddr =
1603 getsockname(fd.as_raw_fd()).expect("getsockname failed");
1604 let addr = addr.as_abstract().unwrap();
1605
1606 // changed from 8 to 5 bytes in Linux 2.3.15, and rust's minimum supported Linux version is 3.2
1607 // (as of 2022-11)
1608 assert_eq!(addr.len(), 5);
1609}
1610
1611// Test creating and using named system control sockets
1612#[cfg(any(target_os = "macos", target_os = "ios"))]
1613#[test]
1614pub fn test_syscontrol() {
1615 use nix::errno::Errno;
1616 use nix::sys::socket::{
1617 socket, SockFlag, SockProtocol, SockType, SysControlAddr,
1618 };
1619
1620 let fd = socket(
1621 AddressFamily::System,
1622 SockType::Datagram,
1623 SockFlag::empty(),
1624 SockProtocol::KextControl,
1625 )
1626 .expect("socket failed");
1627 SysControlAddr::from_name(fd.as_raw_fd(), "com.apple.net.utun_control", 0)
1628 .expect("resolving sys_control name failed");
1629 assert_eq!(
1630 SysControlAddr::from_name(fd.as_raw_fd(), "foo.bar.lol", 0).err(),
1631 Some(Errno::ENOENT)
1632 );
1633
1634 // requires root privileges
1635 // connect(fd.as_raw_fd(), &sockaddr).expect("connect failed");
1636}
1637
1638#[cfg(any(
1639 target_os = "android",
1640 target_os = "freebsd",
1641 target_os = "ios",
1642 target_os = "linux",
1643 target_os = "macos",
1644 target_os = "netbsd",
1645 target_os = "openbsd",
1646))]
1647fn loopback_address(
1648 family: AddressFamily,
1649) -> Option<nix::ifaddrs::InterfaceAddress> {
1650 use nix::ifaddrs::getifaddrs;
1651 use nix::net::if_::*;
1652 use nix::sys::socket::SockaddrLike;
1653 use std::io;
1654 use std::io::Write;
1655
1656 let mut addrs = match getifaddrs() {
1657 Ok(iter) => iter,
1658 Err(e) => {
1659 let stdioerr = io::stderr();
1660 let mut handle = stdioerr.lock();
1661 writeln!(handle, "getifaddrs: {e:?}").unwrap();
1662 return None;
1663 }
1664 };
1665 // return first address matching family
1666 addrs.find(|ifaddr| {
1667 ifaddr.flags.contains(InterfaceFlags::IFF_LOOPBACK)
1668 && ifaddr.address.as_ref().and_then(SockaddrLike::family)
1669 == Some(family)
1670 })
1671}
1672
1673#[cfg(any(
1674 target_os = "android",
1675 target_os = "ios",
1676 target_os = "linux",
1677 target_os = "macos",
1678 target_os = "netbsd",
1679))]
1680// qemu doesn't seem to be emulating this correctly in these architectures
1681#[cfg_attr(
1682 all(
1683 qemu,
1684 any(
1685 target_arch = "mips",
1686 target_arch = "mips64",
1687 target_arch = "powerpc64",
1688 )
1689 ),
1690 ignore
1691)]
1692#[test]
1693pub fn test_recv_ipv4pktinfo() {
1694 use nix::net::if_::*;
1695 use nix::sys::socket::sockopt::Ipv4PacketInfo;
1696 use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn};
1697 use nix::sys::socket::{getsockname, setsockopt, socket};
1698 use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags};
1699 use std::io::{IoSlice, IoSliceMut};
1700
1701 let lo_ifaddr = loopback_address(AddressFamily::Inet);
1702 let (lo_name, lo) = match lo_ifaddr {
1703 Some(ifaddr) => (
1704 ifaddr.interface_name,
1705 ifaddr.address.expect("Expect IPv4 address on interface"),
1706 ),
1707 None => return,
1708 };
1709 let receive = socket(
1710 AddressFamily::Inet,
1711 SockType::Datagram,
1712 SockFlag::empty(),
1713 None,
1714 )
1715 .expect("receive socket failed");
1716 bind(receive.as_raw_fd(), &lo).expect("bind failed");
1717 let sa: SockaddrIn =
1718 getsockname(receive.as_raw_fd()).expect("getsockname failed");
1719 setsockopt(&receive, Ipv4PacketInfo, &true).expect("setsockopt failed");
1720
1721 {
1722 let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
1723 let iov = [IoSlice::new(&slice)];
1724
1725 let send = socket(
1726 AddressFamily::Inet,
1727 SockType::Datagram,
1728 SockFlag::empty(),
1729 None,
1730 )
1731 .expect("send socket failed");
1732 sendmsg(send.as_raw_fd(), &iov, &[], MsgFlags::empty(), Some(&sa))
1733 .expect("sendmsg failed");
1734 }
1735
1736 {
1737 let mut buf = [0u8; 8];
1738 let mut iovec = [IoSliceMut::new(&mut buf)];
1739
1740 let mut space = cmsg_space!(libc::in_pktinfo);
1741 let msg = recvmsg::<()>(
1742 receive.as_raw_fd(),
1743 &mut iovec,
1744 Some(&mut space),
1745 MsgFlags::empty(),
1746 )
1747 .expect("recvmsg failed");
1748 assert!(!msg
1749 .flags
1750 .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
1751
1752 let mut cmsgs = msg.cmsgs();
1753 if let Some(ControlMessageOwned::Ipv4PacketInfo(pktinfo)) = cmsgs.next()
1754 {
1755 let i = if_nametoindex(lo_name.as_bytes()).expect("if_nametoindex");
1756 assert_eq!(
1757 pktinfo.ipi_ifindex as libc::c_uint, i,
1758 "unexpected ifindex (expected {}, got {})",
1759 i, pktinfo.ipi_ifindex
1760 );
1761 }
1762 assert!(cmsgs.next().is_none(), "unexpected additional control msg");
1763 assert_eq!(msg.bytes, 8);
1764 assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]);
1765 }
1766}
1767
1768#[cfg(any(
1769 target_os = "freebsd",
1770 target_os = "ios",
1771 target_os = "macos",
1772 target_os = "netbsd",
1773 target_os = "openbsd",
1774))]
1775// qemu doesn't seem to be emulating this correctly in these architectures
1776#[cfg_attr(
1777 all(
1778 qemu,
1779 any(
1780 target_arch = "mips",
1781 target_arch = "mips64",
1782 target_arch = "powerpc64",
1783 )
1784 ),
1785 ignore
1786)]
1787#[test]
1788pub fn test_recvif() {
1789 use nix::net::if_::*;
1790 use nix::sys::socket::sockopt::{Ipv4RecvDstAddr, Ipv4RecvIf};
1791 use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn};
1792 use nix::sys::socket::{getsockname, setsockopt, socket};
1793 use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags};
1794 use std::io::{IoSlice, IoSliceMut};
1795
1796 let lo_ifaddr = loopback_address(AddressFamily::Inet);
1797 let (lo_name, lo) = match lo_ifaddr {
1798 Some(ifaddr) => (
1799 ifaddr.interface_name,
1800 ifaddr.address.expect("Expect IPv4 address on interface"),
1801 ),
1802 None => return,
1803 };
1804 let receive = socket(
1805 AddressFamily::Inet,
1806 SockType::Datagram,
1807 SockFlag::empty(),
1808 None,
1809 )
1810 .expect("receive socket failed");
1811 bind(receive.as_raw_fd(), &lo).expect("bind failed");
1812 let sa: SockaddrIn =
1813 getsockname(receive.as_raw_fd()).expect("getsockname failed");
1814 setsockopt(&receive, Ipv4RecvIf, &true)
1815 .expect("setsockopt IP_RECVIF failed");
1816 setsockopt(&receive, Ipv4RecvDstAddr, &true)
1817 .expect("setsockopt IP_RECVDSTADDR failed");
1818
1819 {
1820 let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
1821 let iov = [IoSlice::new(&slice)];
1822
1823 let send = socket(
1824 AddressFamily::Inet,
1825 SockType::Datagram,
1826 SockFlag::empty(),
1827 None,
1828 )
1829 .expect("send socket failed");
1830 sendmsg(send.as_raw_fd(), &iov, &[], MsgFlags::empty(), Some(&sa))
1831 .expect("sendmsg failed");
1832 }
1833
1834 {
1835 let mut buf = [0u8; 8];
1836 let mut iovec = [IoSliceMut::new(&mut buf)];
1837 let mut space = cmsg_space!(libc::sockaddr_dl, libc::in_addr);
1838 let msg = recvmsg::<()>(
1839 receive.as_raw_fd(),
1840 &mut iovec,
1841 Some(&mut space),
1842 MsgFlags::empty(),
1843 )
1844 .expect("recvmsg failed");
1845 assert!(!msg
1846 .flags
1847 .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
1848 assert_eq!(msg.cmsgs().count(), 2, "expected 2 cmsgs");
1849
1850 let mut rx_recvif = false;
1851 let mut rx_recvdstaddr = false;
1852 for cmsg in msg.cmsgs() {
1853 match cmsg {
1854 ControlMessageOwned::Ipv4RecvIf(dl) => {
1855 rx_recvif = true;
1856 let i = if_nametoindex(lo_name.as_bytes())
1857 .expect("if_nametoindex");
1858 assert_eq!(
1859 dl.sdl_index as libc::c_uint, i,
1860 "unexpected ifindex (expected {}, got {})",
1861 i, dl.sdl_index
1862 );
1863 }
1864 ControlMessageOwned::Ipv4RecvDstAddr(addr) => {
1865 rx_recvdstaddr = true;
1866 if let Some(sin) = lo.as_sockaddr_in() {
1867 assert_eq!(sin.as_ref().sin_addr.s_addr,
1868 addr.s_addr,
1869 "unexpected destination address (expected {}, got {})",
1870 sin.as_ref().sin_addr.s_addr,
1871 addr.s_addr);
1872 } else {
1873 panic!("unexpected Sockaddr");
1874 }
1875 }
1876 _ => panic!("unexpected additional control msg"),
1877 }
1878 }
1879 assert!(rx_recvif);
1880 assert!(rx_recvdstaddr);
1881 assert_eq!(msg.bytes, 8);
1882 assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]);
1883 }
1884}
1885
1886#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
1887#[cfg_attr(qemu, ignore)]
1888#[test]
1889pub fn test_recvif_ipv4() {
1890 use nix::sys::socket::sockopt::Ipv4OrigDstAddr;
1891 use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn};
1892 use nix::sys::socket::{getsockname, setsockopt, socket};
1893 use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags};
1894 use std::io::{IoSlice, IoSliceMut};
1895
1896 let lo_ifaddr = loopback_address(AddressFamily::Inet);
1897 let (_lo_name, lo) = match lo_ifaddr {
1898 Some(ifaddr) => (
1899 ifaddr.interface_name,
1900 ifaddr.address.expect("Expect IPv4 address on interface"),
1901 ),
1902 None => return,
1903 };
1904 let receive = socket(
1905 AddressFamily::Inet,
1906 SockType::Datagram,
1907 SockFlag::empty(),
1908 None,
1909 )
1910 .expect("receive socket failed");
1911 bind(receive.as_raw_fd(), &lo).expect("bind failed");
1912 let sa: SockaddrIn =
1913 getsockname(receive.as_raw_fd()).expect("getsockname failed");
1914 setsockopt(&receive, Ipv4OrigDstAddr, &true)
1915 .expect("setsockopt IP_ORIGDSTADDR failed");
1916
1917 {
1918 let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
1919 let iov = [IoSlice::new(&slice)];
1920
1921 let send = socket(
1922 AddressFamily::Inet,
1923 SockType::Datagram,
1924 SockFlag::empty(),
1925 None,
1926 )
1927 .expect("send socket failed");
1928 sendmsg(send.as_raw_fd(), &iov, &[], MsgFlags::empty(), Some(&sa))
1929 .expect("sendmsg failed");
1930 }
1931
1932 {
1933 let mut buf = [0u8; 8];
1934 let mut iovec = [IoSliceMut::new(&mut buf)];
1935 let mut space = cmsg_space!(libc::sockaddr_in);
1936 let msg = recvmsg::<()>(
1937 receive.as_raw_fd(),
1938 &mut iovec,
1939 Some(&mut space),
1940 MsgFlags::empty(),
1941 )
1942 .expect("recvmsg failed");
1943 assert!(!msg
1944 .flags
1945 .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
1946 assert_eq!(msg.cmsgs().count(), 1, "expected 1 cmsgs");
1947
1948 let mut rx_recvorigdstaddr = false;
1949 for cmsg in msg.cmsgs() {
1950 match cmsg {
1951 ControlMessageOwned::Ipv4OrigDstAddr(addr) => {
1952 rx_recvorigdstaddr = true;
1953 if let Some(sin) = lo.as_sockaddr_in() {
1954 assert_eq!(sin.as_ref().sin_addr.s_addr,
1955 addr.sin_addr.s_addr,
1956 "unexpected destination address (expected {}, got {})",
1957 sin.as_ref().sin_addr.s_addr,
1958 addr.sin_addr.s_addr);
1959 } else {
1960 panic!("unexpected Sockaddr");
1961 }
1962 }
1963 _ => panic!("unexpected additional control msg"),
1964 }
1965 }
1966 assert!(rx_recvorigdstaddr);
1967 assert_eq!(msg.bytes, 8);
1968 assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]);
1969 }
1970}
1971
1972#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
1973#[cfg_attr(qemu, ignore)]
1974#[test]
1975pub fn test_recvif_ipv6() {
1976 use nix::sys::socket::sockopt::Ipv6OrigDstAddr;
1977 use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn6};
1978 use nix::sys::socket::{getsockname, setsockopt, socket};
1979 use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags};
1980 use std::io::{IoSlice, IoSliceMut};
1981
1982 let lo_ifaddr = loopback_address(AddressFamily::Inet6);
1983 let (_lo_name, lo) = match lo_ifaddr {
1984 Some(ifaddr) => (
1985 ifaddr.interface_name,
1986 ifaddr.address.expect("Expect IPv6 address on interface"),
1987 ),
1988 None => return,
1989 };
1990 let receive = socket(
1991 AddressFamily::Inet6,
1992 SockType::Datagram,
1993 SockFlag::empty(),
1994 None,
1995 )
1996 .expect("receive socket failed");
1997 bind(receive.as_raw_fd(), &lo).expect("bind failed");
1998 let sa: SockaddrIn6 =
1999 getsockname(receive.as_raw_fd()).expect("getsockname failed");
2000 setsockopt(&receive, Ipv6OrigDstAddr, &true)
2001 .expect("setsockopt IP_ORIGDSTADDR failed");
2002
2003 {
2004 let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
2005 let iov = [IoSlice::new(&slice)];
2006
2007 let send = socket(
2008 AddressFamily::Inet6,
2009 SockType::Datagram,
2010 SockFlag::empty(),
2011 None,
2012 )
2013 .expect("send socket failed");
2014 sendmsg(send.as_raw_fd(), &iov, &[], MsgFlags::empty(), Some(&sa))
2015 .expect("sendmsg failed");
2016 }
2017
2018 {
2019 let mut buf = [0u8; 8];
2020 let mut iovec = [IoSliceMut::new(&mut buf)];
2021 let mut space = cmsg_space!(libc::sockaddr_in6);
2022 let msg = recvmsg::<()>(
2023 receive.as_raw_fd(),
2024 &mut iovec,
2025 Some(&mut space),
2026 MsgFlags::empty(),
2027 )
2028 .expect("recvmsg failed");
2029 assert!(!msg
2030 .flags
2031 .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
2032 assert_eq!(msg.cmsgs().count(), 1, "expected 1 cmsgs");
2033
2034 let mut rx_recvorigdstaddr = false;
2035 for cmsg in msg.cmsgs() {
2036 match cmsg {
2037 ControlMessageOwned::Ipv6OrigDstAddr(addr) => {
2038 rx_recvorigdstaddr = true;
2039 if let Some(sin) = lo.as_sockaddr_in6() {
2040 assert_eq!(sin.as_ref().sin6_addr.s6_addr,
2041 addr.sin6_addr.s6_addr,
2042 "unexpected destination address (expected {:?}, got {:?})",
2043 sin.as_ref().sin6_addr.s6_addr,
2044 addr.sin6_addr.s6_addr);
2045 } else {
2046 panic!("unexpected Sockaddr");
2047 }
2048 }
2049 _ => panic!("unexpected additional control msg"),
2050 }
2051 }
2052 assert!(rx_recvorigdstaddr);
2053 assert_eq!(msg.bytes, 8);
2054 assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]);
2055 }
2056}
2057
2058#[cfg(any(
2059 target_os = "android",
2060 target_os = "freebsd",
2061 target_os = "ios",
2062 target_os = "linux",
2063 target_os = "macos",
2064 target_os = "netbsd",
2065 target_os = "openbsd",
2066))]
2067// qemu doesn't seem to be emulating this correctly in these architectures
2068#[cfg_attr(
2069 all(
2070 qemu,
2071 any(
2072 target_arch = "mips",
2073 target_arch = "mips64",
2074 target_arch = "powerpc64",
2075 )
2076 ),
2077 ignore
2078)]
2079#[test]
2080pub fn test_recv_ipv6pktinfo() {
2081 use nix::net::if_::*;
2082 use nix::sys::socket::sockopt::Ipv6RecvPacketInfo;
2083 use nix::sys::socket::{bind, SockFlag, SockType, SockaddrIn6};
2084 use nix::sys::socket::{getsockname, setsockopt, socket};
2085 use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags};
2086 use std::io::{IoSlice, IoSliceMut};
2087
2088 let lo_ifaddr = loopback_address(AddressFamily::Inet6);
2089 let (lo_name, lo) = match lo_ifaddr {
2090 Some(ifaddr) => (
2091 ifaddr.interface_name,
2092 ifaddr.address.expect("Expect IPv6 address on interface"),
2093 ),
2094 None => return,
2095 };
2096 let receive = socket(
2097 AddressFamily::Inet6,
2098 SockType::Datagram,
2099 SockFlag::empty(),
2100 None,
2101 )
2102 .expect("receive socket failed");
2103 bind(receive.as_raw_fd(), &lo).expect("bind failed");
2104 let sa: SockaddrIn6 =
2105 getsockname(receive.as_raw_fd()).expect("getsockname failed");
2106 setsockopt(&receive, Ipv6RecvPacketInfo, &true).expect("setsockopt failed");
2107
2108 {
2109 let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
2110 let iov = [IoSlice::new(&slice)];
2111
2112 let send = socket(
2113 AddressFamily::Inet6,
2114 SockType::Datagram,
2115 SockFlag::empty(),
2116 None,
2117 )
2118 .expect("send socket failed");
2119 sendmsg(send.as_raw_fd(), &iov, &[], MsgFlags::empty(), Some(&sa))
2120 .expect("sendmsg failed");
2121 }
2122
2123 {
2124 let mut buf = [0u8; 8];
2125 let mut iovec = [IoSliceMut::new(&mut buf)];
2126
2127 let mut space = cmsg_space!(libc::in6_pktinfo);
2128 let msg = recvmsg::<()>(
2129 receive.as_raw_fd(),
2130 &mut iovec,
2131 Some(&mut space),
2132 MsgFlags::empty(),
2133 )
2134 .expect("recvmsg failed");
2135 assert!(!msg
2136 .flags
2137 .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
2138
2139 let mut cmsgs = msg.cmsgs();
2140 if let Some(ControlMessageOwned::Ipv6PacketInfo(pktinfo)) = cmsgs.next()
2141 {
2142 let i = if_nametoindex(lo_name.as_bytes()).expect("if_nametoindex");
2143 assert_eq!(
2144 pktinfo.ipi6_ifindex as libc::c_uint, i,
2145 "unexpected ifindex (expected {}, got {})",
2146 i, pktinfo.ipi6_ifindex
2147 );
2148 }
2149 assert!(cmsgs.next().is_none(), "unexpected additional control msg");
2150 assert_eq!(msg.bytes, 8);
2151 assert_eq!(*iovec[0], [1u8, 2, 3, 4, 5, 6, 7, 8]);
2152 }
2153}
2154
2155#[cfg(any(target_os = "android", target_os = "linux"))]
2156#[test]
2157pub fn test_vsock() {
2158 use nix::sys::socket::SockaddrLike;
2159 use nix::sys::socket::{AddressFamily, VsockAddr};
2160 use std::mem;
2161
2162 let port: u32 = 3000;
2163
2164 let addr_local = VsockAddr::new(libc::VMADDR_CID_LOCAL, port);
2165 assert_eq!(addr_local.cid(), libc::VMADDR_CID_LOCAL);
2166 assert_eq!(addr_local.port(), port);
2167
2168 let addr_any = VsockAddr::new(libc::VMADDR_CID_ANY, libc::VMADDR_PORT_ANY);
2169 assert_eq!(addr_any.cid(), libc::VMADDR_CID_ANY);
2170 assert_eq!(addr_any.port(), libc::VMADDR_PORT_ANY);
2171
2172 assert_ne!(addr_local, addr_any);
2173 assert_ne!(calculate_hash(&addr_local), calculate_hash(&addr_any));
2174
2175 let addr1 = VsockAddr::new(libc::VMADDR_CID_HOST, port);
2176 let addr2 = VsockAddr::new(libc::VMADDR_CID_HOST, port);
2177 assert_eq!(addr1, addr2);
2178 assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2));
2179
2180 let addr3 = unsafe {
2181 VsockAddr::from_raw(
2182 addr2.as_ref() as *const libc::sockaddr_vm as *const libc::sockaddr,
2183 Some(mem::size_of::<libc::sockaddr_vm>().try_into().unwrap()),
2184 )
2185 }
2186 .unwrap();
2187 assert_eq!(
2188 addr3.as_ref().svm_family,
2189 AddressFamily::Vsock as libc::sa_family_t
2190 );
2191 assert_eq!(addr3.as_ref().svm_cid, addr1.cid());
2192 assert_eq!(addr3.as_ref().svm_port, addr1.port());
2193}
2194
2195#[cfg(target_os = "macos")]
2196#[test]
2197pub fn test_vsock() {
2198 use nix::sys::socket::SockaddrLike;
2199 use nix::sys::socket::{AddressFamily, VsockAddr};
2200 use std::mem;
2201
2202 let port: u32 = 3000;
2203
2204 // macOS doesn't have a VMADDR_CID_LOCAL, so test with host again
2205 let addr_host = VsockAddr::new(libc::VMADDR_CID_HOST, port);
2206 assert_eq!(addr_host.cid(), libc::VMADDR_CID_HOST);
2207 assert_eq!(addr_host.port(), port);
2208
2209 let addr_any = VsockAddr::new(libc::VMADDR_CID_ANY, libc::VMADDR_PORT_ANY);
2210 assert_eq!(addr_any.cid(), libc::VMADDR_CID_ANY);
2211 assert_eq!(addr_any.port(), libc::VMADDR_PORT_ANY);
2212
2213 assert_ne!(addr_host, addr_any);
2214 assert_ne!(calculate_hash(&addr_host), calculate_hash(&addr_any));
2215
2216 let addr1 = VsockAddr::new(libc::VMADDR_CID_HOST, port);
2217 let addr2 = VsockAddr::new(libc::VMADDR_CID_HOST, port);
2218 assert_eq!(addr1, addr2);
2219 assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2));
2220
2221 let addr3 = unsafe {
2222 VsockAddr::from_raw(
2223 addr2.as_ref() as *const libc::sockaddr_vm as *const libc::sockaddr,
2224 Some(mem::size_of::<libc::sockaddr_vm>().try_into().unwrap()),
2225 )
2226 }
2227 .unwrap();
2228 assert_eq!(
2229 addr3.as_ref().svm_family,
2230 AddressFamily::Vsock as libc::sa_family_t
2231 );
2232 let cid = addr3.as_ref().svm_cid;
2233 let port = addr3.as_ref().svm_port;
2234 assert_eq!(cid, addr1.cid());
2235 assert_eq!(port, addr1.port());
2236}
2237
2238// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack
2239// of QEMU support is suspected.
2240#[cfg_attr(qemu, ignore)]
2241#[cfg(target_os = "linux")]
2242#[test]
2243fn test_recvmsg_timestampns() {
2244 use nix::sys::socket::*;
2245 use nix::sys::time::*;
2246 use std::io::{IoSlice, IoSliceMut};
2247 use std::time::*;
2248
2249 // Set up
2250 let message = "Ohayō!".as_bytes();
2251 let in_socket = socket(
2252 AddressFamily::Inet,
2253 SockType::Datagram,
2254 SockFlag::empty(),
2255 None,
2256 )
2257 .unwrap();
2258 setsockopt(&in_socket, sockopt::ReceiveTimestampns, &true).unwrap();
2259 let localhost = SockaddrIn::new(127, 0, 0, 1, 0);
2260 bind(in_socket.as_raw_fd(), &localhost).unwrap();
2261 let address: SockaddrIn = getsockname(in_socket.as_raw_fd()).unwrap();
2262 // Get initial time
2263 let time0 = SystemTime::now();
2264 // Send the message
2265 let iov = [IoSlice::new(message)];
2266 let flags = MsgFlags::empty();
2267 let l = sendmsg(in_socket.as_raw_fd(), &iov, &[], flags, Some(&address))
2268 .unwrap();
2269 assert_eq!(message.len(), l);
2270 // Receive the message
2271 let mut buffer = vec![0u8; message.len()];
2272 let mut cmsgspace = nix::cmsg_space!(TimeSpec);
2273
2274 let mut iov = [IoSliceMut::new(&mut buffer)];
2275 let r = recvmsg::<()>(
2276 in_socket.as_raw_fd(),
2277 &mut iov,
2278 Some(&mut cmsgspace),
2279 flags,
2280 )
2281 .unwrap();
2282 let rtime = match r.cmsgs().next() {
2283 Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime,
2284 Some(_) => panic!("Unexpected control message"),
2285 None => panic!("No control message"),
2286 };
2287 // Check the final time
2288 let time1 = SystemTime::now();
2289 // the packet's received timestamp should lie in-between the two system
2290 // times, unless the system clock was adjusted in the meantime.
2291 let rduration =
2292 Duration::new(rtime.tv_sec() as u64, rtime.tv_nsec() as u32);
2293 assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration);
2294 assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap());
2295}
2296
2297// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack
2298// of QEMU support is suspected.
2299#[cfg_attr(qemu, ignore)]
2300#[cfg(target_os = "linux")]
2301#[test]
2302fn test_recvmmsg_timestampns() {
2303 use nix::sys::socket::*;
2304 use nix::sys::time::*;
2305 use std::io::{IoSlice, IoSliceMut};
2306 use std::time::*;
2307
2308 // Set up
2309 let message = "Ohayō!".as_bytes();
2310 let in_socket = socket(
2311 AddressFamily::Inet,
2312 SockType::Datagram,
2313 SockFlag::empty(),
2314 None,
2315 )
2316 .unwrap();
2317 setsockopt(&in_socket, sockopt::ReceiveTimestampns, &true).unwrap();
2318 let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap();
2319 bind(in_socket.as_raw_fd(), &localhost).unwrap();
2320 let address: SockaddrIn = getsockname(in_socket.as_raw_fd()).unwrap();
2321 // Get initial time
2322 let time0 = SystemTime::now();
2323 // Send the message
2324 let iov = [IoSlice::new(message)];
2325 let flags = MsgFlags::empty();
2326 let l = sendmsg(in_socket.as_raw_fd(), &iov, &[], flags, Some(&address))
2327 .unwrap();
2328 assert_eq!(message.len(), l);
2329 // Receive the message
2330 let mut buffer = vec![0u8; message.len()];
2331 let cmsgspace = nix::cmsg_space!(TimeSpec);
2332 let iov = vec![[IoSliceMut::new(&mut buffer)]];
2333 let mut data = MultiHeaders::preallocate(1, Some(cmsgspace));
2334 let r: Vec<RecvMsg<()>> =
2335 recvmmsg(in_socket.as_raw_fd(), &mut data, iov.iter(), flags, None)
2336 .unwrap()
2337 .collect();
2338 let rtime = match r[0].cmsgs().next() {
2339 Some(ControlMessageOwned::ScmTimestampns(rtime)) => rtime,
2340 Some(_) => panic!("Unexpected control message"),
2341 None => panic!("No control message"),
2342 };
2343 // Check the final time
2344 let time1 = SystemTime::now();
2345 // the packet's received timestamp should lie in-between the two system
2346 // times, unless the system clock was adjusted in the meantime.
2347 let rduration =
2348 Duration::new(rtime.tv_sec() as u64, rtime.tv_nsec() as u32);
2349 assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration);
2350 assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap());
2351}
2352
2353// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack
2354// of QEMU support is suspected.
2355#[cfg_attr(qemu, ignore)]
2356#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
2357#[test]
2358fn test_recvmsg_rxq_ovfl() {
2359 use nix::sys::socket::sockopt::{RcvBuf, RxqOvfl};
2360 use nix::sys::socket::*;
2361 use nix::Error;
2362 use std::io::{IoSlice, IoSliceMut};
2363
2364 let message = [0u8; 2048];
2365 let bufsize = message.len() * 2;
2366
2367 let in_socket = socket(
2368 AddressFamily::Inet,
2369 SockType::Datagram,
2370 SockFlag::empty(),
2371 None,
2372 )
2373 .unwrap();
2374 let out_socket = socket(
2375 AddressFamily::Inet,
2376 SockType::Datagram,
2377 SockFlag::empty(),
2378 None,
2379 )
2380 .unwrap();
2381
2382 let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap();
2383 bind(in_socket.as_raw_fd(), &localhost).unwrap();
2384
2385 let address: SockaddrIn = getsockname(in_socket.as_raw_fd()).unwrap();
2386 connect(out_socket.as_raw_fd(), &address).unwrap();
2387
2388 // Set SO_RXQ_OVFL flag.
2389 setsockopt(&in_socket, RxqOvfl, &1).unwrap();
2390
2391 // Set the receiver buffer size to hold only 2 messages.
2392 setsockopt(&in_socket, RcvBuf, &bufsize).unwrap();
2393
2394 let mut drop_counter = 0;
2395
2396 for _ in 0..2 {
2397 let iov = [IoSlice::new(&message)];
2398 let flags = MsgFlags::empty();
2399
2400 // Send the 3 messages (the receiver buffer can only hold 2 messages)
2401 // to create an overflow.
2402 for _ in 0..3 {
2403 let l = sendmsg(
2404 out_socket.as_raw_fd(),
2405 &iov,
2406 &[],
2407 flags,
2408 Some(&address),
2409 )
2410 .unwrap();
2411 assert_eq!(message.len(), l);
2412 }
2413
2414 // Receive the message and check the drop counter if any.
2415 loop {
2416 let mut buffer = vec![0u8; message.len()];
2417 let mut cmsgspace = nix::cmsg_space!(u32);
2418
2419 let mut iov = [IoSliceMut::new(&mut buffer)];
2420
2421 match recvmsg::<()>(
2422 in_socket.as_raw_fd(),
2423 &mut iov,
2424 Some(&mut cmsgspace),
2425 MsgFlags::MSG_DONTWAIT,
2426 ) {
2427 Ok(r) => {
2428 drop_counter = match r.cmsgs().next() {
2429 Some(ControlMessageOwned::RxqOvfl(drop_counter)) => {
2430 drop_counter
2431 }
2432 Some(_) => panic!("Unexpected control message"),
2433 None => 0,
2434 };
2435 }
2436 Err(Error::EAGAIN) => {
2437 break;
2438 }
2439 _ => {
2440 panic!("unknown recvmsg() error");
2441 }
2442 }
2443 }
2444 }
2445
2446 // One packet lost.
2447 assert_eq!(drop_counter, 1);
2448}
2449
2450#[cfg(any(target_os = "linux", target_os = "android",))]
2451mod linux_errqueue {
2452 use super::FromStr;
2453 use nix::sys::socket::*;
2454 use std::os::unix::io::AsRawFd;
2455
2456 // Send a UDP datagram to a bogus destination address and observe an ICMP error (v4).
2457 //
2458 // Disable the test on QEMU because QEMU emulation of IP_RECVERR is broken (as documented on PR
2459 // #1514).
2460 #[cfg_attr(qemu, ignore)]
2461 #[test]
2462 fn test_recverr_v4() {
2463 #[repr(u8)]
2464 enum IcmpTypes {
2465 DestUnreach = 3, // ICMP_DEST_UNREACH
2466 }
2467 #[repr(u8)]
2468 enum IcmpUnreachCodes {
2469 PortUnreach = 3, // ICMP_PORT_UNREACH
2470 }
2471
2472 test_recverr_impl::<sockaddr_in, _, _>(
2473 "127.0.0.1:6800",
2474 AddressFamily::Inet,
2475 sockopt::Ipv4RecvErr,
2476 libc::SO_EE_ORIGIN_ICMP,
2477 IcmpTypes::DestUnreach as u8,
2478 IcmpUnreachCodes::PortUnreach as u8,
2479 // Closure handles protocol-specific testing and returns generic sock_extended_err for
2480 // protocol-independent test impl.
2481 |cmsg| {
2482 if let ControlMessageOwned::Ipv4RecvErr(ext_err, err_addr) =
2483 cmsg
2484 {
2485 if let Some(origin) = err_addr {
2486 // Validate that our network error originated from 127.0.0.1:0.
2487 assert_eq!(origin.sin_family, AddressFamily::Inet as _);
2488 assert_eq!(
2489 origin.sin_addr.s_addr,
2490 u32::from_be(0x7f000001)
2491 );
2492 assert_eq!(origin.sin_port, 0);
2493 } else {
2494 panic!("Expected some error origin");
2495 }
2496 *ext_err
2497 } else {
2498 panic!("Unexpected control message {cmsg:?}");
2499 }
2500 },
2501 )
2502 }
2503
2504 // Essentially the same test as v4.
2505 //
2506 // Disable the test on QEMU because QEMU emulation of IPV6_RECVERR is broken (as documented on
2507 // PR #1514).
2508 #[cfg_attr(qemu, ignore)]
2509 #[test]
2510 fn test_recverr_v6() {
2511 #[repr(u8)]
2512 enum IcmpV6Types {
2513 DestUnreach = 1, // ICMPV6_DEST_UNREACH
2514 }
2515 #[repr(u8)]
2516 enum IcmpV6UnreachCodes {
2517 PortUnreach = 4, // ICMPV6_PORT_UNREACH
2518 }
2519
2520 test_recverr_impl::<sockaddr_in6, _, _>(
2521 "[::1]:6801",
2522 AddressFamily::Inet6,
2523 sockopt::Ipv6RecvErr,
2524 libc::SO_EE_ORIGIN_ICMP6,
2525 IcmpV6Types::DestUnreach as u8,
2526 IcmpV6UnreachCodes::PortUnreach as u8,
2527 // Closure handles protocol-specific testing and returns generic sock_extended_err for
2528 // protocol-independent test impl.
2529 |cmsg| {
2530 if let ControlMessageOwned::Ipv6RecvErr(ext_err, err_addr) =
2531 cmsg
2532 {
2533 if let Some(origin) = err_addr {
2534 // Validate that our network error originated from localhost:0.
2535 assert_eq!(
2536 origin.sin6_family,
2537 AddressFamily::Inet6 as _
2538 );
2539 assert_eq!(
2540 origin.sin6_addr.s6_addr,
2541 std::net::Ipv6Addr::LOCALHOST.octets()
2542 );
2543 assert_eq!(origin.sin6_port, 0);
2544 } else {
2545 panic!("Expected some error origin");
2546 }
2547 *ext_err
2548 } else {
2549 panic!("Unexpected control message {cmsg:?}");
2550 }
2551 },
2552 )
2553 }
2554
2555 fn test_recverr_impl<SA, OPT, TESTF>(
2556 sa: &str,
2557 af: AddressFamily,
2558 opt: OPT,
2559 ee_origin: u8,
2560 ee_type: u8,
2561 ee_code: u8,
2562 testf: TESTF,
2563 ) where
2564 OPT: SetSockOpt<Val = bool>,
2565 TESTF: FnOnce(&ControlMessageOwned) -> libc::sock_extended_err,
2566 {
2567 use nix::errno::Errno;
2568 use std::io::IoSliceMut;
2569
2570 const MESSAGE_CONTENTS: &str = "ABCDEF";
2571 let std_sa = std::net::SocketAddr::from_str(sa).unwrap();
2572 let sock_addr = SockaddrStorage::from(std_sa);
2573 let sock = socket(af, SockType::Datagram, SockFlag::SOCK_CLOEXEC, None)
2574 .unwrap();
2575 setsockopt(&sock, opt, &true).unwrap();
2576 if let Err(e) = sendto(
2577 sock.as_raw_fd(),
2578 MESSAGE_CONTENTS.as_bytes(),
2579 &sock_addr,
2580 MsgFlags::empty(),
2581 ) {
2582 assert_eq!(e, Errno::EADDRNOTAVAIL);
2583 println!("{af:?} not available, skipping test.");
2584 return;
2585 }
2586
2587 let mut buf = [0u8; 8];
2588 let mut iovec = [IoSliceMut::new(&mut buf)];
2589 let mut cspace = cmsg_space!(libc::sock_extended_err, SA);
2590
2591 let msg = recvmsg(
2592 sock.as_raw_fd(),
2593 &mut iovec,
2594 Some(&mut cspace),
2595 MsgFlags::MSG_ERRQUEUE,
2596 )
2597 .unwrap();
2598 // The sent message / destination associated with the error is returned:
2599 assert_eq!(msg.bytes, MESSAGE_CONTENTS.as_bytes().len());
2600 // recvmsg(2): "The original destination address of the datagram that caused the error is
2601 // supplied via msg_name;" however, this is not literally true. E.g., an earlier version
2602 // of this test used 0.0.0.0 (::0) as the destination address, which was mutated into
2603 // 127.0.0.1 (::1).
2604 assert_eq!(msg.address, Some(sock_addr));
2605
2606 // Check for expected control message.
2607 let ext_err = match msg.cmsgs().next() {
2608 Some(cmsg) => testf(&cmsg),
2609 None => panic!("No control message"),
2610 };
2611
2612 assert_eq!(ext_err.ee_errno, libc::ECONNREFUSED as u32);
2613 assert_eq!(ext_err.ee_origin, ee_origin);
2614 // ip(7): ee_type and ee_code are set from the type and code fields of the ICMP (ICMPv6)
2615 // header.
2616 assert_eq!(ext_err.ee_type, ee_type);
2617 assert_eq!(ext_err.ee_code, ee_code);
2618 // ip(7): ee_info contains the discovered MTU for EMSGSIZE errors.
2619 assert_eq!(ext_err.ee_info, 0);
2620
2621 let bytes = msg.bytes;
2622 assert_eq!(&buf[..bytes], MESSAGE_CONTENTS.as_bytes());
2623 }
2624}
2625
2626// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack
2627// of QEMU support is suspected.
2628#[cfg_attr(qemu, ignore)]
2629#[cfg(target_os = "linux")]
2630#[test]
2631pub fn test_txtime() {
2632 use nix::sys::socket::{
2633 bind, recvmsg, sendmsg, setsockopt, socket, sockopt, ControlMessage,
2634 MsgFlags, SockFlag, SockType, SockaddrIn,
2635 };
2636 use nix::sys::time::TimeValLike;
2637 use nix::time::{clock_gettime, ClockId};
2638
2639 require_kernel_version!(test_txtime, ">= 5.8");
2640
2641 let sock_addr = SockaddrIn::from_str("127.0.0.1:6802").unwrap();
2642
2643 let ssock = socket(
2644 AddressFamily::Inet,
2645 SockType::Datagram,
2646 SockFlag::empty(),
2647 None,
2648 )
2649 .expect("send socket failed");
2650
2651 let txtime_cfg = libc::sock_txtime {
2652 clockid: libc::CLOCK_MONOTONIC,
2653 flags: 0,
2654 };
2655 setsockopt(&ssock, sockopt::TxTime, &txtime_cfg).unwrap();
2656
2657 let rsock = socket(
2658 AddressFamily::Inet,
2659 SockType::Datagram,
2660 SockFlag::empty(),
2661 None,
2662 )
2663 .unwrap();
2664 bind(rsock.as_raw_fd(), &sock_addr).unwrap();
2665
2666 let sbuf = [0u8; 2048];
2667 let iov1 = [std::io::IoSlice::new(&sbuf)];
2668
2669 let now = clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap();
2670 let delay = std::time::Duration::from_secs(1).into();
2671 let txtime = (now + delay).num_nanoseconds() as u64;
2672
2673 let cmsg = ControlMessage::TxTime(&txtime);
2674 sendmsg(
2675 ssock.as_raw_fd(),
2676 &iov1,
2677 &[cmsg],
2678 MsgFlags::empty(),
2679 Some(&sock_addr),
2680 )
2681 .unwrap();
2682
2683 let mut rbuf = [0u8; 2048];
2684 let mut iov2 = [std::io::IoSliceMut::new(&mut rbuf)];
2685 recvmsg::<()>(rsock.as_raw_fd(), &mut iov2, None, MsgFlags::empty())
2686 .unwrap();
2687}
2688