1#[test]
2fn test_sockopts() {
3    use rustix::net::{AddressFamily, Protocol, SocketType};
4    use std::time::Duration;
5
6    let s =
7        rustix::net::socket(AddressFamily::INET, SocketType::STREAM, Protocol::default()).unwrap();
8
9    // On a new socket we shouldn't have a timeout yet.
10    assert!(
11        rustix::net::sockopt::get_socket_timeout(&s, rustix::net::sockopt::Timeout::Recv)
12            .unwrap()
13            .is_none()
14    );
15    assert_eq!(
16        rustix::net::sockopt::get_socket_type(&s).unwrap(),
17        SocketType::STREAM
18    );
19    #[cfg(not(windows))]
20    assert!(!rustix::net::sockopt::get_socket_broadcast(&s).unwrap());
21    // On a new socket we shouldn't have a linger yet.
22    assert!(rustix::net::sockopt::get_socket_linger(&s)
23        .unwrap()
24        .is_none());
25    #[cfg(any(target_os = "android", target_os = "linux"))]
26    assert!(!rustix::net::sockopt::get_socket_passcred(&s).unwrap());
27    assert_ne!(rustix::net::sockopt::get_ip_ttl(&s).unwrap(), 0);
28    assert_ne!(rustix::net::sockopt::get_ip_ttl(&s).unwrap(), 77);
29    #[cfg(not(any(
30        windows,
31        target_os = "dragonfly",
32        target_os = "freebsd",
33        target_os = "ios",
34        target_os = "macos",
35        target_os = "netbsd",
36        target_os = "openbsd",
37    )))]
38    assert!(rustix::net::sockopt::get_ip_multicast_loop(&s).unwrap());
39    #[cfg(not(any(
40        windows,
41        target_os = "dragonfly",
42        target_os = "freebsd",
43        target_os = "ios",
44        target_os = "macos",
45        target_os = "netbsd",
46        target_os = "openbsd",
47    )))]
48    assert_eq!(rustix::net::sockopt::get_ip_multicast_ttl(&s).unwrap(), 1);
49    assert!(!rustix::net::sockopt::get_tcp_nodelay(&s).unwrap());
50
51    // Set a timeout.
52    rustix::net::sockopt::set_socket_timeout(
53        &s,
54        rustix::net::sockopt::Timeout::Recv,
55        Some(Duration::new(1, 1)),
56    )
57    .unwrap();
58
59    // Check that we have a timeout of at least the time we set.
60    if cfg!(not(target_os = "freebsd")) {
61        assert!(
62            rustix::net::sockopt::get_socket_timeout(&s, rustix::net::sockopt::Timeout::Recv)
63                .unwrap()
64                .unwrap()
65                >= Duration::new(1, 1)
66        );
67    } else {
68        // On FreeBSD <= 12, it appears the system rounds the timeout down.
69        assert!(
70            rustix::net::sockopt::get_socket_timeout(&s, rustix::net::sockopt::Timeout::Recv)
71                .unwrap()
72                .unwrap()
73                >= Duration::new(1, 0)
74        );
75    }
76
77    #[cfg(not(windows))]
78    {
79        // Set the broadcast flag;
80        rustix::net::sockopt::set_socket_broadcast(&s, true).unwrap();
81
82        // Check that the broadcast flag is set. This has no effect on stream
83        // sockets, and not all platforms even remember the value.
84        #[cfg(not(any(
85            target_os = "dragonfly",
86            target_os = "freebsd",
87            target_os = "ios",
88            target_os = "macos",
89            target_os = "netbsd",
90            target_os = "openbsd",
91        )))]
92        assert!(rustix::net::sockopt::get_socket_broadcast(&s).unwrap());
93    }
94
95    // Set a linger.
96    rustix::net::sockopt::set_socket_linger(&s, Some(Duration::new(1, 1))).unwrap();
97
98    // Check that we have a linger of at least the time we set.
99    assert!(
100        dbg!(rustix::net::sockopt::get_socket_linger(&s)
101            .unwrap()
102            .unwrap())
103            >= Duration::new(1, 1)
104    );
105
106    #[cfg(any(target_os = "android", target_os = "linux"))]
107    {
108        // Set the passcred flag;
109        rustix::net::sockopt::set_socket_passcred(&s, true).unwrap();
110
111        // Check that the passcred flag is set.
112        assert!(rustix::net::sockopt::get_socket_passcred(&s).unwrap());
113    }
114
115    // Set the ip ttl.
116    rustix::net::sockopt::set_ip_ttl(&s, 77).unwrap();
117
118    // Check the ip ttl.
119    assert_eq!(rustix::net::sockopt::get_ip_ttl(&s).unwrap(), 77);
120
121    #[cfg(not(any(
122        windows,
123        target_os = "dragonfly",
124        target_os = "freebsd",
125        target_os = "ios",
126        target_os = "macos",
127        target_os = "netbsd",
128        target_os = "openbsd",
129    )))]
130    {
131        // Set the multicast loop flag;
132        rustix::net::sockopt::set_ip_multicast_loop(&s, false).unwrap();
133
134        // Check that the multicast loop flag is set.
135        assert!(!rustix::net::sockopt::get_ip_multicast_loop(&s).unwrap());
136    }
137
138    // Set the nodelay flag;
139    rustix::net::sockopt::set_tcp_nodelay(&s, true).unwrap();
140
141    // Check that the nodelay flag is set.
142    assert!(rustix::net::sockopt::get_tcp_nodelay(&s).unwrap());
143}
144