1#[cfg(feature = "async")]
6mod async_impl;
7mod config;
8mod sync_impl;
9
10use std::io;
11
12use socket2::Socket;
13
14use crate::SocketFamily;
15
16#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
17fn set_bool_sockopt(
18 socket: &Socket,
19 level: libc::c_int,
20 optname: libc::c_int,
21 on: bool,
22) -> io::Result<()> {
23 use std::os::fd::AsRawFd;
24 let value: libc::c_int = if on { 1 } else { 0 };
25 let ret = unsafe {
28 libc::setsockopt(
29 socket.as_raw_fd(),
30 level,
31 optname,
32 (&value as *const libc::c_int).cast(),
33 std::mem::size_of::<libc::c_int>() as libc::socklen_t,
34 )
35 };
36 if ret == 0 {
37 Ok(())
38 } else {
39 Err(io::Error::last_os_error())
40 }
41}
42
43#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
44fn get_bool_sockopt(socket: &Socket, level: libc::c_int, optname: libc::c_int) -> io::Result<bool> {
45 use std::os::fd::AsRawFd;
46 let mut value: libc::c_int = 0;
47 let mut len = std::mem::size_of::<libc::c_int>() as libc::socklen_t;
48 let ret = unsafe {
51 libc::getsockopt(
52 socket.as_raw_fd(),
53 level,
54 optname,
55 (&mut value as *mut libc::c_int).cast(),
56 &mut len,
57 )
58 };
59 if ret == 0 {
60 Ok(value != 0)
61 } else {
62 Err(io::Error::last_os_error())
63 }
64}
65
66pub(crate) fn set_recv_pktinfo(socket: &Socket, family: SocketFamily, on: bool) -> io::Result<()> {
67 match family {
68 SocketFamily::IPV4 => set_recv_pktinfo_v4(socket, on),
69 SocketFamily::IPV6 => set_recv_pktinfo_v6(socket, on),
70 }
71}
72
73#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
74pub(crate) fn set_recv_pktinfo_v4(socket: &Socket, on: bool) -> io::Result<()> {
75 set_bool_sockopt(socket, libc::IPPROTO_IP, libc::IP_PKTINFO, on)
76}
77
78#[cfg(not(any(target_os = "android", target_os = "fuchsia", target_os = "linux")))]
79pub(crate) fn set_recv_pktinfo_v4(_socket: &Socket, _on: bool) -> io::Result<()> {
80 Err(io::Error::new(
81 io::ErrorKind::Unsupported,
82 "IP_PKTINFO is not supported on this platform",
83 ))
84}
85
86#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
87pub(crate) fn set_recv_pktinfo_v6(socket: &Socket, on: bool) -> io::Result<()> {
88 set_bool_sockopt(socket, libc::IPPROTO_IPV6, libc::IPV6_RECVPKTINFO, on)
89}
90
91#[cfg(not(any(target_os = "android", target_os = "fuchsia", target_os = "linux")))]
92pub(crate) fn set_recv_pktinfo_v6(_socket: &Socket, _on: bool) -> io::Result<()> {
93 Err(io::Error::new(
94 io::ErrorKind::Unsupported,
95 "IPV6_RECVPKTINFO is not supported on this platform",
96 ))
97}
98
99#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
100pub(crate) fn recv_pktinfo_v4(socket: &Socket) -> io::Result<bool> {
101 get_bool_sockopt(socket, libc::IPPROTO_IP, libc::IP_PKTINFO)
102}
103
104#[cfg(not(any(target_os = "android", target_os = "fuchsia", target_os = "linux")))]
105pub(crate) fn recv_pktinfo_v4(_socket: &Socket) -> io::Result<bool> {
106 Err(io::Error::new(
107 io::ErrorKind::Unsupported,
108 "IP_PKTINFO is not supported on this platform",
109 ))
110}
111
112#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
113pub(crate) fn recv_pktinfo_v6(socket: &Socket) -> io::Result<bool> {
114 get_bool_sockopt(socket, libc::IPPROTO_IPV6, libc::IPV6_RECVPKTINFO)
115}
116
117#[cfg(not(any(target_os = "android", target_os = "fuchsia", target_os = "linux")))]
118pub(crate) fn recv_pktinfo_v6(_socket: &Socket) -> io::Result<bool> {
119 Err(io::Error::new(
120 io::ErrorKind::Unsupported,
121 "IPV6_RECVPKTINFO is not supported on this platform",
122 ))
123}
124
125#[cfg(feature = "async")]
126pub use async_impl::*;
127pub use config::*;
128pub use sync_impl::*;