1#![allow(unsafe_code, clippy::undocumented_unsafe_blocks)]
7
8use crate::backend::c;
9use crate::backend::conv::{by_mut, c_uint, ret, socklen_t};
10#[cfg(all(target_os = "linux", feature = "time"))]
11use crate::clockid::ClockId;
12use crate::fd::BorrowedFd;
13#[cfg(feature = "alloc")]
14use crate::ffi::CStr;
15use crate::io;
16use crate::net::sockopt::{Ipv4PathMtuDiscovery, Ipv6PathMtuDiscovery, Timeout};
17#[cfg(target_os = "linux")]
18use crate::net::xdp::{XdpMmapOffsets, XdpOptionsFlags, XdpRingOffset, XdpStatistics, XdpUmemReg};
19#[cfg(all(target_os = "linux", feature = "time"))]
20use crate::net::TxTimeFlags;
21use crate::net::{
22 AddressFamily, Ipv4Addr, Ipv6Addr, Protocol, RawProtocol, SocketAddrBuf, SocketAddrV4,
23 SocketAddrV6, SocketType, UCred,
24};
25#[cfg(feature = "alloc")]
26use alloc::borrow::ToOwned as _;
27#[cfg(feature = "alloc")]
28use alloc::string::String;
29use core::mem::{size_of, MaybeUninit};
30use core::time::Duration;
31use linux_raw_sys::general::{__kernel_old_timeval, __kernel_sock_timeval};
32use linux_raw_sys::net::{
33 IPV6_MTU, IPV6_MTU_DISCOVER, IPV6_MULTICAST_IF, IP_MTU, IP_MTU_DISCOVER, IP_MULTICAST_IF,
34};
35#[cfg(target_os = "linux")]
36use linux_raw_sys::xdp::{xdp_mmap_offsets, xdp_statistics, xdp_statistics_v1};
37#[cfg(target_arch = "x86")]
38use {
39 crate::backend::conv::{slice_just_addr, x86_sys},
40 crate::backend::reg::{ArgReg, SocketArg},
41 linux_raw_sys::net::{SYS_GETSOCKOPT, SYS_SETSOCKOPT},
42};
43
44#[inline]
45fn getsockopt<T: Copy>(fd: BorrowedFd<'_>, level: u32, optname: u32) -> io::Result<T> {
46 let mut optlen: c::socklen_t = size_of::<T>().try_into().unwrap();
47 debug_assert!(
48 optlen as usize >= size_of::<c::c_int>(),
49 "Socket APIs don't ever use `bool` directly"
50 );
51
52 let mut value = MaybeUninit::<T>::uninit();
53 getsockopt_raw(fd, level, optname, &mut value, &mut optlen)?;
54
55 assert_eq!(
56 optlen as usize,
57 size_of::<T>(),
58 "unexpected getsockopt size"
59 );
60
61 unsafe { Ok(value.assume_init()) }
62}
63
64#[inline]
65fn getsockopt_raw<T>(
66 fd: BorrowedFd<'_>,
67 level: u32,
68 optname: u32,
69 value: &mut MaybeUninit<T>,
70 optlen: &mut c::socklen_t,
71) -> io::Result<()> {
72 #[cfg(not(target_arch = "x86"))]
73 unsafe {
74 ret(syscall!(
75 __NR_getsockopt,
76 fd,
77 c_uint(level),
78 c_uint(optname),
79 value,
80 by_mut(optlen)
81 ))
82 }
83 #[cfg(target_arch = "x86")]
84 unsafe {
85 ret(syscall!(
86 __NR_socketcall,
87 x86_sys(SYS_GETSOCKOPT),
88 slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
89 fd.into(),
90 c_uint(level),
91 c_uint(optname),
92 value.into(),
93 by_mut(optlen),
94 ])
95 ))
96 }
97}
98
99#[inline]
100fn setsockopt<T: Copy>(fd: BorrowedFd<'_>, level: u32, optname: u32, value: T) -> io::Result<()> {
101 let optlen = size_of::<T>().try_into().unwrap();
102 debug_assert!(
103 optlen as usize >= size_of::<c::c_int>(),
104 "Socket APIs don't ever use `bool` directly"
105 );
106 setsockopt_raw(fd, level, optname, &value, optlen)
107}
108
109#[inline]
110fn setsockopt_raw<T>(
111 fd: BorrowedFd<'_>,
112 level: u32,
113 optname: u32,
114 ptr: *const T,
115 optlen: c::socklen_t,
116) -> io::Result<()> {
117 #[cfg(not(target_arch = "x86"))]
118 unsafe {
119 ret(syscall_readonly!(
120 __NR_setsockopt,
121 fd,
122 c_uint(level),
123 c_uint(optname),
124 ptr,
125 socklen_t(optlen)
126 ))
127 }
128 #[cfg(target_arch = "x86")]
129 unsafe {
130 ret(syscall_readonly!(
131 __NR_socketcall,
132 x86_sys(SYS_SETSOCKOPT),
133 slice_just_addr::<ArgReg<'_, SocketArg>, _>(&[
134 fd.into(),
135 c_uint(level),
136 c_uint(optname),
137 ptr.into(),
138 socklen_t(optlen),
139 ])
140 ))
141 }
142}
143
144#[inline]
145pub(crate) fn socket_type(fd: BorrowedFd<'_>) -> io::Result<SocketType> {
146 getsockopt(fd, c::SOL_SOCKET, c::SO_TYPE)
147}
148
149#[inline]
150pub(crate) fn set_socket_reuseaddr(fd: BorrowedFd<'_>, reuseaddr: bool) -> io::Result<()> {
151 setsockopt(fd, c::SOL_SOCKET, c::SO_REUSEADDR, from_bool(reuseaddr))
152}
153
154#[inline]
155pub(crate) fn socket_reuseaddr(fd: BorrowedFd<'_>) -> io::Result<bool> {
156 getsockopt(fd, c::SOL_SOCKET, c::SO_REUSEADDR).map(to_bool)
157}
158
159#[inline]
160pub(crate) fn set_socket_broadcast(fd: BorrowedFd<'_>, broadcast: bool) -> io::Result<()> {
161 setsockopt(fd, c::SOL_SOCKET, c::SO_BROADCAST, from_bool(broadcast))
162}
163
164#[inline]
165pub(crate) fn socket_broadcast(fd: BorrowedFd<'_>) -> io::Result<bool> {
166 getsockopt(fd, c::SOL_SOCKET, c::SO_BROADCAST).map(to_bool)
167}
168
169#[inline]
170pub(crate) fn set_socket_linger(fd: BorrowedFd<'_>, linger: Option<Duration>) -> io::Result<()> {
171 let l_linger = if let Some(linger) = linger {
173 duration_to_secs(linger)?
174 } else {
175 0
176 };
177 let linger = c::linger {
178 l_onoff: c::c_int::from(linger.is_some()),
179 l_linger,
180 };
181 setsockopt(fd, c::SOL_SOCKET, c::SO_LINGER, linger)
182}
183
184#[inline]
185pub(crate) fn socket_linger(fd: BorrowedFd<'_>) -> io::Result<Option<Duration>> {
186 let linger: c::linger = getsockopt(fd, c::SOL_SOCKET, c::SO_LINGER)?;
187 Ok((linger.l_onoff != 0).then(|| Duration::from_secs(linger.l_linger as u64)))
188}
189
190#[inline]
191pub(crate) fn set_socket_passcred(fd: BorrowedFd<'_>, passcred: bool) -> io::Result<()> {
192 setsockopt(fd, c::SOL_SOCKET, c::SO_PASSCRED, from_bool(passcred))
193}
194
195#[inline]
196pub(crate) fn socket_passcred(fd: BorrowedFd<'_>) -> io::Result<bool> {
197 getsockopt(fd, c::SOL_SOCKET, c::SO_PASSCRED).map(to_bool)
198}
199
200#[inline]
201pub(crate) fn set_socket_timeout(
202 fd: BorrowedFd<'_>,
203 id: Timeout,
204 timeout: Option<Duration>,
205) -> io::Result<()> {
206 let time = duration_to_linux_sock_timeval(timeout)?;
207 let optname = match id {
208 Timeout::Recv => c::SO_RCVTIMEO_NEW,
209 Timeout::Send => c::SO_SNDTIMEO_NEW,
210 };
211 match setsockopt(fd, c::SOL_SOCKET, optname, time) {
212 Err(io::Errno::NOPROTOOPT) if c::SO_RCVTIMEO_NEW != c::SO_RCVTIMEO_OLD => {
213 set_socket_timeout_old(fd, id, timeout)
214 }
215 otherwise => otherwise,
216 }
217}
218
219fn set_socket_timeout_old(
222 fd: BorrowedFd<'_>,
223 id: Timeout,
224 timeout: Option<Duration>,
225) -> io::Result<()> {
226 let time = duration_to_linux_old_timeval(timeout)?;
227 let optname = match id {
228 Timeout::Recv => c::SO_RCVTIMEO_OLD,
229 Timeout::Send => c::SO_SNDTIMEO_OLD,
230 };
231 setsockopt(fd, c::SOL_SOCKET, optname, time)
232}
233
234#[inline]
235pub(crate) fn socket_timeout(fd: BorrowedFd<'_>, id: Timeout) -> io::Result<Option<Duration>> {
236 let optname = match id {
237 Timeout::Recv => c::SO_RCVTIMEO_NEW,
238 Timeout::Send => c::SO_SNDTIMEO_NEW,
239 };
240 let time: __kernel_sock_timeval = match getsockopt(fd, c::SOL_SOCKET, optname) {
241 Err(io::Errno::NOPROTOOPT) if c::SO_RCVTIMEO_NEW != c::SO_RCVTIMEO_OLD => {
242 return socket_timeout_old(fd, id)
243 }
244 otherwise => otherwise?,
245 };
246 Ok(duration_from_linux_sock_timeval(time))
247}
248
249fn socket_timeout_old(fd: BorrowedFd<'_>, id: Timeout) -> io::Result<Option<Duration>> {
252 let optname = match id {
253 Timeout::Recv => c::SO_RCVTIMEO_OLD,
254 Timeout::Send => c::SO_SNDTIMEO_OLD,
255 };
256 let time: __kernel_old_timeval = getsockopt(fd, c::SOL_SOCKET, optname)?;
257 Ok(duration_from_linux_old_timeval(time))
258}
259
260#[inline]
262fn duration_from_linux_sock_timeval(time: __kernel_sock_timeval) -> Option<Duration> {
263 if time.tv_sec == 0 && time.tv_usec == 0 {
264 None
265 } else {
266 Some(Duration::from_secs(time.tv_sec as u64) + Duration::from_micros(time.tv_usec as u64))
267 }
268}
269
270fn duration_from_linux_old_timeval(time: __kernel_old_timeval) -> Option<Duration> {
273 if time.tv_sec == 0 && time.tv_usec == 0 {
274 None
275 } else {
276 Some(Duration::from_secs(time.tv_sec as u64) + Duration::from_micros(time.tv_usec as u64))
277 }
278}
279
280#[inline]
282fn duration_to_linux_sock_timeval(timeout: Option<Duration>) -> io::Result<__kernel_sock_timeval> {
283 Ok(match timeout {
284 Some(timeout) => {
285 if timeout == Duration::ZERO {
286 return Err(io::Errno::INVAL);
287 }
288 let mut timeout = __kernel_sock_timeval {
291 tv_sec: timeout.as_secs().try_into().unwrap_or(i64::MAX),
292 tv_usec: ((timeout.subsec_nanos() + 999) / 1000) as _,
293 };
294 if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
295 timeout.tv_usec = 1;
296 }
297 timeout
298 }
299 None => __kernel_sock_timeval {
300 tv_sec: 0,
301 tv_usec: 0,
302 },
303 })
304}
305
306fn duration_to_linux_old_timeval(timeout: Option<Duration>) -> io::Result<__kernel_old_timeval> {
309 Ok(match timeout {
310 Some(timeout) => {
311 if timeout == Duration::ZERO {
312 return Err(io::Errno::INVAL);
313 }
314
315 let mut timeout = __kernel_old_timeval {
318 tv_sec: timeout.as_secs().try_into().unwrap_or(c::c_long::MAX),
319 tv_usec: ((timeout.subsec_nanos() + 999) / 1000) as _,
320 };
321 if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
322 timeout.tv_usec = 1;
323 }
324 timeout
325 }
326 None => __kernel_old_timeval {
327 tv_sec: 0,
328 tv_usec: 0,
329 },
330 })
331}
332
333#[inline]
334pub(crate) fn socket_error(fd: BorrowedFd<'_>) -> io::Result<Result<(), io::Errno>> {
335 let err: c::c_int = getsockopt(fd, c::SOL_SOCKET, c::SO_ERROR)?;
336 Ok(if err == 0 {
337 Ok(())
338 } else {
339 Err(io::Errno::from_raw_os_error(err))
340 })
341}
342
343#[inline]
344pub(crate) fn set_socket_keepalive(fd: BorrowedFd<'_>, keepalive: bool) -> io::Result<()> {
345 setsockopt(fd, c::SOL_SOCKET, c::SO_KEEPALIVE, from_bool(keepalive))
346}
347
348#[inline]
349pub(crate) fn socket_keepalive(fd: BorrowedFd<'_>) -> io::Result<bool> {
350 getsockopt(fd, c::SOL_SOCKET, c::SO_KEEPALIVE).map(to_bool)
351}
352
353#[inline]
354pub(crate) fn set_socket_recv_buffer_size(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> {
355 let size: c::c_int = size.try_into().map_err(|_| io::Errno::INVAL)?;
356 setsockopt(fd, c::SOL_SOCKET, c::SO_RCVBUF, size)
357}
358
359#[inline]
360pub(crate) fn set_socket_recv_buffer_size_force(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> {
361 let size: c::c_int = size.try_into().map_err(|_| io::Errno::INVAL)?;
362 setsockopt(fd, c::SOL_SOCKET, c::SO_RCVBUFFORCE, size)
363}
364
365#[inline]
366pub(crate) fn socket_recv_buffer_size(fd: BorrowedFd<'_>) -> io::Result<usize> {
367 getsockopt(fd, c::SOL_SOCKET, c::SO_RCVBUF).map(|size: u32| size as usize)
368}
369
370#[inline]
371pub(crate) fn set_socket_send_buffer_size(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> {
372 let size: c::c_int = size.try_into().map_err(|_| io::Errno::INVAL)?;
373 setsockopt(fd, c::SOL_SOCKET, c::SO_SNDBUF, size)
374}
375
376#[inline]
377pub(crate) fn set_socket_send_buffer_size_force(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> {
378 let size: c::c_int = size.try_into().map_err(|_| io::Errno::INVAL)?;
379 setsockopt(fd, c::SOL_SOCKET, c::SO_SNDBUFFORCE, size)
380}
381
382#[inline]
383pub(crate) fn socket_send_buffer_size(fd: BorrowedFd<'_>) -> io::Result<usize> {
384 getsockopt(fd, c::SOL_SOCKET, c::SO_SNDBUF).map(|size: u32| size as usize)
385}
386
387#[inline]
388pub(crate) fn socket_domain(fd: BorrowedFd<'_>) -> io::Result<AddressFamily> {
389 let domain: c::c_int = getsockopt(fd, c::SOL_SOCKET, c::SO_DOMAIN)?;
390 Ok(AddressFamily(
391 domain.try_into().map_err(|_| io::Errno::OPNOTSUPP)?,
392 ))
393}
394
395#[inline]
396pub(crate) fn socket_acceptconn(fd: BorrowedFd<'_>) -> io::Result<bool> {
397 getsockopt(fd, c::SOL_SOCKET, c::SO_ACCEPTCONN).map(to_bool)
398}
399
400#[inline]
401pub(crate) fn set_socket_oobinline(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
402 setsockopt(fd, c::SOL_SOCKET, c::SO_OOBINLINE, from_bool(value))
403}
404
405#[inline]
406pub(crate) fn socket_oobinline(fd: BorrowedFd<'_>) -> io::Result<bool> {
407 getsockopt(fd, c::SOL_SOCKET, c::SO_OOBINLINE).map(to_bool)
408}
409
410#[inline]
411pub(crate) fn set_socket_reuseport(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
412 setsockopt(fd, c::SOL_SOCKET, c::SO_REUSEPORT, from_bool(value))
413}
414
415#[inline]
416pub(crate) fn socket_reuseport(fd: BorrowedFd<'_>) -> io::Result<bool> {
417 getsockopt(fd, c::SOL_SOCKET, c::SO_REUSEPORT).map(to_bool)
418}
419
420#[inline]
421pub(crate) fn socket_protocol(fd: BorrowedFd<'_>) -> io::Result<Option<Protocol>> {
422 getsockopt(fd, c::SOL_SOCKET, c::SO_PROTOCOL)
423 .map(|raw: u32| RawProtocol::new(raw).map(Protocol::from_raw))
424}
425
426#[inline]
427pub(crate) fn socket_cookie(fd: BorrowedFd<'_>) -> io::Result<u64> {
428 getsockopt(fd, c::SOL_SOCKET, c::SO_COOKIE)
429}
430
431#[inline]
432pub(crate) fn socket_incoming_cpu(fd: BorrowedFd<'_>) -> io::Result<u32> {
433 getsockopt(fd, c::SOL_SOCKET, c::SO_INCOMING_CPU)
434}
435
436#[inline]
437pub(crate) fn set_socket_incoming_cpu(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
438 setsockopt(fd, c::SOL_SOCKET, c::SO_INCOMING_CPU, value)
439}
440
441#[inline]
442pub(crate) fn set_ip_ttl(fd: BorrowedFd<'_>, ttl: u32) -> io::Result<()> {
443 setsockopt(fd, c::IPPROTO_IP, c::IP_TTL, ttl)
444}
445
446#[inline]
447pub(crate) fn ip_ttl(fd: BorrowedFd<'_>) -> io::Result<u32> {
448 getsockopt(fd, c::IPPROTO_IP, c::IP_TTL)
449}
450
451#[inline]
452pub(crate) fn set_ipv6_v6only(fd: BorrowedFd<'_>, only_v6: bool) -> io::Result<()> {
453 setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_V6ONLY, from_bool(only_v6))
454}
455
456#[inline]
457pub(crate) fn ipv6_v6only(fd: BorrowedFd<'_>) -> io::Result<bool> {
458 getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_V6ONLY).map(to_bool)
459}
460
461#[inline]
462pub(crate) fn ip_mtu(fd: BorrowedFd<'_>) -> io::Result<u32> {
463 getsockopt(fd, c::IPPROTO_IP, IP_MTU)
464}
465
466#[inline]
467pub(crate) fn ipv6_mtu(fd: BorrowedFd<'_>) -> io::Result<u32> {
468 getsockopt(fd, c::IPPROTO_IPV6, IPV6_MTU)
469}
470
471#[inline]
472pub(crate) fn set_ip_mtu_discover(
473 fd: BorrowedFd<'_>,
474 value: Ipv4PathMtuDiscovery,
475) -> io::Result<()> {
476 setsockopt(fd, c::IPPROTO_IP, IP_MTU_DISCOVER, value)
477}
478
479#[inline]
480pub(crate) fn ip_mtu_discover(fd: BorrowedFd<'_>) -> io::Result<Ipv4PathMtuDiscovery> {
481 getsockopt(fd, c::IPPROTO_IP, IP_MTU_DISCOVER)
482}
483
484#[inline]
485pub(crate) fn set_ipv6_mtu_discover(
486 fd: BorrowedFd<'_>,
487 value: Ipv6PathMtuDiscovery,
488) -> io::Result<()> {
489 setsockopt(fd, c::IPPROTO_IPV6, IPV6_MTU_DISCOVER, value)
490}
491
492#[inline]
493pub(crate) fn ipv6_mtu_discover(fd: BorrowedFd<'_>) -> io::Result<Ipv6PathMtuDiscovery> {
494 getsockopt(fd, c::IPPROTO_IPV6, IPV6_MTU_DISCOVER)
495}
496
497#[inline]
498pub(crate) fn set_ip_multicast_if_with_ifindex(
499 fd: BorrowedFd<'_>,
500 multiaddr: &Ipv4Addr,
501 address: &Ipv4Addr,
502 ifindex: u32,
503) -> io::Result<()> {
504 let mreqn = to_ip_mreqn(multiaddr, address, ifindex as i32);
505 setsockopt(fd, c::IPPROTO_IP, IP_MULTICAST_IF, mreqn)
506}
507
508#[inline]
509pub(crate) fn set_ip_multicast_if(fd: BorrowedFd<'_>, value: &Ipv4Addr) -> io::Result<()> {
510 setsockopt(fd, c::IPPROTO_IP, IP_MULTICAST_IF, to_imr_addr(value))
511}
512
513#[inline]
514pub(crate) fn ip_multicast_if(fd: BorrowedFd<'_>) -> io::Result<Ipv4Addr> {
515 getsockopt(fd, c::IPPROTO_IP, IP_MULTICAST_IF).map(from_in_addr)
516}
517
518#[inline]
519pub(crate) fn set_ipv6_multicast_if(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
520 setsockopt(fd, c::IPPROTO_IPV6, IPV6_MULTICAST_IF, value as c::c_int)
521}
522
523#[inline]
524pub(crate) fn ipv6_multicast_if(fd: BorrowedFd<'_>) -> io::Result<u32> {
525 getsockopt(fd, c::IPPROTO_IPV6, IPV6_MULTICAST_IF)
526}
527
528#[inline]
529pub(crate) fn set_ip_multicast_loop(fd: BorrowedFd<'_>, multicast_loop: bool) -> io::Result<()> {
530 setsockopt(
531 fd,
532 c::IPPROTO_IP,
533 c::IP_MULTICAST_LOOP,
534 from_bool(multicast_loop),
535 )
536}
537
538#[inline]
539pub(crate) fn ip_multicast_loop(fd: BorrowedFd<'_>) -> io::Result<bool> {
540 getsockopt(fd, c::IPPROTO_IP, c::IP_MULTICAST_LOOP).map(to_bool)
541}
542
543#[inline]
544pub(crate) fn set_ip_multicast_ttl(fd: BorrowedFd<'_>, multicast_ttl: u32) -> io::Result<()> {
545 setsockopt(fd, c::IPPROTO_IP, c::IP_MULTICAST_TTL, multicast_ttl)
546}
547
548#[inline]
549pub(crate) fn ip_multicast_ttl(fd: BorrowedFd<'_>) -> io::Result<u32> {
550 getsockopt(fd, c::IPPROTO_IP, c::IP_MULTICAST_TTL)
551}
552
553#[inline]
554pub(crate) fn set_ipv6_multicast_loop(fd: BorrowedFd<'_>, multicast_loop: bool) -> io::Result<()> {
555 setsockopt(
556 fd,
557 c::IPPROTO_IPV6,
558 c::IPV6_MULTICAST_LOOP,
559 from_bool(multicast_loop),
560 )
561}
562
563#[inline]
564pub(crate) fn ipv6_multicast_loop(fd: BorrowedFd<'_>) -> io::Result<bool> {
565 getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_MULTICAST_LOOP).map(to_bool)
566}
567
568#[inline]
569pub(crate) fn set_ipv6_multicast_hops(fd: BorrowedFd<'_>, multicast_hops: u32) -> io::Result<()> {
570 setsockopt(fd, c::IPPROTO_IP, c::IPV6_MULTICAST_HOPS, multicast_hops)
571}
572
573#[inline]
574pub(crate) fn ipv6_multicast_hops(fd: BorrowedFd<'_>) -> io::Result<u32> {
575 getsockopt(fd, c::IPPROTO_IP, c::IPV6_MULTICAST_HOPS)
576}
577
578#[inline]
579pub(crate) fn set_ip_add_membership(
580 fd: BorrowedFd<'_>,
581 multiaddr: &Ipv4Addr,
582 interface: &Ipv4Addr,
583) -> io::Result<()> {
584 let mreq = to_ip_mreq(multiaddr, interface);
585 setsockopt(fd, c::IPPROTO_IP, c::IP_ADD_MEMBERSHIP, mreq)
586}
587
588#[inline]
589pub(crate) fn set_ip_add_membership_with_ifindex(
590 fd: BorrowedFd<'_>,
591 multiaddr: &Ipv4Addr,
592 address: &Ipv4Addr,
593 ifindex: u32,
594) -> io::Result<()> {
595 let mreqn = to_ip_mreqn(multiaddr, address, ifindex as i32);
596 setsockopt(fd, c::IPPROTO_IP, c::IP_ADD_MEMBERSHIP, mreqn)
597}
598
599#[inline]
600pub(crate) fn set_ip_add_source_membership(
601 fd: BorrowedFd<'_>,
602 multiaddr: &Ipv4Addr,
603 interface: &Ipv4Addr,
604 sourceaddr: &Ipv4Addr,
605) -> io::Result<()> {
606 let mreq_source = to_imr_source(multiaddr, interface, sourceaddr);
607 setsockopt(fd, c::IPPROTO_IP, c::IP_ADD_SOURCE_MEMBERSHIP, mreq_source)
608}
609
610#[inline]
611pub(crate) fn set_ip_drop_source_membership(
612 fd: BorrowedFd<'_>,
613 multiaddr: &Ipv4Addr,
614 interface: &Ipv4Addr,
615 sourceaddr: &Ipv4Addr,
616) -> io::Result<()> {
617 let mreq_source = to_imr_source(multiaddr, interface, sourceaddr);
618 setsockopt(fd, c::IPPROTO_IP, c::IP_DROP_SOURCE_MEMBERSHIP, mreq_source)
619}
620
621#[inline]
622pub(crate) fn set_ipv6_add_membership(
623 fd: BorrowedFd<'_>,
624 multiaddr: &Ipv6Addr,
625 interface: u32,
626) -> io::Result<()> {
627 let mreq = to_ipv6mr(multiaddr, interface);
628 setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_ADD_MEMBERSHIP, mreq)
629}
630
631#[inline]
632pub(crate) fn set_ip_drop_membership(
633 fd: BorrowedFd<'_>,
634 multiaddr: &Ipv4Addr,
635 interface: &Ipv4Addr,
636) -> io::Result<()> {
637 let mreq = to_ip_mreq(multiaddr, interface);
638 setsockopt(fd, c::IPPROTO_IP, c::IP_DROP_MEMBERSHIP, mreq)
639}
640
641#[inline]
642pub(crate) fn set_ip_drop_membership_with_ifindex(
643 fd: BorrowedFd<'_>,
644 multiaddr: &Ipv4Addr,
645 address: &Ipv4Addr,
646 ifindex: u32,
647) -> io::Result<()> {
648 let mreqn = to_ip_mreqn(multiaddr, address, ifindex as i32);
649 setsockopt(fd, c::IPPROTO_IP, c::IP_DROP_MEMBERSHIP, mreqn)
650}
651
652#[inline]
653pub(crate) fn set_ipv6_drop_membership(
654 fd: BorrowedFd<'_>,
655 multiaddr: &Ipv6Addr,
656 interface: u32,
657) -> io::Result<()> {
658 let mreq = to_ipv6mr(multiaddr, interface);
659 setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_DROP_MEMBERSHIP, mreq)
660}
661
662#[inline]
663pub(crate) fn ipv6_unicast_hops(fd: BorrowedFd<'_>) -> io::Result<u8> {
664 getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS).map(|hops: c::c_int| hops as u8)
665}
666
667#[inline]
668pub(crate) fn set_ipv6_unicast_hops(fd: BorrowedFd<'_>, hops: Option<u8>) -> io::Result<()> {
669 let hops = match hops {
670 Some(hops) => hops.into(),
671 None => -1,
672 };
673 setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_UNICAST_HOPS, hops)
674}
675
676#[inline]
677pub(crate) fn set_ip_tos(fd: BorrowedFd<'_>, value: u8) -> io::Result<()> {
678 setsockopt(fd, c::IPPROTO_IP, c::IP_TOS, i32::from(value))
679}
680
681#[inline]
682pub(crate) fn ip_tos(fd: BorrowedFd<'_>) -> io::Result<u8> {
683 let value: i32 = getsockopt(fd, c::IPPROTO_IP, c::IP_TOS)?;
684 Ok(value as u8)
685}
686
687#[inline]
688pub(crate) fn set_ip_recvtos(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
689 setsockopt(fd, c::IPPROTO_IP, c::IP_RECVTOS, from_bool(value))
690}
691
692#[inline]
693pub(crate) fn ip_recvtos(fd: BorrowedFd<'_>) -> io::Result<bool> {
694 getsockopt(fd, c::IPPROTO_IP, c::IP_RECVTOS).map(to_bool)
695}
696
697#[inline]
698pub(crate) fn set_ipv6_recvtclass(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
699 setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_RECVTCLASS, from_bool(value))
700}
701
702#[inline]
703pub(crate) fn ipv6_recvtclass(fd: BorrowedFd<'_>) -> io::Result<bool> {
704 getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_RECVTCLASS).map(to_bool)
705}
706
707#[inline]
708pub(crate) fn set_ip_freebind(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
709 setsockopt(fd, c::IPPROTO_IP, c::IP_FREEBIND, from_bool(value))
710}
711
712#[inline]
713pub(crate) fn ip_freebind(fd: BorrowedFd<'_>) -> io::Result<bool> {
714 getsockopt(fd, c::IPPROTO_IP, c::IP_FREEBIND).map(to_bool)
715}
716
717#[inline]
718pub(crate) fn set_ipv6_freebind(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
719 setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_FREEBIND, from_bool(value))
720}
721
722#[inline]
723pub(crate) fn ipv6_freebind(fd: BorrowedFd<'_>) -> io::Result<bool> {
724 getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_FREEBIND).map(to_bool)
725}
726
727#[inline]
728pub(crate) fn ip_original_dst(fd: BorrowedFd<'_>) -> io::Result<SocketAddrV4> {
729 let level = c::IPPROTO_IP;
730 let optname = c::SO_ORIGINAL_DST;
731 let mut addr = SocketAddrBuf::new();
732
733 getsockopt_raw(fd, level, optname, &mut addr.storage, &mut addr.len)?;
734
735 Ok(unsafe { addr.into_any() }.try_into().unwrap())
736}
737
738#[inline]
739pub(crate) fn ipv6_original_dst(fd: BorrowedFd<'_>) -> io::Result<SocketAddrV6> {
740 let level = c::IPPROTO_IPV6;
741 let optname = c::IP6T_SO_ORIGINAL_DST;
742 let mut addr = SocketAddrBuf::new();
743
744 getsockopt_raw(fd, level, optname, &mut addr.storage, &mut addr.len)?;
745
746 Ok(unsafe { addr.into_any() }.try_into().unwrap())
747}
748
749#[inline]
750pub(crate) fn set_ipv6_tclass(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
751 setsockopt(fd, c::IPPROTO_IPV6, c::IPV6_TCLASS, value)
752}
753
754#[inline]
755pub(crate) fn ipv6_tclass(fd: BorrowedFd<'_>) -> io::Result<u32> {
756 getsockopt(fd, c::IPPROTO_IPV6, c::IPV6_TCLASS)
757}
758
759#[inline]
760pub(crate) fn set_tcp_nodelay(fd: BorrowedFd<'_>, nodelay: bool) -> io::Result<()> {
761 setsockopt(fd, c::IPPROTO_TCP, c::TCP_NODELAY, from_bool(nodelay))
762}
763
764#[inline]
765pub(crate) fn tcp_nodelay(fd: BorrowedFd<'_>) -> io::Result<bool> {
766 getsockopt(fd, c::IPPROTO_TCP, c::TCP_NODELAY).map(to_bool)
767}
768
769#[inline]
770pub(crate) fn set_tcp_keepcnt(fd: BorrowedFd<'_>, count: u32) -> io::Result<()> {
771 setsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPCNT, count)
772}
773
774#[inline]
775pub(crate) fn tcp_keepcnt(fd: BorrowedFd<'_>) -> io::Result<u32> {
776 getsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPCNT)
777}
778
779#[inline]
780pub(crate) fn set_tcp_keepidle(fd: BorrowedFd<'_>, duration: Duration) -> io::Result<()> {
781 let secs: c::c_uint = duration_to_secs(duration)?;
782 setsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPIDLE, secs)
783}
784
785#[inline]
786pub(crate) fn tcp_keepidle(fd: BorrowedFd<'_>) -> io::Result<Duration> {
787 let secs: c::c_uint = getsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPIDLE)?;
788 Ok(Duration::from_secs(secs.into()))
789}
790
791#[inline]
792pub(crate) fn set_tcp_keepintvl(fd: BorrowedFd<'_>, duration: Duration) -> io::Result<()> {
793 let secs: c::c_uint = duration_to_secs(duration)?;
794 setsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPINTVL, secs)
795}
796
797#[inline]
798pub(crate) fn tcp_keepintvl(fd: BorrowedFd<'_>) -> io::Result<Duration> {
799 let secs: c::c_uint = getsockopt(fd, c::IPPROTO_TCP, c::TCP_KEEPINTVL)?;
800 Ok(Duration::from_secs(secs.into()))
801}
802
803#[inline]
804pub(crate) fn set_tcp_user_timeout(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
805 setsockopt(fd, c::IPPROTO_TCP, c::TCP_USER_TIMEOUT, value)
806}
807
808#[inline]
809pub(crate) fn tcp_user_timeout(fd: BorrowedFd<'_>) -> io::Result<u32> {
810 getsockopt(fd, c::IPPROTO_TCP, c::TCP_USER_TIMEOUT)
811}
812
813#[inline]
814pub(crate) fn set_tcp_quickack(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
815 setsockopt(fd, c::IPPROTO_TCP, c::TCP_QUICKACK, from_bool(value))
816}
817
818#[inline]
819pub(crate) fn tcp_quickack(fd: BorrowedFd<'_>) -> io::Result<bool> {
820 getsockopt(fd, c::IPPROTO_TCP, c::TCP_QUICKACK).map(to_bool)
821}
822
823#[inline]
824pub(crate) fn set_tcp_congestion(fd: BorrowedFd<'_>, value: &str) -> io::Result<()> {
825 let level = c::IPPROTO_TCP;
826 let optname = c::TCP_CONGESTION;
827 let optlen = value.len().try_into().unwrap();
828 setsockopt_raw(fd, level, optname, value.as_ptr(), optlen)
829}
830
831#[cfg(feature = "alloc")]
832#[inline]
833pub(crate) fn tcp_congestion(fd: BorrowedFd<'_>) -> io::Result<String> {
834 const OPTLEN: c::socklen_t = 16;
835
836 let level = c::IPPROTO_TCP;
837 let optname = c::TCP_CONGESTION;
838 let mut value = MaybeUninit::<[MaybeUninit<u8>; OPTLEN as usize]>::uninit();
839 let mut optlen = OPTLEN;
840 getsockopt_raw(fd, level, optname, &mut value, &mut optlen)?;
841 unsafe {
842 let value = value.assume_init();
843 let slice: &[u8] = core::mem::transmute(&value[..optlen as usize]);
844 assert!(slice.contains(&b'\0'));
845 Ok(
846 core::str::from_utf8(CStr::from_ptr(slice.as_ptr().cast()).to_bytes())
847 .unwrap()
848 .to_owned(),
849 )
850 }
851}
852
853#[inline]
854pub(crate) fn set_tcp_thin_linear_timeouts(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
855 setsockopt(
856 fd,
857 c::IPPROTO_TCP,
858 c::TCP_THIN_LINEAR_TIMEOUTS,
859 from_bool(value),
860 )
861}
862
863#[inline]
864pub(crate) fn tcp_thin_linear_timeouts(fd: BorrowedFd<'_>) -> io::Result<bool> {
865 getsockopt(fd, c::IPPROTO_TCP, c::TCP_THIN_LINEAR_TIMEOUTS).map(to_bool)
866}
867
868#[inline]
869pub(crate) fn set_tcp_cork(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> {
870 setsockopt(fd, c::IPPROTO_TCP, c::TCP_CORK, from_bool(value))
871}
872
873#[inline]
874pub(crate) fn tcp_cork(fd: BorrowedFd<'_>) -> io::Result<bool> {
875 getsockopt(fd, c::IPPROTO_TCP, c::TCP_CORK).map(to_bool)
876}
877
878#[inline]
879pub(crate) fn socket_peercred(fd: BorrowedFd<'_>) -> io::Result<UCred> {
880 getsockopt(fd, c::SOL_SOCKET, linux_raw_sys::net::SO_PEERCRED)
881}
882
883#[cfg(all(target_os = "linux", feature = "time"))]
884#[inline]
885pub(crate) fn set_txtime(
886 fd: BorrowedFd<'_>,
887 clockid: ClockId,
888 flags: TxTimeFlags,
889) -> io::Result<()> {
890 setsockopt(
891 fd,
892 c::SOL_SOCKET,
893 c::SO_TXTIME,
894 c::sock_txtime {
895 clockid: clockid as _,
896 flags: flags.bits(),
897 },
898 )
899}
900
901#[cfg(all(target_os = "linux", feature = "time"))]
902#[inline]
903pub(crate) fn get_txtime(fd: BorrowedFd<'_>) -> io::Result<(ClockId, TxTimeFlags)> {
904 let txtime: c::sock_txtime = getsockopt(fd, c::SOL_SOCKET, c::SO_TXTIME)?;
905
906 Ok((
907 txtime.clockid.try_into().map_err(|_| io::Errno::RANGE)?,
908 TxTimeFlags::from_bits(txtime.flags).ok_or(io::Errno::RANGE)?,
909 ))
910}
911
912#[cfg(target_os = "linux")]
913#[inline]
914pub(crate) fn set_xdp_umem_reg(fd: BorrowedFd<'_>, value: XdpUmemReg) -> io::Result<()> {
915 setsockopt(fd, c::SOL_XDP, c::XDP_UMEM_REG, value)
916}
917
918#[cfg(target_os = "linux")]
919#[inline]
920pub(crate) fn set_xdp_umem_fill_ring_size(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
921 setsockopt(fd, c::SOL_XDP, c::XDP_UMEM_FILL_RING, value)
922}
923
924#[cfg(target_os = "linux")]
925#[inline]
926pub(crate) fn set_xdp_umem_completion_ring_size(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
927 setsockopt(fd, c::SOL_XDP, c::XDP_UMEM_COMPLETION_RING, value)
928}
929
930#[cfg(target_os = "linux")]
931#[inline]
932pub(crate) fn set_xdp_tx_ring_size(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
933 setsockopt(fd, c::SOL_XDP, c::XDP_TX_RING, value)
934}
935
936#[cfg(target_os = "linux")]
937#[inline]
938pub(crate) fn set_xdp_rx_ring_size(fd: BorrowedFd<'_>, value: u32) -> io::Result<()> {
939 setsockopt(fd, c::SOL_XDP, c::XDP_RX_RING, value)
940}
941
942#[cfg(target_os = "linux")]
943#[inline]
944pub(crate) fn xdp_mmap_offsets(fd: BorrowedFd<'_>) -> io::Result<XdpMmapOffsets> {
945 let mut optlen = size_of::<xdp_mmap_offsets>().try_into().unwrap();
954 debug_assert!(
955 optlen as usize >= size_of::<c::c_int>(),
956 "Socket APIs don't ever use `bool` directly"
957 );
958 let mut value = MaybeUninit::<xdp_mmap_offsets>::zeroed();
959 getsockopt_raw(fd, c::SOL_XDP, c::XDP_MMAP_OFFSETS, &mut value, &mut optlen)?;
960
961 if optlen as usize == size_of::<c::xdp_mmap_offsets_v1>() {
962 let xpd_mmap_offsets = unsafe { value.assume_init() };
965 Ok(XdpMmapOffsets {
966 rx: XdpRingOffset {
967 producer: xpd_mmap_offsets.rx.producer,
968 consumer: xpd_mmap_offsets.rx.consumer,
969 desc: xpd_mmap_offsets.rx.desc,
970 flags: None,
971 },
972 tx: XdpRingOffset {
973 producer: xpd_mmap_offsets.rx.flags,
974 consumer: xpd_mmap_offsets.tx.producer,
975 desc: xpd_mmap_offsets.tx.consumer,
976 flags: None,
977 },
978 fr: XdpRingOffset {
979 producer: xpd_mmap_offsets.tx.desc,
980 consumer: xpd_mmap_offsets.tx.flags,
981 desc: xpd_mmap_offsets.fr.producer,
982 flags: None,
983 },
984 cr: XdpRingOffset {
985 producer: xpd_mmap_offsets.fr.consumer,
986 consumer: xpd_mmap_offsets.fr.desc,
987 desc: xpd_mmap_offsets.fr.flags,
988 flags: None,
989 },
990 })
991 } else {
992 assert_eq!(
993 optlen as usize,
994 size_of::<xdp_mmap_offsets>(),
995 "unexpected getsockopt size"
996 );
997 let xpd_mmap_offsets = unsafe { value.assume_init() };
1000 Ok(XdpMmapOffsets {
1001 rx: XdpRingOffset {
1002 producer: xpd_mmap_offsets.rx.producer,
1003 consumer: xpd_mmap_offsets.rx.consumer,
1004 desc: xpd_mmap_offsets.rx.desc,
1005 flags: Some(xpd_mmap_offsets.rx.flags),
1006 },
1007 tx: XdpRingOffset {
1008 producer: xpd_mmap_offsets.tx.producer,
1009 consumer: xpd_mmap_offsets.tx.consumer,
1010 desc: xpd_mmap_offsets.tx.desc,
1011 flags: Some(xpd_mmap_offsets.tx.flags),
1012 },
1013 fr: XdpRingOffset {
1014 producer: xpd_mmap_offsets.fr.producer,
1015 consumer: xpd_mmap_offsets.fr.consumer,
1016 desc: xpd_mmap_offsets.fr.desc,
1017 flags: Some(xpd_mmap_offsets.fr.flags),
1018 },
1019 cr: XdpRingOffset {
1020 producer: xpd_mmap_offsets.cr.producer,
1021 consumer: xpd_mmap_offsets.cr.consumer,
1022 desc: xpd_mmap_offsets.cr.desc,
1023 flags: Some(xpd_mmap_offsets.cr.flags),
1024 },
1025 })
1026 }
1027}
1028
1029#[cfg(target_os = "linux")]
1030#[inline]
1031pub(crate) fn xdp_statistics(fd: BorrowedFd<'_>) -> io::Result<XdpStatistics> {
1032 let mut optlen = size_of::<xdp_statistics>().try_into().unwrap();
1033 debug_assert!(
1034 optlen as usize >= size_of::<c::c_int>(),
1035 "Socket APIs don't ever use `bool` directly"
1036 );
1037 let mut value = MaybeUninit::<xdp_statistics>::zeroed();
1038 getsockopt_raw(fd, c::SOL_XDP, c::XDP_STATISTICS, &mut value, &mut optlen)?;
1039
1040 if optlen as usize == size_of::<xdp_statistics_v1>() {
1041 let xdp_statistics = unsafe { value.assume_init() };
1044 Ok(XdpStatistics {
1045 rx_dropped: xdp_statistics.rx_dropped,
1046 rx_invalid_descs: xdp_statistics.rx_dropped,
1047 tx_invalid_descs: xdp_statistics.rx_dropped,
1048 rx_ring_full: None,
1049 rx_fill_ring_empty_descs: None,
1050 tx_ring_empty_descs: None,
1051 })
1052 } else {
1053 assert_eq!(
1054 optlen as usize,
1055 size_of::<xdp_statistics>(),
1056 "unexpected getsockopt size"
1057 );
1058 let xdp_statistics = unsafe { value.assume_init() };
1061 Ok(XdpStatistics {
1062 rx_dropped: xdp_statistics.rx_dropped,
1063 rx_invalid_descs: xdp_statistics.rx_invalid_descs,
1064 tx_invalid_descs: xdp_statistics.tx_invalid_descs,
1065 rx_ring_full: Some(xdp_statistics.rx_ring_full),
1066 rx_fill_ring_empty_descs: Some(xdp_statistics.rx_fill_ring_empty_descs),
1067 tx_ring_empty_descs: Some(xdp_statistics.tx_ring_empty_descs),
1068 })
1069 }
1070}
1071
1072#[cfg(target_os = "linux")]
1073#[inline]
1074pub(crate) fn xdp_options(fd: BorrowedFd<'_>) -> io::Result<XdpOptionsFlags> {
1075 getsockopt(fd, c::SOL_XDP, c::XDP_OPTIONS)
1076}
1077
1078#[inline]
1079fn from_in_addr(in_addr: c::in_addr) -> Ipv4Addr {
1080 Ipv4Addr::from(in_addr.s_addr.to_ne_bytes())
1081}
1082
1083#[inline]
1084fn to_ip_mreq(multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> c::ip_mreq {
1085 c::ip_mreq {
1086 imr_multiaddr: to_imr_addr(multiaddr),
1087 imr_interface: to_imr_addr(interface),
1088 }
1089}
1090
1091#[inline]
1092fn to_ip_mreqn(multiaddr: &Ipv4Addr, address: &Ipv4Addr, ifindex: i32) -> c::ip_mreqn {
1093 c::ip_mreqn {
1094 imr_multiaddr: to_imr_addr(multiaddr),
1095 imr_address: to_imr_addr(address),
1096 imr_ifindex: ifindex,
1097 }
1098}
1099
1100#[inline]
1101fn to_imr_source(
1102 multiaddr: &Ipv4Addr,
1103 interface: &Ipv4Addr,
1104 sourceaddr: &Ipv4Addr,
1105) -> c::ip_mreq_source {
1106 c::ip_mreq_source {
1107 imr_multiaddr: to_imr_addr(multiaddr).s_addr,
1108 imr_interface: to_imr_addr(interface).s_addr,
1109 imr_sourceaddr: to_imr_addr(sourceaddr).s_addr,
1110 }
1111}
1112
1113#[inline]
1114fn to_imr_addr(addr: &Ipv4Addr) -> c::in_addr {
1115 c::in_addr {
1116 s_addr: u32::from_ne_bytes(addr.octets()),
1117 }
1118}
1119
1120#[inline]
1121fn to_ipv6mr(multiaddr: &Ipv6Addr, interface: u32) -> c::ipv6_mreq {
1122 c::ipv6_mreq {
1123 ipv6mr_multiaddr: to_ipv6mr_multiaddr(multiaddr),
1124 ipv6mr_ifindex: to_ipv6mr_interface(interface),
1125 }
1126}
1127
1128#[inline]
1129fn to_ipv6mr_multiaddr(multiaddr: &Ipv6Addr) -> c::in6_addr {
1130 c::in6_addr {
1131 in6_u: linux_raw_sys::net::in6_addr__bindgen_ty_1 {
1132 u6_addr8: multiaddr.octets(),
1133 },
1134 }
1135}
1136
1137#[inline]
1138fn to_ipv6mr_interface(interface: u32) -> c::c_int {
1139 interface as c::c_int
1140}
1141
1142#[inline]
1143fn from_bool(value: bool) -> c::c_uint {
1144 c::c_uint::from(value)
1145}
1146
1147#[inline]
1148fn to_bool(value: c::c_uint) -> bool {
1149 value != 0
1150}
1151
1152#[inline]
1154fn duration_to_secs<T: TryFrom<u64>>(duration: Duration) -> io::Result<T> {
1155 let mut secs = duration.as_secs();
1156 if duration.subsec_nanos() != 0 {
1157 secs = secs.checked_add(1).ok_or(io::Errno::INVAL)?;
1158 }
1159 T::try_from(secs).map_err(|_e| io::Errno::INVAL)
1160}