1#[cfg(any(target_os = "linux", target_os = "android"))]
8#[derive(Clone, Copy, PartialEq, Eq)]
9pub struct DeviceName {
10 pub(super) bytes: [u8; libc::IFNAMSIZ],
11 pub(super) len: u8,
12}
13
14#[cfg(any(target_os = "linux", target_os = "android"))]
15impl core::ops::Deref for DeviceName {
16 type Target = [u8];
17
18 fn deref(&self) -> &[u8] {
19 &self.bytes[..usize::from(self.len)]
20 }
21}
22
23#[cfg(any(target_os = "linux", target_os = "android"))]
24impl core::fmt::Debug for DeviceName {
25 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
26 write!(f, "{:?}", String::from_utf8_lossy(self))
27 }
28}
29
30macro_rules! socket_options {
32 ($($ty:ty),* $(,)?) => {$(
33 impl $ty {
34 pub fn set_reuseaddr(&self, reuseaddr: bool) -> std::io::Result<()> {
37 opt::set_flag(self.raw(), opt::SOL_SOCKET, opt::SO_REUSEADDR, reuseaddr)
38 }
39
40 pub fn reuseaddr(&self) -> std::io::Result<bool> {
42 opt::flag(self.raw(), opt::SOL_SOCKET, opt::SO_REUSEADDR)
43 }
44
45 #[cfg(all(unix, not(any(target_os = "solaris", target_os = "illumos"))))]
48 pub fn set_reuseport(&self, reuseport: bool) -> std::io::Result<()> {
49 opt::set_flag(self.raw(), opt::SOL_SOCKET, opt::SO_REUSEPORT, reuseport)
50 }
51
52 #[cfg(all(unix, not(any(target_os = "solaris", target_os = "illumos"))))]
54 pub fn reuseport(&self) -> std::io::Result<bool> {
55 opt::flag(self.raw(), opt::SOL_SOCKET, opt::SO_REUSEPORT)
56 }
57
58 pub fn set_send_buffer_size(&self, size: u32) -> std::io::Result<()> {
61 opt::set_size(self.raw(), opt::SOL_SOCKET, opt::SO_SNDBUF, size)
62 }
63
64 pub fn send_buffer_size(&self) -> std::io::Result<u32> {
66 opt::size(self.raw(), opt::SOL_SOCKET, opt::SO_SNDBUF)
67 }
68
69 pub fn set_recv_buffer_size(&self, size: u32) -> std::io::Result<()> {
72 opt::set_size(self.raw(), opt::SOL_SOCKET, opt::SO_RCVBUF, size)
73 }
74
75 pub fn recv_buffer_size(&self) -> std::io::Result<u32> {
77 opt::size(self.raw(), opt::SOL_SOCKET, opt::SO_RCVBUF)
78 }
79
80 pub fn set_tos(&self, tos: u32) -> std::io::Result<()> {
82 let tos = opt::int(u64::from(tos), "type of service")?;
83 opt::set(self.raw(), opt::IPPROTO_IP, opt::IP_TOS, tos)
84 }
85
86 pub fn tos(&self) -> std::io::Result<u32> {
88 opt::size(self.raw(), opt::IPPROTO_IP, opt::IP_TOS)
89 }
90
91 #[cfg(unix)]
93 pub fn set_tclass_v6(&self, tclass: u32) -> std::io::Result<()> {
94 let tclass = opt::int(u64::from(tclass), "traffic class")?;
95 opt::set(self.raw(), opt::IPPROTO_IPV6, opt::IPV6_TCLASS, tclass)
96 }
97
98 #[cfg(unix)]
100 pub fn tclass_v6(&self) -> std::io::Result<u32> {
101 opt::size(self.raw(), opt::IPPROTO_IPV6, opt::IPV6_TCLASS)
102 }
103
104 pub fn set_only_v6(&self, only_v6: bool) -> std::io::Result<()> {
112 opt::set_flag(self.raw(), opt::IPPROTO_IPV6, opt::IPV6_V6ONLY, only_v6)
113 }
114
115 pub fn only_v6(&self) -> std::io::Result<bool> {
121 opt::flag(self.raw(), opt::IPPROTO_IPV6, opt::IPV6_V6ONLY)
122 }
123
124 #[cfg(any(target_os = "linux", target_os = "android"))]
127 pub fn bind_device(&self, interface: Option<&[u8]>) -> std::io::Result<()> {
128 let name = interface.unwrap_or_default();
129 unsafe {
131 opt::set_raw(
132 self.raw(),
133 opt::SOL_SOCKET,
134 libc::SO_BINDTODEVICE,
135 name.as_ptr(),
136 name.len(),
137 )
138 }
139 }
140
141 #[cfg(any(target_os = "linux", target_os = "android"))]
144 pub fn device(&self) -> std::io::Result<Option<super::DeviceName>> {
145 let mut name = super::DeviceName {
146 bytes: [0; libc::IFNAMSIZ],
147 len: 0,
148 };
149 let len = unsafe {
151 opt::get_raw(
152 self.raw(),
153 opt::SOL_SOCKET,
154 libc::SO_BINDTODEVICE,
155 name.bytes.as_mut_ptr(),
156 name.bytes.len(),
157 )?
158 };
159 let len = name.bytes[..len.min(name.bytes.len())]
161 .iter()
162 .position(|&b| b == 0)
163 .unwrap_or(len.min(name.bytes.len()));
164 name.len = len as u8;
165 Ok((len > 0).then_some(name))
166 }
167 }
168 )*};
169}
170
171pub(super) use socket_options;