1 //! linux_raw syscalls supporting `rustix::net`.
5 //! See the `rustix::backend` module documentation for details.
7 #![allow(clippy::undocumented_unsafe_blocks)]
10 use super::super::conv
::{
11 by_mut
, by_ref
, c_int
, c_uint
, ret
, ret_owned_fd
, ret_usize
, size_of
, slice
, slice_mut
,
14 use super::read_sockaddr
::{initialize_family_to_unspec, maybe_read_sockaddr_os, read_sockaddr_os}
;
15 use super::send_recv
::{RecvFlags, SendFlags}
;
16 use super::types
::{AcceptFlags, AddressFamily, Protocol, Shutdown, SocketFlags, SocketType}
;
17 use super::write_sockaddr
::{encode_sockaddr_v4, encode_sockaddr_v6}
;
18 use crate::fd
::{BorrowedFd, OwnedFd}
;
20 use crate::net
::{SocketAddrAny, SocketAddrUnix, SocketAddrV4, SocketAddrV6}
;
21 use c
::{sockaddr, sockaddr_in, sockaddr_in6, socklen_t}
;
22 use core
::convert
::TryInto
;
23 use core
::mem
::MaybeUninit
;
24 #[cfg(target_arch = "x86")]
26 super::super::conv
::{slice_just_addr, x86_sys}
,
27 super::super::reg
::{ArgReg, SocketArg}
,
28 linux_raw_sys
::general
::{
29 SYS_ACCEPT
, SYS_ACCEPT4
, SYS_BIND
, SYS_CONNECT
, SYS_GETPEERNAME
, SYS_GETSOCKNAME
,
30 SYS_GETSOCKOPT
, SYS_LISTEN
, SYS_RECV
, SYS_RECVFROM
, SYS_SEND
, SYS_SENDTO
, SYS_SETSOCKOPT
,
31 SYS_SHUTDOWN
, SYS_SOCKET
, SYS_SOCKETPAIR
,
37 family
: AddressFamily
,
40 ) -> io
::Result
<OwnedFd
> {
41 #[cfg(not(target_arch = "x86"))]
43 ret_owned_fd(syscall_readonly
!(__NR_socket
, family
, type_
, protocol
))
45 #[cfg(target_arch = "x86")]
47 ret_owned_fd(syscall_readonly
!(
50 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
60 pub(crate) fn socket_with(
61 family
: AddressFamily
,
65 ) -> io
::Result
<OwnedFd
> {
66 #[cfg(not(target_arch = "x86"))]
68 ret_owned_fd(syscall_readonly
!(
75 #[cfg(target_arch = "x86")]
77 ret_owned_fd(syscall_readonly
!(
80 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
82 (type_
, flags
).into(),
90 pub(crate) fn socketpair(
91 family
: AddressFamily
,
95 ) -> io
::Result
<(OwnedFd
, OwnedFd
)> {
96 #[cfg(not(target_arch = "x86"))]
98 let mut result
= MaybeUninit
::<[OwnedFd
; 2]>::uninit();
106 let [fd0
, fd1
] = result
.assume_init();
109 #[cfg(target_arch = "x86")]
111 let mut result
= MaybeUninit
::<[OwnedFd
; 2]>::uninit();
114 x86_sys(SYS_SOCKETPAIR
),
115 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
117 (type_
, flags
).into(),
119 (&mut result
).into(),
122 let [fd0
, fd1
] = result
.assume_init();
128 pub(crate) fn accept(fd
: BorrowedFd
<'_
>) -> io
::Result
<OwnedFd
> {
129 #[cfg(not(target_arch = "x86"))]
131 let fd
= ret_owned_fd(syscall_readonly
!(__NR_accept
, fd
, zero(), zero()))?
;
134 #[cfg(target_arch = "x86")]
136 let fd
= ret_owned_fd(syscall_readonly
!(
139 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[fd
.into(), zero(), zero()])
146 pub(crate) fn accept_with(fd
: BorrowedFd
<'_
>, flags
: AcceptFlags
) -> io
::Result
<OwnedFd
> {
147 #[cfg(not(target_arch = "x86"))]
149 let fd
= ret_owned_fd(syscall_readonly
!(__NR_accept4
, fd
, zero(), zero(), flags
))?
;
152 #[cfg(target_arch = "x86")]
154 let fd
= ret_owned_fd(syscall_readonly
!(
156 x86_sys(SYS_ACCEPT4
),
157 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[fd
.into(), zero(), zero(), flags
.into()])
164 pub(crate) fn acceptfrom(fd
: BorrowedFd
<'_
>) -> io
::Result
<(OwnedFd
, Option
<SocketAddrAny
>)> {
165 #[cfg(not(target_arch = "x86"))]
167 let mut addrlen
= core
::mem
::size_of
::<sockaddr
>() as socklen_t
;
168 let mut storage
= MaybeUninit
::<sockaddr
>::uninit();
169 let fd
= ret_owned_fd(syscall
!(
177 maybe_read_sockaddr_os(&storage
.assume_init(), addrlen
.try_into().unwrap()),
180 #[cfg(target_arch = "x86")]
182 let mut addrlen
= core
::mem
::size_of
::<sockaddr
>() as socklen_t
;
183 let mut storage
= MaybeUninit
::<sockaddr
>::uninit();
184 let fd
= ret_owned_fd(syscall
!(
187 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
189 (&mut storage
).into(),
190 by_mut(&mut addrlen
),
195 maybe_read_sockaddr_os(&storage
.assume_init(), addrlen
.try_into().unwrap()),
201 pub(crate) fn acceptfrom_with(
204 ) -> io
::Result
<(OwnedFd
, Option
<SocketAddrAny
>)> {
205 #[cfg(not(target_arch = "x86"))]
207 let mut addrlen
= core
::mem
::size_of
::<sockaddr
>() as socklen_t
;
208 let mut storage
= MaybeUninit
::<sockaddr
>::uninit();
209 let fd
= ret_owned_fd(syscall
!(
213 by_mut(&mut addrlen
),
218 maybe_read_sockaddr_os(&storage
.assume_init(), addrlen
.try_into().unwrap()),
221 #[cfg(target_arch = "x86")]
223 let mut addrlen
= core
::mem
::size_of
::<sockaddr
>() as socklen_t
;
224 let mut storage
= MaybeUninit
::<sockaddr
>::uninit();
225 let fd
= ret_owned_fd(syscall
!(
227 x86_sys(SYS_ACCEPT4
),
228 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
230 (&mut storage
).into(),
231 by_mut(&mut addrlen
),
237 maybe_read_sockaddr_os(&storage
.assume_init(), addrlen
.try_into().unwrap()),
243 pub(crate) fn shutdown(fd
: BorrowedFd
<'_
>, how
: Shutdown
) -> io
::Result
<()> {
244 #[cfg(not(target_arch = "x86"))]
246 ret(syscall_readonly
!(
249 c_uint(how
as c
::c_uint
)
252 #[cfg(target_arch = "x86")]
254 ret(syscall_readonly
!(
256 x86_sys(SYS_SHUTDOWN
),
257 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[fd
.into(), c_uint(how
as c
::c_uint
)])
263 pub(crate) fn send(fd
: BorrowedFd
<'_
>, buf
: &[u8], flags
: SendFlags
) -> io
::Result
<usize> {
264 let (buf_addr
, buf_len
) = slice(buf
);
267 target_arch
= "aarch64",
268 target_arch
= "mips64",
269 target_arch
= "riscv64",
271 target_arch
= "x86_64",
274 ret_usize(syscall_readonly
!(__NR_send
, fd
, buf_addr
, buf_len
, flags
))
277 target_arch
= "aarch64",
278 target_arch
= "mips64",
279 target_arch
= "riscv64",
280 target_arch
= "x86_64",
283 ret_usize(syscall_readonly
!(
293 #[cfg(target_arch = "x86")]
295 ret_usize(syscall_readonly
!(
298 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[fd
.into(), buf_addr
, buf_len
, flags
.into()])
304 pub(crate) fn sendto_v4(
309 ) -> io
::Result
<usize> {
310 let (buf_addr
, buf_len
) = slice(buf
);
312 #[cfg(not(target_arch = "x86"))]
314 ret_usize(syscall_readonly
!(
320 by_ref(&encode_sockaddr_v4(addr
)),
321 size_of
::<sockaddr_in
, _
>()
324 #[cfg(target_arch = "x86")]
326 ret_usize(syscall_readonly
!(
329 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
334 by_ref(&encode_sockaddr_v4(addr
)),
335 size_of
::<sockaddr_in
, _
>(),
342 pub(crate) fn sendto_v6(
347 ) -> io
::Result
<usize> {
348 let (buf_addr
, buf_len
) = slice(buf
);
350 #[cfg(not(target_arch = "x86"))]
352 ret_usize(syscall_readonly
!(
358 by_ref(&encode_sockaddr_v6(addr
)),
359 size_of
::<sockaddr_in6
, _
>()
362 #[cfg(target_arch = "x86")]
364 ret_usize(syscall_readonly
!(
367 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
372 by_ref(&encode_sockaddr_v6(addr
)),
373 size_of
::<sockaddr_in6
, _
>(),
380 pub(crate) fn sendto_unix(
384 addr
: &SocketAddrUnix
,
385 ) -> io
::Result
<usize> {
386 let (buf_addr
, buf_len
) = slice(buf
);
388 #[cfg(not(target_arch = "x86"))]
390 ret_usize(syscall_readonly
!(
397 socklen_t(addr
.addr_len())
400 #[cfg(target_arch = "x86")]
402 ret_usize(syscall_readonly
!(
405 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
411 socklen_t(addr
.addr_len()),
418 pub(crate) fn recv(fd
: BorrowedFd
<'_
>, buf
: &mut [u8], flags
: RecvFlags
) -> io
::Result
<usize> {
419 let (buf_addr_mut
, buf_len
) = slice_mut(buf
);
422 target_arch
= "aarch64",
423 target_arch
= "mips64",
424 target_arch
= "riscv64",
426 target_arch
= "x86_64",
429 ret_usize(syscall
!(__NR_recv
, fd
, buf_addr_mut
, buf_len
, flags
))
432 target_arch
= "aarch64",
433 target_arch
= "mips64",
434 target_arch
= "riscv64",
435 target_arch
= "x86_64",
448 #[cfg(target_arch = "x86")]
453 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
464 pub(crate) fn recvfrom(
468 ) -> io
::Result
<(usize, Option
<SocketAddrAny
>)> {
469 let (buf_addr_mut
, buf_len
) = slice_mut(buf
);
471 let mut addrlen
= core
::mem
::size_of
::<sockaddr
>() as socklen_t
;
472 let mut storage
= MaybeUninit
::<sockaddr
>::uninit();
475 // `recvfrom` does not write to the storage if the socket is
476 // connection-oriented sockets, so we initialize the family field to
477 // `AF_UNSPEC` so that we can detect this case.
478 initialize_family_to_unspec(storage
.as_mut_ptr());
480 #[cfg(not(target_arch = "x86"))]
481 let nread
= ret_usize(syscall
!(
490 #[cfg(target_arch = "x86")]
491 let nread
= ret_usize(syscall
!(
493 x86_sys(SYS_RECVFROM
),
494 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
499 (&mut storage
).into(),
500 by_mut(&mut addrlen
),
506 maybe_read_sockaddr_os(&storage
.assume_init(), addrlen
.try_into().unwrap()),
512 pub(crate) fn getpeername(fd
: BorrowedFd
<'_
>) -> io
::Result
<Option
<SocketAddrAny
>> {
513 #[cfg(not(target_arch = "x86"))]
515 let mut addrlen
= core
::mem
::size_of
::<sockaddr
>() as socklen_t
;
516 let mut storage
= MaybeUninit
::<sockaddr
>::uninit();
523 Ok(maybe_read_sockaddr_os(
524 &storage
.assume_init(),
525 addrlen
.try_into().unwrap(),
528 #[cfg(target_arch = "x86")]
530 let mut addrlen
= core
::mem
::size_of
::<sockaddr
>() as socklen_t
;
531 let mut storage
= MaybeUninit
::<sockaddr
>::uninit();
534 x86_sys(SYS_GETPEERNAME
),
535 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
537 (&mut storage
).into(),
538 by_mut(&mut addrlen
),
541 Ok(maybe_read_sockaddr_os(
542 &storage
.assume_init(),
543 addrlen
.try_into().unwrap(),
549 pub(crate) fn getsockname(fd
: BorrowedFd
<'_
>) -> io
::Result
<SocketAddrAny
> {
550 #[cfg(not(target_arch = "x86"))]
552 let mut addrlen
= core
::mem
::size_of
::<sockaddr
>() as socklen_t
;
553 let mut storage
= MaybeUninit
::<sockaddr
>::uninit();
561 &storage
.assume_init(),
562 addrlen
.try_into().unwrap(),
565 #[cfg(target_arch = "x86")]
567 let mut addrlen
= core
::mem
::size_of
::<sockaddr
>() as socklen_t
;
568 let mut storage
= MaybeUninit
::<sockaddr
>::uninit();
571 x86_sys(SYS_GETSOCKNAME
),
572 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
574 (&mut storage
).into(),
575 by_mut(&mut addrlen
),
579 &storage
.assume_init(),
580 addrlen
.try_into().unwrap(),
586 pub(crate) fn bind_v4(fd
: BorrowedFd
<'_
>, addr
: &SocketAddrV4
) -> io
::Result
<()> {
587 #[cfg(not(target_arch = "x86"))]
589 ret(syscall_readonly
!(
592 by_ref(&encode_sockaddr_v4(addr
)),
593 size_of
::<sockaddr_in
, _
>()
596 #[cfg(target_arch = "x86")]
598 ret(syscall_readonly
!(
601 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
603 by_ref(&encode_sockaddr_v4(addr
)),
604 size_of
::<sockaddr_in
, _
>(),
611 pub(crate) fn bind_v6(fd
: BorrowedFd
<'_
>, addr
: &SocketAddrV6
) -> io
::Result
<()> {
612 #[cfg(not(target_arch = "x86"))]
614 ret(syscall_readonly
!(
617 by_ref(&encode_sockaddr_v6(addr
)),
618 size_of
::<sockaddr_in6
, _
>()
621 #[cfg(target_arch = "x86")]
623 ret(syscall_readonly
!(
626 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
628 by_ref(&encode_sockaddr_v6(addr
)),
629 size_of
::<sockaddr_in6
, _
>(),
636 pub(crate) fn bind_unix(fd
: BorrowedFd
<'_
>, addr
: &SocketAddrUnix
) -> io
::Result
<()> {
637 #[cfg(not(target_arch = "x86"))]
639 ret(syscall_readonly
!(
643 socklen_t(addr
.addr_len())
646 #[cfg(target_arch = "x86")]
648 ret(syscall_readonly
!(
651 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
654 socklen_t(addr
.addr_len()),
661 pub(crate) fn connect_v4(fd
: BorrowedFd
<'_
>, addr
: &SocketAddrV4
) -> io
::Result
<()> {
662 #[cfg(not(target_arch = "x86"))]
664 ret(syscall_readonly
!(
667 by_ref(&encode_sockaddr_v4(addr
)),
668 size_of
::<sockaddr_in
, _
>()
671 #[cfg(target_arch = "x86")]
673 ret(syscall_readonly
!(
675 x86_sys(SYS_CONNECT
),
676 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
678 by_ref(&encode_sockaddr_v4(addr
)),
679 size_of
::<sockaddr_in
, _
>(),
686 pub(crate) fn connect_v6(fd
: BorrowedFd
<'_
>, addr
: &SocketAddrV6
) -> io
::Result
<()> {
687 #[cfg(not(target_arch = "x86"))]
689 ret(syscall_readonly
!(
692 by_ref(&encode_sockaddr_v6(addr
)),
693 size_of
::<sockaddr_in6
, _
>()
696 #[cfg(target_arch = "x86")]
698 ret(syscall_readonly
!(
700 x86_sys(SYS_CONNECT
),
701 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
703 by_ref(&encode_sockaddr_v6(addr
)),
704 size_of
::<sockaddr_in6
, _
>(),
711 pub(crate) fn connect_unix(fd
: BorrowedFd
<'_
>, addr
: &SocketAddrUnix
) -> io
::Result
<()> {
712 #[cfg(not(target_arch = "x86"))]
714 ret(syscall_readonly
!(
718 socklen_t(addr
.addr_len())
721 #[cfg(target_arch = "x86")]
723 ret(syscall_readonly
!(
725 x86_sys(SYS_CONNECT
),
726 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
729 socklen_t(addr
.addr_len()),
736 pub(crate) fn listen(fd
: BorrowedFd
<'_
>, backlog
: c
::c_int
) -> io
::Result
<()> {
737 #[cfg(not(target_arch = "x86"))]
739 ret(syscall_readonly
!(__NR_listen
, fd
, c_int(backlog
)))
741 #[cfg(target_arch = "x86")]
743 ret(syscall_readonly
!(
746 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[fd
.into(), c_int(backlog
)])
751 pub(crate) mod sockopt
{
752 use super::{c, BorrowedFd}
;
754 use crate::net
::sockopt
::Timeout
;
755 use crate::net
::{Ipv4Addr, Ipv6Addr, SocketType}
;
756 use c
::{SO_RCVTIMEO_NEW, SO_RCVTIMEO_OLD, SO_SNDTIMEO_NEW, SO_SNDTIMEO_OLD}
;
757 use core
::convert
::TryInto
;
758 use core
::time
::Duration
;
759 use linux_raw_sys
::general
::{__kernel_timespec, timeval}
;
761 // TODO: With Rust 1.53 we can use `Duration::ZERO` instead.
762 const DURATION_ZERO
: Duration
= Duration
::from_secs(0);
765 fn getsockopt
<T
: Copy
>(fd
: BorrowedFd
<'_
>, level
: u32, optname
: u32) -> io
::Result
<T
> {
768 let mut optlen
= core
::mem
::size_of
::<T
>();
770 optlen
as usize >= core
::mem
::size_of
::<c
::c_int
>(),
771 "Socket APIs don't ever use `bool` directly"
774 #[cfg(not(target_arch = "x86"))]
776 let mut value
= MaybeUninit
::<T
>::uninit();
788 core
::mem
::size_of
::<T
>(),
789 "unexpected getsockopt size"
791 Ok(value
.assume_init())
793 #[cfg(target_arch = "x86")]
795 let mut value
= MaybeUninit
::<T
>::uninit();
798 x86_sys(SYS_GETSOCKOPT
),
799 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
809 core
::mem
::size_of
::<T
>(),
810 "unexpected getsockopt size"
812 Ok(value
.assume_init())
817 fn setsockopt
<T
: Copy
>(
822 ) -> io
::Result
<()> {
825 let optlen
= core
::mem
::size_of
::<T
>().try_into().unwrap();
827 optlen
as usize >= core
::mem
::size_of
::<c
::c_int
>(),
828 "Socket APIs don't ever use `bool` directly"
831 #[cfg(not(target_arch = "x86"))]
833 ret(syscall_readonly
!(
842 #[cfg(target_arch = "x86")]
844 ret(syscall_readonly
!(
846 x86_sys(SYS_SETSOCKOPT
),
847 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
859 pub(crate) fn get_socket_type(fd
: BorrowedFd
<'_
>) -> io
::Result
<SocketType
> {
860 getsockopt(fd
, c
::SOL_SOCKET
as _
, c
::SO_TYPE
)
864 pub(crate) fn set_socket_reuseaddr(fd
: BorrowedFd
<'_
>, reuseaddr
: bool
) -> io
::Result
<()> {
869 from_bool(reuseaddr
),
874 pub(crate) fn set_socket_broadcast(fd
: BorrowedFd
<'_
>, broadcast
: bool
) -> io
::Result
<()> {
879 from_bool(broadcast
),
884 pub(crate) fn get_socket_broadcast(fd
: BorrowedFd
<'_
>) -> io
::Result
<bool
> {
885 getsockopt(fd
, c
::SOL_SOCKET
as _
, c
::SO_BROADCAST
).map(to_bool
)
889 pub(crate) fn set_socket_linger(
891 linger
: Option
<Duration
>,
892 ) -> io
::Result
<()> {
893 // Convert `linger` to seconds, rounding up.
894 let l_linger
= if let Some(linger
) = linger
{
895 let mut l_linger
= linger
.as_secs();
896 if linger
.subsec_nanos() != 0 {
897 l_linger
= l_linger
.checked_add(1).ok_or(io
::Errno
::INVAL
)?
;
899 l_linger
.try_into().map_err(|_e
| io
::Errno
::INVAL
)?
903 let linger
= c
::linger
{
904 l_onoff
: c
::c_int
::from(linger
.is_some()),
907 setsockopt(fd
, c
::SOL_SOCKET
as _
, c
::SO_LINGER
, linger
)
911 pub(crate) fn get_socket_linger(fd
: BorrowedFd
<'_
>) -> io
::Result
<Option
<Duration
>> {
912 let linger
: c
::linger
= getsockopt(fd
, c
::SOL_SOCKET
as _
, c
::SO_LINGER
)?
;
913 // TODO: With Rust 1.50, this could use `.then`.
914 Ok(if linger
.l_onoff
!= 0 {
915 Some(Duration
::from_secs(linger
.l_linger
as u64))
922 pub(crate) fn set_socket_passcred(fd
: BorrowedFd
<'_
>, passcred
: bool
) -> io
::Result
<()> {
923 setsockopt(fd
, c
::SOL_SOCKET
as _
, c
::SO_PASSCRED
, from_bool(passcred
))
927 pub(crate) fn get_socket_passcred(fd
: BorrowedFd
<'_
>) -> io
::Result
<bool
> {
928 getsockopt(fd
, c
::SOL_SOCKET
as _
, c
::SO_PASSCRED
).map(to_bool
)
932 pub(crate) fn set_socket_timeout(
935 timeout
: Option
<Duration
>,
936 ) -> io
::Result
<()> {
937 let time
= duration_to_linux(timeout
)?
;
938 let optname
= match id
{
939 Timeout
::Recv
=> SO_RCVTIMEO_NEW
,
940 Timeout
::Send
=> SO_SNDTIMEO_NEW
,
942 match setsockopt(fd
, c
::SOL_SOCKET
, optname
, time
) {
943 Err(io
::Errno
::NOPROTOOPT
) if SO_RCVTIMEO_NEW
!= SO_RCVTIMEO_OLD
=> {
944 set_socket_timeout_old(fd
, id
, timeout
)
946 otherwise
=> otherwise
,
950 /// Same as `set_socket_timeout` but uses `timeval` instead of
951 /// `__kernel_timespec` and `_OLD` constants instead of `_NEW`.
952 fn set_socket_timeout_old(
955 timeout
: Option
<Duration
>,
956 ) -> io
::Result
<()> {
957 let time
= duration_to_linux_old(timeout
)?
;
958 let optname
= match id
{
959 Timeout
::Recv
=> SO_RCVTIMEO_OLD
,
960 Timeout
::Send
=> SO_SNDTIMEO_OLD
,
962 setsockopt(fd
, c
::SOL_SOCKET
, optname
, time
)
966 pub(crate) fn get_socket_timeout(
969 ) -> io
::Result
<Option
<Duration
>> {
970 let optname
= match id
{
971 Timeout
::Recv
=> SO_RCVTIMEO_NEW
,
972 Timeout
::Send
=> SO_SNDTIMEO_NEW
,
974 let time
: __kernel_timespec
= match getsockopt(fd
, c
::SOL_SOCKET
, optname
) {
975 Err(io
::Errno
::NOPROTOOPT
) if SO_RCVTIMEO_NEW
!= SO_RCVTIMEO_OLD
=> {
976 return get_socket_timeout_old(fd
, id
)
978 otherwise
=> otherwise?
,
980 Ok(duration_from_linux(time
))
983 /// Same as `get_socket_timeout` but uses `timeval` instead of
984 /// `__kernel_timespec` and `_OLD` constants instead of `_NEW`.
985 fn get_socket_timeout_old(fd
: BorrowedFd
<'_
>, id
: Timeout
) -> io
::Result
<Option
<Duration
>> {
986 let optname
= match id
{
987 Timeout
::Recv
=> SO_RCVTIMEO_OLD
,
988 Timeout
::Send
=> SO_SNDTIMEO_OLD
,
990 let time
: timeval
= getsockopt(fd
, c
::SOL_SOCKET
, optname
)?
;
991 Ok(duration_from_linux_old(time
))
994 /// Convert a C `timespec` to a Rust `Option<Duration>`.
996 fn duration_from_linux(time
: __kernel_timespec
) -> Option
<Duration
> {
997 if time
.tv_sec
== 0 && time
.tv_nsec
== 0 {
1001 Duration
::from_secs(time
.tv_sec
as u64) + Duration
::from_nanos(time
.tv_nsec
as u64),
1006 /// Like `duration_from_linux` but uses Linux's old 32-bit `timeval`.
1007 fn duration_from_linux_old(time
: timeval
) -> Option
<Duration
> {
1008 if time
.tv_sec
== 0 && time
.tv_usec
== 0 {
1012 Duration
::from_secs(time
.tv_sec
as u64)
1013 + Duration
::from_micros(time
.tv_usec
as u64),
1018 /// Convert a Rust `Option<Duration>` to a C `timespec`.
1020 fn duration_to_linux(timeout
: Option
<Duration
>) -> io
::Result
<__kernel_timespec
> {
1023 if timeout
== DURATION_ZERO
{
1024 return Err(io
::Errno
::INVAL
);
1026 let mut timeout
= __kernel_timespec
{
1027 tv_sec
: timeout
.as_secs().try_into().unwrap_or(i64::MAX
),
1028 tv_nsec
: timeout
.subsec_nanos().into(),
1030 if timeout
.tv_sec
== 0 && timeout
.tv_nsec
== 0 {
1031 timeout
.tv_nsec
= 1;
1035 None
=> __kernel_timespec
{
1042 /// Like `duration_to_linux` but uses Linux's old 32-bit `timeval`.
1043 fn duration_to_linux_old(timeout
: Option
<Duration
>) -> io
::Result
<timeval
> {
1046 if timeout
== DURATION_ZERO
{
1047 return Err(io
::Errno
::INVAL
);
1050 // `subsec_micros` rounds down, so we use `subsec_nanos` and
1051 // manually round up.
1052 let mut timeout
= timeval
{
1053 tv_sec
: timeout
.as_secs().try_into().unwrap_or(c
::c_long
::MAX
),
1054 tv_usec
: ((timeout
.subsec_nanos() + 999) / 1000) as _
,
1056 if timeout
.tv_sec
== 0 && timeout
.tv_usec
== 0 {
1057 timeout
.tv_usec
= 1;
1069 pub(crate) fn set_ip_ttl(fd
: BorrowedFd
<'_
>, ttl
: u32) -> io
::Result
<()> {
1070 setsockopt(fd
, c
::IPPROTO_IP
as _
, c
::IP_TTL
, ttl
)
1074 pub(crate) fn get_ip_ttl(fd
: BorrowedFd
<'_
>) -> io
::Result
<u32> {
1075 getsockopt(fd
, c
::IPPROTO_IP
as _
, c
::IP_TTL
)
1079 pub(crate) fn set_ipv6_v6only(fd
: BorrowedFd
<'_
>, only_v6
: bool
) -> io
::Result
<()> {
1080 setsockopt(fd
, c
::IPPROTO_IPV6
as _
, c
::IPV6_V6ONLY
, from_bool(only_v6
))
1084 pub(crate) fn get_ipv6_v6only(fd
: BorrowedFd
<'_
>) -> io
::Result
<bool
> {
1085 getsockopt(fd
, c
::IPPROTO_IPV6
as _
, c
::IPV6_V6ONLY
).map(to_bool
)
1089 pub(crate) fn set_ip_multicast_loop(
1091 multicast_loop
: bool
,
1092 ) -> io
::Result
<()> {
1096 c
::IP_MULTICAST_LOOP
,
1097 from_bool(multicast_loop
),
1102 pub(crate) fn get_ip_multicast_loop(fd
: BorrowedFd
<'_
>) -> io
::Result
<bool
> {
1103 getsockopt(fd
, c
::IPPROTO_IP
as _
, c
::IP_MULTICAST_LOOP
).map(to_bool
)
1107 pub(crate) fn set_ip_multicast_ttl(fd
: BorrowedFd
<'_
>, multicast_ttl
: u32) -> io
::Result
<()> {
1108 setsockopt(fd
, c
::IPPROTO_IP
as _
, c
::IP_MULTICAST_TTL
, multicast_ttl
)
1112 pub(crate) fn get_ip_multicast_ttl(fd
: BorrowedFd
<'_
>) -> io
::Result
<u32> {
1113 getsockopt(fd
, c
::IPPROTO_IP
as _
, c
::IP_MULTICAST_TTL
)
1117 pub(crate) fn set_ipv6_multicast_loop(
1119 multicast_loop
: bool
,
1120 ) -> io
::Result
<()> {
1123 c
::IPPROTO_IPV6
as _
,
1124 c
::IPV6_MULTICAST_LOOP
,
1125 from_bool(multicast_loop
),
1130 pub(crate) fn get_ipv6_multicast_loop(fd
: BorrowedFd
<'_
>) -> io
::Result
<bool
> {
1131 getsockopt(fd
, c
::IPPROTO_IPV6
as _
, c
::IPV6_MULTICAST_LOOP
).map(to_bool
)
1135 pub(crate) fn set_ipv6_multicast_hops(
1137 multicast_hops
: u32,
1138 ) -> io
::Result
<()> {
1142 c
::IPV6_MULTICAST_LOOP
,
1148 pub(crate) fn get_ipv6_multicast_hops(fd
: BorrowedFd
<'_
>) -> io
::Result
<u32> {
1149 getsockopt(fd
, c
::IPPROTO_IP
as _
, c
::IPV6_MULTICAST_LOOP
)
1153 pub(crate) fn set_ip_add_membership(
1155 multiaddr
: &Ipv4Addr
,
1156 interface
: &Ipv4Addr
,
1157 ) -> io
::Result
<()> {
1158 let mreq
= to_imr(multiaddr
, interface
);
1159 setsockopt(fd
, c
::IPPROTO_IP
as _
, c
::IP_ADD_MEMBERSHIP
, mreq
)
1163 pub(crate) fn set_ipv6_add_membership(
1165 multiaddr
: &Ipv6Addr
,
1167 ) -> io
::Result
<()> {
1168 let mreq
= to_ipv6mr(multiaddr
, interface
);
1169 setsockopt(fd
, c
::IPPROTO_IPV6
as _
, c
::IPV6_ADD_MEMBERSHIP
, mreq
)
1173 pub(crate) fn set_ip_drop_membership(
1175 multiaddr
: &Ipv4Addr
,
1176 interface
: &Ipv4Addr
,
1177 ) -> io
::Result
<()> {
1178 let mreq
= to_imr(multiaddr
, interface
);
1179 setsockopt(fd
, c
::IPPROTO_IP
as _
, c
::IP_DROP_MEMBERSHIP
, mreq
)
1183 pub(crate) fn set_ipv6_drop_membership(
1185 multiaddr
: &Ipv6Addr
,
1187 ) -> io
::Result
<()> {
1188 let mreq
= to_ipv6mr(multiaddr
, interface
);
1189 setsockopt(fd
, c
::IPPROTO_IPV6
as _
, c
::IPV6_DROP_MEMBERSHIP
, mreq
)
1193 pub(crate) fn set_tcp_nodelay(fd
: BorrowedFd
<'_
>, nodelay
: bool
) -> io
::Result
<()> {
1194 setsockopt(fd
, c
::IPPROTO_TCP
as _
, c
::TCP_NODELAY
, from_bool(nodelay
))
1198 pub(crate) fn get_tcp_nodelay(fd
: BorrowedFd
<'_
>) -> io
::Result
<bool
> {
1199 getsockopt(fd
, c
::IPPROTO_TCP
as _
, c
::TCP_NODELAY
).map(to_bool
)
1203 fn to_imr(multiaddr
: &Ipv4Addr
, interface
: &Ipv4Addr
) -> c
::ip_mreq
{
1205 imr_multiaddr
: to_imr_addr(multiaddr
),
1206 imr_interface
: to_imr_addr(interface
),
1211 fn to_imr_addr(addr
: &Ipv4Addr
) -> c
::in_addr
{
1213 s_addr
: u32::from_ne_bytes(addr
.octets()),
1218 fn to_ipv6mr(multiaddr
: &Ipv6Addr
, interface
: u32) -> c
::ipv6_mreq
{
1220 ipv6mr_multiaddr
: to_ipv6mr_multiaddr(multiaddr
),
1221 ipv6mr_ifindex
: to_ipv6mr_interface(interface
),
1226 fn to_ipv6mr_multiaddr(multiaddr
: &Ipv6Addr
) -> c
::in6_addr
{
1228 in6_u
: linux_raw_sys
::general
::in6_addr__bindgen_ty_1
{
1229 u6_addr8
: multiaddr
.octets(),
1235 fn to_ipv6mr_interface(interface
: u32) -> c
::c_int
{
1236 interface
as c
::c_int
1240 fn from_bool(value
: bool
) -> c
::c_uint
{
1241 c
::c_uint
::from(value
)
1245 fn to_bool(value
: c
::c_uint
) -> bool
{