1 use rand::{thread_rng, Rng};
2 use nix::sys::socket::{socket, sockopt, getsockopt, setsockopt, AddressFamily, SockType, SockFlag, SockProtocol};
3 #[cfg(any(target_os = "android", target_os = "linux"))]
4 use crate::*;
5 
6 #[cfg(target_os = "linux")]
7 #[test]
is_so_mark_functional()8 fn is_so_mark_functional() {
9     use nix::sys::socket::sockopt;
10 
11     require_capability!(CAP_NET_ADMIN);
12 
13     let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
14     setsockopt(s, sockopt::Mark, &1337).unwrap();
15     let mark = getsockopt(s, sockopt::Mark).unwrap();
16     assert_eq!(mark, 1337);
17 }
18 
19 #[test]
test_so_buf()20 fn test_so_buf() {
21     let fd = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), SockProtocol::Udp)
22              .unwrap();
23     let bufsize: usize = thread_rng().gen_range(4096..131_072);
24     setsockopt(fd, sockopt::SndBuf, &bufsize).unwrap();
25     let actual = getsockopt(fd, sockopt::SndBuf).unwrap();
26     assert!(actual >= bufsize);
27     setsockopt(fd, sockopt::RcvBuf, &bufsize).unwrap();
28     let actual = getsockopt(fd, sockopt::RcvBuf).unwrap();
29     assert!(actual >= bufsize);
30 }
31 
32 // The CI doesn't supported getsockopt and setsockopt on emulated processors.
33 // It's beleived that a QEMU issue, the tests run ok on a fully emulated system.
34 // Current CI just run the binary with QEMU but the Kernel remains the same as the host.
35 // So the syscall doesn't work properly unless the kernel is also emulated.
36 #[test]
37 #[cfg(all(
38     any(target_arch = "x86", target_arch = "x86_64"),
39     any(target_os = "freebsd", target_os = "linux")
40 ))]
test_tcp_congestion()41 fn test_tcp_congestion() {
42     use std::ffi::OsString;
43 
44     let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
45 
46     let val = getsockopt(fd, sockopt::TcpCongestion).unwrap();
47     setsockopt(fd, sockopt::TcpCongestion, &val).unwrap();
48 
49     setsockopt(fd, sockopt::TcpCongestion, &OsString::from("tcp_congestion_does_not_exist")).unwrap_err();
50 
51     assert_eq!(
52         getsockopt(fd, sockopt::TcpCongestion).unwrap(),
53         val
54     );
55 }
56 
57 #[test]
58 #[cfg(any(target_os = "android", target_os = "linux"))]
test_bindtodevice()59 fn test_bindtodevice() {
60     skip_if_not_root!("test_bindtodevice");
61 
62     let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
63 
64     let val = getsockopt(fd, sockopt::BindToDevice).unwrap();
65     setsockopt(fd, sockopt::BindToDevice, &val).unwrap();
66 
67     assert_eq!(
68         getsockopt(fd, sockopt::BindToDevice).unwrap(),
69         val
70     );
71 }
72 
73 #[test]
test_so_tcp_keepalive()74 fn test_so_tcp_keepalive() {
75     let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), SockProtocol::Tcp).unwrap();
76     setsockopt(fd, sockopt::KeepAlive, &true).unwrap();
77     assert!(getsockopt(fd, sockopt::KeepAlive).unwrap());
78 
79     #[cfg(any(target_os = "android",
80               target_os = "dragonfly",
81               target_os = "freebsd",
82               target_os = "linux",
83               target_os = "nacl"))] {
84         let x = getsockopt(fd, sockopt::TcpKeepIdle).unwrap();
85         setsockopt(fd, sockopt::TcpKeepIdle, &(x + 1)).unwrap();
86         assert_eq!(getsockopt(fd, sockopt::TcpKeepIdle).unwrap(), x + 1);
87 
88         let x = getsockopt(fd, sockopt::TcpKeepCount).unwrap();
89         setsockopt(fd, sockopt::TcpKeepCount, &(x + 1)).unwrap();
90         assert_eq!(getsockopt(fd, sockopt::TcpKeepCount).unwrap(), x + 1);
91 
92         let x = getsockopt(fd, sockopt::TcpKeepInterval).unwrap();
93         setsockopt(fd, sockopt::TcpKeepInterval, &(x + 1)).unwrap();
94         assert_eq!(getsockopt(fd, sockopt::TcpKeepInterval).unwrap(), x + 1);
95     }
96 }
97