1 //! linux_raw syscalls supporting `rustix::net`.
5 //! See the `rustix::backend` module documentation for details.
7 #![allow(clippy::undocumented_unsafe_blocks)]
10 with_noaddr_msghdr
, with_recv_msghdr
, with_unix_msghdr
, with_v4_msghdr
, with_v6_msghdr
,
12 use super::read_sockaddr
::{initialize_family_to_unspec, maybe_read_sockaddr_os, read_sockaddr_os}
;
13 use super::send_recv
::{RecvFlags, SendFlags}
;
14 use super::write_sockaddr
::{encode_sockaddr_v4, encode_sockaddr_v6}
;
15 use crate::backend
::c
;
16 use crate::backend
::conv
::{
17 by_mut
, by_ref
, c_int
, c_uint
, ret
, ret_owned_fd
, ret_usize
, size_of
, slice
, slice_mut
,
20 use crate::fd
::{BorrowedFd, OwnedFd}
;
21 use crate::io
::{self, IoSlice, IoSliceMut}
;
23 AddressFamily
, Protocol
, RecvAncillaryBuffer
, RecvMsgReturn
, SendAncillaryBuffer
, Shutdown
,
24 SocketAddrAny
, SocketAddrUnix
, SocketAddrV4
, SocketAddrV6
, SocketFlags
, SocketType
,
26 use c
::{sockaddr, sockaddr_in, sockaddr_in6, socklen_t}
;
27 use core
::mem
::MaybeUninit
;
28 #[cfg(target_arch = "x86")]
30 crate::backend
::conv
::{slice_just_addr, x86_sys}
,
31 crate::backend
::reg
::{ArgReg, SocketArg}
,
33 SYS_ACCEPT
, SYS_ACCEPT4
, SYS_BIND
, SYS_CONNECT
, SYS_GETPEERNAME
, SYS_GETSOCKNAME
,
34 SYS_GETSOCKOPT
, SYS_LISTEN
, SYS_RECV
, SYS_RECVFROM
, SYS_RECVMSG
, SYS_SEND
, SYS_SENDMSG
,
35 SYS_SENDTO
, SYS_SETSOCKOPT
, SYS_SHUTDOWN
, SYS_SOCKET
, SYS_SOCKETPAIR
,
41 family
: AddressFamily
,
43 protocol
: Option
<Protocol
>,
44 ) -> io
::Result
<OwnedFd
> {
45 #[cfg(not(target_arch = "x86"))]
47 ret_owned_fd(syscall_readonly
!(__NR_socket
, family
, type_
, protocol
))
49 #[cfg(target_arch = "x86")]
51 ret_owned_fd(syscall_readonly
!(
54 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
64 pub(crate) fn socket_with(
65 family
: AddressFamily
,
68 protocol
: Option
<Protocol
>,
69 ) -> io
::Result
<OwnedFd
> {
70 #[cfg(not(target_arch = "x86"))]
72 ret_owned_fd(syscall_readonly
!(
79 #[cfg(target_arch = "x86")]
81 ret_owned_fd(syscall_readonly
!(
84 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
86 (type_
, flags
).into(),
94 pub(crate) fn socketpair(
95 family
: AddressFamily
,
98 protocol
: Option
<Protocol
>,
99 ) -> io
::Result
<(OwnedFd
, OwnedFd
)> {
100 #[cfg(not(target_arch = "x86"))]
102 let mut result
= MaybeUninit
::<[OwnedFd
; 2]>::uninit();
110 let [fd0
, fd1
] = result
.assume_init();
113 #[cfg(target_arch = "x86")]
115 let mut result
= MaybeUninit
::<[OwnedFd
; 2]>::uninit();
118 x86_sys(SYS_SOCKETPAIR
),
119 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
121 (type_
, flags
).into(),
123 (&mut result
).into(),
126 let [fd0
, fd1
] = result
.assume_init();
132 pub(crate) fn accept(fd
: BorrowedFd
<'_
>) -> io
::Result
<OwnedFd
> {
133 #[cfg(not(target_arch = "x86"))]
135 let fd
= ret_owned_fd(syscall_readonly
!(__NR_accept
, fd
, zero(), zero()))?
;
138 #[cfg(target_arch = "x86")]
140 let fd
= ret_owned_fd(syscall_readonly
!(
143 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[fd
.into(), zero(), zero()])
150 pub(crate) fn accept_with(fd
: BorrowedFd
<'_
>, flags
: SocketFlags
) -> io
::Result
<OwnedFd
> {
151 #[cfg(not(target_arch = "x86"))]
153 let fd
= ret_owned_fd(syscall_readonly
!(__NR_accept4
, fd
, zero(), zero(), flags
))?
;
156 #[cfg(target_arch = "x86")]
158 let fd
= ret_owned_fd(syscall_readonly
!(
160 x86_sys(SYS_ACCEPT4
),
161 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[fd
.into(), zero(), zero(), flags
.into()])
168 pub(crate) fn acceptfrom(fd
: BorrowedFd
<'_
>) -> io
::Result
<(OwnedFd
, Option
<SocketAddrAny
>)> {
169 #[cfg(not(target_arch = "x86"))]
171 let mut addrlen
= core
::mem
::size_of
::<sockaddr
>() as socklen_t
;
172 let mut storage
= MaybeUninit
::<sockaddr
>::uninit();
173 let fd
= ret_owned_fd(syscall
!(
181 maybe_read_sockaddr_os(&storage
.assume_init(), addrlen
.try_into().unwrap()),
184 #[cfg(target_arch = "x86")]
186 let mut addrlen
= core
::mem
::size_of
::<sockaddr
>() as socklen_t
;
187 let mut storage
= MaybeUninit
::<sockaddr
>::uninit();
188 let fd
= ret_owned_fd(syscall
!(
191 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
193 (&mut storage
).into(),
194 by_mut(&mut addrlen
),
199 maybe_read_sockaddr_os(&storage
.assume_init(), addrlen
.try_into().unwrap()),
205 pub(crate) fn acceptfrom_with(
208 ) -> io
::Result
<(OwnedFd
, Option
<SocketAddrAny
>)> {
209 #[cfg(not(target_arch = "x86"))]
211 let mut addrlen
= core
::mem
::size_of
::<sockaddr
>() as socklen_t
;
212 let mut storage
= MaybeUninit
::<sockaddr
>::uninit();
213 let fd
= ret_owned_fd(syscall
!(
217 by_mut(&mut addrlen
),
222 maybe_read_sockaddr_os(&storage
.assume_init(), addrlen
.try_into().unwrap()),
225 #[cfg(target_arch = "x86")]
227 let mut addrlen
= core
::mem
::size_of
::<sockaddr
>() as socklen_t
;
228 let mut storage
= MaybeUninit
::<sockaddr
>::uninit();
229 let fd
= ret_owned_fd(syscall
!(
231 x86_sys(SYS_ACCEPT4
),
232 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
234 (&mut storage
).into(),
235 by_mut(&mut addrlen
),
241 maybe_read_sockaddr_os(&storage
.assume_init(), addrlen
.try_into().unwrap()),
247 pub(crate) fn recvmsg(
248 sockfd
: BorrowedFd
<'_
>,
249 iov
: &mut [IoSliceMut
<'_
>],
250 control
: &mut RecvAncillaryBuffer
<'_
>,
251 msg_flags
: RecvFlags
,
252 ) -> io
::Result
<RecvMsgReturn
> {
253 let mut storage
= MaybeUninit
::<c
::sockaddr_storage
>::uninit();
255 with_recv_msghdr(&mut storage
, iov
, control
, |msghdr
| {
256 #[cfg(not(target_arch = "x86"))]
258 unsafe { ret_usize(syscall!(__NR_recvmsg, sockfd, by_mut(msghdr), msg_flags)) }
;
260 #[cfg(target_arch = "x86")]
261 let result
= unsafe {
264 x86_sys(SYS_RECVMSG
),
265 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
274 // Get the address of the sender, if any.
276 unsafe { maybe_read_sockaddr_os(msghdr.msg_name as _, msghdr.msg_namelen as _) }
;
281 flags
: RecvFlags
::from_bits_retain(msghdr
.msg_flags
),
288 pub(crate) fn sendmsg(
289 sockfd
: BorrowedFd
<'_
>,
291 control
: &mut SendAncillaryBuffer
<'_
, '_
, '_
>,
292 msg_flags
: SendFlags
,
293 ) -> io
::Result
<usize> {
294 with_noaddr_msghdr(iov
, control
, |msghdr
| {
295 #[cfg(not(target_arch = "x86"))]
297 unsafe { ret_usize(syscall!(__NR_sendmsg, sockfd, by_ref(&msghdr), msg_flags)) }
;
299 #[cfg(target_arch = "x86")]
300 let result
= unsafe {
303 x86_sys(SYS_SENDMSG
),
304 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
317 pub(crate) fn sendmsg_v4(
318 sockfd
: BorrowedFd
<'_
>,
321 control
: &mut SendAncillaryBuffer
<'_
, '_
, '_
>,
322 msg_flags
: SendFlags
,
323 ) -> io
::Result
<usize> {
324 with_v4_msghdr(addr
, iov
, control
, |msghdr
| {
325 #[cfg(not(target_arch = "x86"))]
327 unsafe { ret_usize(syscall!(__NR_sendmsg, sockfd, by_ref(&msghdr), msg_flags)) }
;
329 #[cfg(target_arch = "x86")]
330 let result
= unsafe {
333 x86_sys(SYS_SENDMSG
),
334 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
347 pub(crate) fn sendmsg_v6(
348 sockfd
: BorrowedFd
<'_
>,
351 control
: &mut SendAncillaryBuffer
<'_
, '_
, '_
>,
352 msg_flags
: SendFlags
,
353 ) -> io
::Result
<usize> {
354 with_v6_msghdr(addr
, iov
, control
, |msghdr
| {
355 #[cfg(not(target_arch = "x86"))]
357 unsafe { ret_usize(syscall!(__NR_sendmsg, sockfd, by_ref(&msghdr), msg_flags)) }
;
359 #[cfg(target_arch = "x86")]
360 let result
= unsafe {
363 x86_sys(SYS_SENDMSG
),
364 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
377 pub(crate) fn sendmsg_unix(
378 sockfd
: BorrowedFd
<'_
>,
379 addr
: &SocketAddrUnix
,
381 control
: &mut SendAncillaryBuffer
<'_
, '_
, '_
>,
382 msg_flags
: SendFlags
,
383 ) -> io
::Result
<usize> {
384 with_unix_msghdr(addr
, iov
, control
, |msghdr
| {
385 #[cfg(not(target_arch = "x86"))]
387 unsafe { ret_usize(syscall!(__NR_sendmsg, sockfd, by_ref(&msghdr), msg_flags)) }
;
389 #[cfg(target_arch = "x86")]
390 let result
= unsafe {
393 x86_sys(SYS_SENDMSG
),
394 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
407 pub(crate) fn shutdown(fd
: BorrowedFd
<'_
>, how
: Shutdown
) -> io
::Result
<()> {
408 #[cfg(not(target_arch = "x86"))]
410 ret(syscall_readonly
!(
413 c_uint(how
as c
::c_uint
)
416 #[cfg(target_arch = "x86")]
418 ret(syscall_readonly
!(
420 x86_sys(SYS_SHUTDOWN
),
421 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[fd
.into(), c_uint(how
as c
::c_uint
)])
427 pub(crate) fn send(fd
: BorrowedFd
<'_
>, buf
: &[u8], flags
: SendFlags
) -> io
::Result
<usize> {
428 let (buf_addr
, buf_len
) = slice(buf
);
431 target_arch
= "aarch64",
432 target_arch
= "mips64",
433 target_arch
= "mips64r6",
434 target_arch
= "riscv64",
436 target_arch
= "x86_64",
439 ret_usize(syscall_readonly
!(__NR_send
, fd
, buf_addr
, buf_len
, flags
))
442 target_arch
= "aarch64",
443 target_arch
= "mips64",
444 target_arch
= "mips64r6",
445 target_arch
= "riscv64",
446 target_arch
= "x86_64",
449 ret_usize(syscall_readonly
!(
459 #[cfg(target_arch = "x86")]
461 ret_usize(syscall_readonly
!(
464 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[fd
.into(), buf_addr
, buf_len
, flags
.into()])
470 pub(crate) fn sendto_v4(
475 ) -> io
::Result
<usize> {
476 let (buf_addr
, buf_len
) = slice(buf
);
478 #[cfg(not(target_arch = "x86"))]
480 ret_usize(syscall_readonly
!(
486 by_ref(&encode_sockaddr_v4(addr
)),
487 size_of
::<sockaddr_in
, _
>()
490 #[cfg(target_arch = "x86")]
492 ret_usize(syscall_readonly
!(
495 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
500 by_ref(&encode_sockaddr_v4(addr
)),
501 size_of
::<sockaddr_in
, _
>(),
508 pub(crate) fn sendto_v6(
513 ) -> io
::Result
<usize> {
514 let (buf_addr
, buf_len
) = slice(buf
);
516 #[cfg(not(target_arch = "x86"))]
518 ret_usize(syscall_readonly
!(
524 by_ref(&encode_sockaddr_v6(addr
)),
525 size_of
::<sockaddr_in6
, _
>()
528 #[cfg(target_arch = "x86")]
530 ret_usize(syscall_readonly
!(
533 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
538 by_ref(&encode_sockaddr_v6(addr
)),
539 size_of
::<sockaddr_in6
, _
>(),
546 pub(crate) fn sendto_unix(
550 addr
: &SocketAddrUnix
,
551 ) -> io
::Result
<usize> {
552 let (buf_addr
, buf_len
) = slice(buf
);
554 #[cfg(not(target_arch = "x86"))]
556 ret_usize(syscall_readonly
!(
563 socklen_t(addr
.addr_len())
566 #[cfg(target_arch = "x86")]
568 ret_usize(syscall_readonly
!(
571 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
577 socklen_t(addr
.addr_len()),
584 pub(crate) fn recv(fd
: BorrowedFd
<'_
>, buf
: &mut [u8], flags
: RecvFlags
) -> io
::Result
<usize> {
585 let (buf_addr_mut
, buf_len
) = slice_mut(buf
);
588 target_arch
= "aarch64",
589 target_arch
= "mips64",
590 target_arch
= "mips64r6",
591 target_arch
= "riscv64",
593 target_arch
= "x86_64",
596 ret_usize(syscall
!(__NR_recv
, fd
, buf_addr_mut
, buf_len
, flags
))
599 target_arch
= "aarch64",
600 target_arch
= "mips64",
601 target_arch
= "mips64r6",
602 target_arch
= "riscv64",
603 target_arch
= "x86_64",
616 #[cfg(target_arch = "x86")]
621 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
632 pub(crate) fn recvfrom(
636 ) -> io
::Result
<(usize, Option
<SocketAddrAny
>)> {
637 let (buf_addr_mut
, buf_len
) = slice_mut(buf
);
639 let mut addrlen
= core
::mem
::size_of
::<sockaddr
>() as socklen_t
;
640 let mut storage
= MaybeUninit
::<sockaddr
>::uninit();
643 // `recvfrom` does not write to the storage if the socket is
644 // connection-oriented sockets, so we initialize the family field to
645 // `AF_UNSPEC` so that we can detect this case.
646 initialize_family_to_unspec(storage
.as_mut_ptr());
648 #[cfg(not(target_arch = "x86"))]
649 let nread
= ret_usize(syscall
!(
658 #[cfg(target_arch = "x86")]
659 let nread
= ret_usize(syscall
!(
661 x86_sys(SYS_RECVFROM
),
662 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
667 (&mut storage
).into(),
668 by_mut(&mut addrlen
),
674 maybe_read_sockaddr_os(&storage
.assume_init(), addrlen
.try_into().unwrap()),
680 pub(crate) fn getpeername(fd
: BorrowedFd
<'_
>) -> io
::Result
<Option
<SocketAddrAny
>> {
681 #[cfg(not(target_arch = "x86"))]
683 let mut addrlen
= core
::mem
::size_of
::<sockaddr
>() as socklen_t
;
684 let mut storage
= MaybeUninit
::<sockaddr
>::uninit();
691 Ok(maybe_read_sockaddr_os(
692 &storage
.assume_init(),
693 addrlen
.try_into().unwrap(),
696 #[cfg(target_arch = "x86")]
698 let mut addrlen
= core
::mem
::size_of
::<sockaddr
>() as socklen_t
;
699 let mut storage
= MaybeUninit
::<sockaddr
>::uninit();
702 x86_sys(SYS_GETPEERNAME
),
703 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
705 (&mut storage
).into(),
706 by_mut(&mut addrlen
),
709 Ok(maybe_read_sockaddr_os(
710 &storage
.assume_init(),
711 addrlen
.try_into().unwrap(),
717 pub(crate) fn getsockname(fd
: BorrowedFd
<'_
>) -> io
::Result
<SocketAddrAny
> {
718 #[cfg(not(target_arch = "x86"))]
720 let mut addrlen
= core
::mem
::size_of
::<sockaddr
>() as socklen_t
;
721 let mut storage
= MaybeUninit
::<sockaddr
>::uninit();
729 &storage
.assume_init(),
730 addrlen
.try_into().unwrap(),
733 #[cfg(target_arch = "x86")]
735 let mut addrlen
= core
::mem
::size_of
::<sockaddr
>() as socklen_t
;
736 let mut storage
= MaybeUninit
::<sockaddr
>::uninit();
739 x86_sys(SYS_GETSOCKNAME
),
740 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
742 (&mut storage
).into(),
743 by_mut(&mut addrlen
),
747 &storage
.assume_init(),
748 addrlen
.try_into().unwrap(),
754 pub(crate) fn bind_v4(fd
: BorrowedFd
<'_
>, addr
: &SocketAddrV4
) -> io
::Result
<()> {
755 #[cfg(not(target_arch = "x86"))]
757 ret(syscall_readonly
!(
760 by_ref(&encode_sockaddr_v4(addr
)),
761 size_of
::<sockaddr_in
, _
>()
764 #[cfg(target_arch = "x86")]
766 ret(syscall_readonly
!(
769 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
771 by_ref(&encode_sockaddr_v4(addr
)),
772 size_of
::<sockaddr_in
, _
>(),
779 pub(crate) fn bind_v6(fd
: BorrowedFd
<'_
>, addr
: &SocketAddrV6
) -> io
::Result
<()> {
780 #[cfg(not(target_arch = "x86"))]
782 ret(syscall_readonly
!(
785 by_ref(&encode_sockaddr_v6(addr
)),
786 size_of
::<sockaddr_in6
, _
>()
789 #[cfg(target_arch = "x86")]
791 ret(syscall_readonly
!(
794 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
796 by_ref(&encode_sockaddr_v6(addr
)),
797 size_of
::<sockaddr_in6
, _
>(),
804 pub(crate) fn bind_unix(fd
: BorrowedFd
<'_
>, addr
: &SocketAddrUnix
) -> io
::Result
<()> {
805 #[cfg(not(target_arch = "x86"))]
807 ret(syscall_readonly
!(
811 socklen_t(addr
.addr_len())
814 #[cfg(target_arch = "x86")]
816 ret(syscall_readonly
!(
819 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
822 socklen_t(addr
.addr_len()),
829 pub(crate) fn connect_v4(fd
: BorrowedFd
<'_
>, addr
: &SocketAddrV4
) -> io
::Result
<()> {
830 #[cfg(not(target_arch = "x86"))]
832 ret(syscall_readonly
!(
835 by_ref(&encode_sockaddr_v4(addr
)),
836 size_of
::<sockaddr_in
, _
>()
839 #[cfg(target_arch = "x86")]
841 ret(syscall_readonly
!(
843 x86_sys(SYS_CONNECT
),
844 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
846 by_ref(&encode_sockaddr_v4(addr
)),
847 size_of
::<sockaddr_in
, _
>(),
854 pub(crate) fn connect_v6(fd
: BorrowedFd
<'_
>, addr
: &SocketAddrV6
) -> io
::Result
<()> {
855 #[cfg(not(target_arch = "x86"))]
857 ret(syscall_readonly
!(
860 by_ref(&encode_sockaddr_v6(addr
)),
861 size_of
::<sockaddr_in6
, _
>()
864 #[cfg(target_arch = "x86")]
866 ret(syscall_readonly
!(
868 x86_sys(SYS_CONNECT
),
869 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
871 by_ref(&encode_sockaddr_v6(addr
)),
872 size_of
::<sockaddr_in6
, _
>(),
879 pub(crate) fn connect_unix(fd
: BorrowedFd
<'_
>, addr
: &SocketAddrUnix
) -> io
::Result
<()> {
880 #[cfg(not(target_arch = "x86"))]
882 ret(syscall_readonly
!(
886 socklen_t(addr
.addr_len())
889 #[cfg(target_arch = "x86")]
891 ret(syscall_readonly
!(
893 x86_sys(SYS_CONNECT
),
894 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
897 socklen_t(addr
.addr_len()),
904 pub(crate) fn listen(fd
: BorrowedFd
<'_
>, backlog
: c
::c_int
) -> io
::Result
<()> {
905 #[cfg(not(target_arch = "x86"))]
907 ret(syscall_readonly
!(__NR_listen
, fd
, c_int(backlog
)))
909 #[cfg(target_arch = "x86")]
911 ret(syscall_readonly
!(
914 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[fd
.into(), c_int(backlog
)])
919 pub(crate) mod sockopt
{
920 use super::{c, BorrowedFd}
;
922 use crate::net
::sockopt
::Timeout
;
923 use crate::net
::{Ipv4Addr, Ipv6Addr, SocketType}
;
924 use c
::{SO_RCVTIMEO_NEW, SO_RCVTIMEO_OLD, SO_SNDTIMEO_NEW, SO_SNDTIMEO_OLD}
;
925 use core
::time
::Duration
;
926 use linux_raw_sys
::general
::{__kernel_timespec, timeval}
;
929 fn getsockopt
<T
: Copy
>(fd
: BorrowedFd
<'_
>, level
: u32, optname
: u32) -> io
::Result
<T
> {
932 let mut optlen
= core
::mem
::size_of
::<T
>();
934 optlen
as usize >= core
::mem
::size_of
::<c
::c_int
>(),
935 "Socket APIs don't ever use `bool` directly"
938 #[cfg(not(target_arch = "x86"))]
940 let mut value
= MaybeUninit
::<T
>::uninit();
952 core
::mem
::size_of
::<T
>(),
953 "unexpected getsockopt size"
955 Ok(value
.assume_init())
957 #[cfg(target_arch = "x86")]
959 let mut value
= MaybeUninit
::<T
>::uninit();
962 x86_sys(SYS_GETSOCKOPT
),
963 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
973 core
::mem
::size_of
::<T
>(),
974 "unexpected getsockopt size"
976 Ok(value
.assume_init())
981 fn setsockopt
<T
: Copy
>(
986 ) -> io
::Result
<()> {
989 let optlen
= core
::mem
::size_of
::<T
>().try_into().unwrap();
991 optlen
as usize >= core
::mem
::size_of
::<c
::c_int
>(),
992 "Socket APIs don't ever use `bool` directly"
995 #[cfg(not(target_arch = "x86"))]
997 ret(syscall_readonly
!(
1006 #[cfg(target_arch = "x86")]
1008 ret(syscall_readonly
!(
1010 x86_sys(SYS_SETSOCKOPT
),
1011 slice_just_addr
::<ArgReg
<SocketArg
>, _
>(&[
1023 pub(crate) fn get_socket_type(fd
: BorrowedFd
<'_
>) -> io
::Result
<SocketType
> {
1024 getsockopt(fd
, c
::SOL_SOCKET
as _
, c
::SO_TYPE
)
1028 pub(crate) fn set_socket_reuseaddr(fd
: BorrowedFd
<'_
>, reuseaddr
: bool
) -> io
::Result
<()> {
1033 from_bool(reuseaddr
),
1038 pub(crate) fn set_socket_broadcast(fd
: BorrowedFd
<'_
>, broadcast
: bool
) -> io
::Result
<()> {
1043 from_bool(broadcast
),
1048 pub(crate) fn get_socket_broadcast(fd
: BorrowedFd
<'_
>) -> io
::Result
<bool
> {
1049 getsockopt(fd
, c
::SOL_SOCKET
as _
, c
::SO_BROADCAST
).map(to_bool
)
1053 pub(crate) fn set_socket_linger(
1055 linger
: Option
<Duration
>,
1056 ) -> io
::Result
<()> {
1057 // Convert `linger` to seconds, rounding up.
1058 let l_linger
= if let Some(linger
) = linger
{
1059 let mut l_linger
= linger
.as_secs();
1060 if linger
.subsec_nanos() != 0 {
1061 l_linger
= l_linger
.checked_add(1).ok_or(io
::Errno
::INVAL
)?
;
1063 l_linger
.try_into().map_err(|_e
| io
::Errno
::INVAL
)?
1067 let linger
= c
::linger
{
1068 l_onoff
: c
::c_int
::from(linger
.is_some()),
1071 setsockopt(fd
, c
::SOL_SOCKET
as _
, c
::SO_LINGER
, linger
)
1075 pub(crate) fn get_socket_linger(fd
: BorrowedFd
<'_
>) -> io
::Result
<Option
<Duration
>> {
1076 let linger
: c
::linger
= getsockopt(fd
, c
::SOL_SOCKET
as _
, c
::SO_LINGER
)?
;
1077 Ok((linger
.l_onoff
!= 0).then(|| Duration
::from_secs(linger
.l_linger
as u64)))
1081 pub(crate) fn set_socket_passcred(fd
: BorrowedFd
<'_
>, passcred
: bool
) -> io
::Result
<()> {
1082 setsockopt(fd
, c
::SOL_SOCKET
as _
, c
::SO_PASSCRED
, from_bool(passcred
))
1086 pub(crate) fn get_socket_passcred(fd
: BorrowedFd
<'_
>) -> io
::Result
<bool
> {
1087 getsockopt(fd
, c
::SOL_SOCKET
as _
, c
::SO_PASSCRED
).map(to_bool
)
1091 pub(crate) fn set_socket_timeout(
1094 timeout
: Option
<Duration
>,
1095 ) -> io
::Result
<()> {
1096 let time
= duration_to_linux(timeout
)?
;
1097 let optname
= match id
{
1098 Timeout
::Recv
=> SO_RCVTIMEO_NEW
,
1099 Timeout
::Send
=> SO_SNDTIMEO_NEW
,
1101 match setsockopt(fd
, c
::SOL_SOCKET
, optname
, time
) {
1102 Err(io
::Errno
::NOPROTOOPT
) if SO_RCVTIMEO_NEW
!= SO_RCVTIMEO_OLD
=> {
1103 set_socket_timeout_old(fd
, id
, timeout
)
1105 otherwise
=> otherwise
,
1109 /// Same as `set_socket_timeout` but uses `timeval` instead of
1110 /// `__kernel_timespec` and `_OLD` constants instead of `_NEW`.
1111 fn set_socket_timeout_old(
1114 timeout
: Option
<Duration
>,
1115 ) -> io
::Result
<()> {
1116 let time
= duration_to_linux_old(timeout
)?
;
1117 let optname
= match id
{
1118 Timeout
::Recv
=> SO_RCVTIMEO_OLD
,
1119 Timeout
::Send
=> SO_SNDTIMEO_OLD
,
1121 setsockopt(fd
, c
::SOL_SOCKET
, optname
, time
)
1125 pub(crate) fn get_socket_timeout(
1128 ) -> io
::Result
<Option
<Duration
>> {
1129 let optname
= match id
{
1130 Timeout
::Recv
=> SO_RCVTIMEO_NEW
,
1131 Timeout
::Send
=> SO_SNDTIMEO_NEW
,
1133 let time
: __kernel_timespec
= match getsockopt(fd
, c
::SOL_SOCKET
, optname
) {
1134 Err(io
::Errno
::NOPROTOOPT
) if SO_RCVTIMEO_NEW
!= SO_RCVTIMEO_OLD
=> {
1135 return get_socket_timeout_old(fd
, id
)
1137 otherwise
=> otherwise?
,
1139 Ok(duration_from_linux(time
))
1142 /// Same as `get_socket_timeout` but uses `timeval` instead of
1143 /// `__kernel_timespec` and `_OLD` constants instead of `_NEW`.
1144 fn get_socket_timeout_old(fd
: BorrowedFd
<'_
>, id
: Timeout
) -> io
::Result
<Option
<Duration
>> {
1145 let optname
= match id
{
1146 Timeout
::Recv
=> SO_RCVTIMEO_OLD
,
1147 Timeout
::Send
=> SO_SNDTIMEO_OLD
,
1149 let time
: timeval
= getsockopt(fd
, c
::SOL_SOCKET
, optname
)?
;
1150 Ok(duration_from_linux_old(time
))
1153 /// Convert a C `timespec` to a Rust `Option<Duration>`.
1155 fn duration_from_linux(time
: __kernel_timespec
) -> Option
<Duration
> {
1156 if time
.tv_sec
== 0 && time
.tv_nsec
== 0 {
1160 Duration
::from_secs(time
.tv_sec
as u64) + Duration
::from_nanos(time
.tv_nsec
as u64),
1165 /// Like `duration_from_linux` but uses Linux's old 32-bit `timeval`.
1166 fn duration_from_linux_old(time
: timeval
) -> Option
<Duration
> {
1167 if time
.tv_sec
== 0 && time
.tv_usec
== 0 {
1171 Duration
::from_secs(time
.tv_sec
as u64)
1172 + Duration
::from_micros(time
.tv_usec
as u64),
1177 /// Convert a Rust `Option<Duration>` to a C `timespec`.
1179 fn duration_to_linux(timeout
: Option
<Duration
>) -> io
::Result
<__kernel_timespec
> {
1182 if timeout
== Duration
::ZERO
{
1183 return Err(io
::Errno
::INVAL
);
1185 let mut timeout
= __kernel_timespec
{
1186 tv_sec
: timeout
.as_secs().try_into().unwrap_or(i64::MAX
),
1187 tv_nsec
: timeout
.subsec_nanos().into(),
1189 if timeout
.tv_sec
== 0 && timeout
.tv_nsec
== 0 {
1190 timeout
.tv_nsec
= 1;
1194 None
=> __kernel_timespec
{
1201 /// Like `duration_to_linux` but uses Linux's old 32-bit `timeval`.
1202 fn duration_to_linux_old(timeout
: Option
<Duration
>) -> io
::Result
<timeval
> {
1205 if timeout
== Duration
::ZERO
{
1206 return Err(io
::Errno
::INVAL
);
1209 // `subsec_micros` rounds down, so we use `subsec_nanos` and
1210 // manually round up.
1211 let mut timeout
= timeval
{
1212 tv_sec
: timeout
.as_secs().try_into().unwrap_or(c
::c_long
::MAX
),
1213 tv_usec
: ((timeout
.subsec_nanos() + 999) / 1000) as _
,
1215 if timeout
.tv_sec
== 0 && timeout
.tv_usec
== 0 {
1216 timeout
.tv_usec
= 1;
1228 pub(crate) fn get_socket_error(fd
: BorrowedFd
<'_
>) -> io
::Result
<Result
<(), io
::Errno
>> {
1229 let err
: c
::c_int
= getsockopt(fd
, c
::SOL_SOCKET
as _
, c
::SO_ERROR
)?
;
1233 Err(io
::Errno
::from_raw_os_error(err
))
1238 pub(crate) fn set_socket_keepalive(fd
: BorrowedFd
<'_
>, keepalive
: bool
) -> io
::Result
<()> {
1243 from_bool(keepalive
),
1248 pub(crate) fn get_socket_keepalive(fd
: BorrowedFd
<'_
>) -> io
::Result
<bool
> {
1249 getsockopt(fd
, c
::SOL_SOCKET
as _
, c
::SO_KEEPALIVE
).map(to_bool
)
1253 pub(crate) fn set_socket_recv_buffer_size(fd
: BorrowedFd
<'_
>, size
: usize) -> io
::Result
<()> {
1254 let size
: c
::c_int
= size
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
;
1255 setsockopt(fd
, c
::SOL_SOCKET
as _
, c
::SO_RCVBUF
, size
)
1259 pub(crate) fn get_socket_recv_buffer_size(fd
: BorrowedFd
<'_
>) -> io
::Result
<usize> {
1260 getsockopt(fd
, c
::SOL_SOCKET
as _
, c
::SO_RCVBUF
).map(|size
: u32| size
as usize)
1264 pub(crate) fn set_socket_send_buffer_size(fd
: BorrowedFd
<'_
>, size
: usize) -> io
::Result
<()> {
1265 let size
: c
::c_int
= size
.try_into().map_err(|_
| io
::Errno
::OVERFLOW
)?
;
1266 setsockopt(fd
, c
::SOL_SOCKET
as _
, c
::SO_SNDBUF
, size
)
1270 pub(crate) fn get_socket_send_buffer_size(fd
: BorrowedFd
<'_
>) -> io
::Result
<usize> {
1271 getsockopt(fd
, c
::SOL_SOCKET
as _
, c
::SO_SNDBUF
).map(|size
: u32| size
as usize)
1275 pub(crate) fn set_ip_ttl(fd
: BorrowedFd
<'_
>, ttl
: u32) -> io
::Result
<()> {
1276 setsockopt(fd
, c
::IPPROTO_IP
as _
, c
::IP_TTL
, ttl
)
1280 pub(crate) fn get_ip_ttl(fd
: BorrowedFd
<'_
>) -> io
::Result
<u32> {
1281 getsockopt(fd
, c
::IPPROTO_IP
as _
, c
::IP_TTL
)
1285 pub(crate) fn set_ipv6_v6only(fd
: BorrowedFd
<'_
>, only_v6
: bool
) -> io
::Result
<()> {
1286 setsockopt(fd
, c
::IPPROTO_IPV6
as _
, c
::IPV6_V6ONLY
, from_bool(only_v6
))
1290 pub(crate) fn get_ipv6_v6only(fd
: BorrowedFd
<'_
>) -> io
::Result
<bool
> {
1291 getsockopt(fd
, c
::IPPROTO_IPV6
as _
, c
::IPV6_V6ONLY
).map(to_bool
)
1295 pub(crate) fn set_ip_multicast_loop(
1297 multicast_loop
: bool
,
1298 ) -> io
::Result
<()> {
1302 c
::IP_MULTICAST_LOOP
,
1303 from_bool(multicast_loop
),
1308 pub(crate) fn get_ip_multicast_loop(fd
: BorrowedFd
<'_
>) -> io
::Result
<bool
> {
1309 getsockopt(fd
, c
::IPPROTO_IP
as _
, c
::IP_MULTICAST_LOOP
).map(to_bool
)
1313 pub(crate) fn set_ip_multicast_ttl(fd
: BorrowedFd
<'_
>, multicast_ttl
: u32) -> io
::Result
<()> {
1314 setsockopt(fd
, c
::IPPROTO_IP
as _
, c
::IP_MULTICAST_TTL
, multicast_ttl
)
1318 pub(crate) fn get_ip_multicast_ttl(fd
: BorrowedFd
<'_
>) -> io
::Result
<u32> {
1319 getsockopt(fd
, c
::IPPROTO_IP
as _
, c
::IP_MULTICAST_TTL
)
1323 pub(crate) fn set_ipv6_multicast_loop(
1325 multicast_loop
: bool
,
1326 ) -> io
::Result
<()> {
1329 c
::IPPROTO_IPV6
as _
,
1330 c
::IPV6_MULTICAST_LOOP
,
1331 from_bool(multicast_loop
),
1336 pub(crate) fn get_ipv6_multicast_loop(fd
: BorrowedFd
<'_
>) -> io
::Result
<bool
> {
1337 getsockopt(fd
, c
::IPPROTO_IPV6
as _
, c
::IPV6_MULTICAST_LOOP
).map(to_bool
)
1341 pub(crate) fn set_ipv6_multicast_hops(
1343 multicast_hops
: u32,
1344 ) -> io
::Result
<()> {
1348 c
::IPV6_MULTICAST_HOPS
,
1354 pub(crate) fn get_ipv6_multicast_hops(fd
: BorrowedFd
<'_
>) -> io
::Result
<u32> {
1355 getsockopt(fd
, c
::IPPROTO_IP
as _
, c
::IPV6_MULTICAST_HOPS
)
1359 pub(crate) fn set_ip_add_membership(
1361 multiaddr
: &Ipv4Addr
,
1362 interface
: &Ipv4Addr
,
1363 ) -> io
::Result
<()> {
1364 let mreq
= to_imr(multiaddr
, interface
);
1365 setsockopt(fd
, c
::IPPROTO_IP
as _
, c
::IP_ADD_MEMBERSHIP
, mreq
)
1369 pub(crate) fn set_ipv6_add_membership(
1371 multiaddr
: &Ipv6Addr
,
1373 ) -> io
::Result
<()> {
1374 let mreq
= to_ipv6mr(multiaddr
, interface
);
1375 setsockopt(fd
, c
::IPPROTO_IPV6
as _
, c
::IPV6_ADD_MEMBERSHIP
, mreq
)
1379 pub(crate) fn set_ip_drop_membership(
1381 multiaddr
: &Ipv4Addr
,
1382 interface
: &Ipv4Addr
,
1383 ) -> io
::Result
<()> {
1384 let mreq
= to_imr(multiaddr
, interface
);
1385 setsockopt(fd
, c
::IPPROTO_IP
as _
, c
::IP_DROP_MEMBERSHIP
, mreq
)
1389 pub(crate) fn set_ipv6_drop_membership(
1391 multiaddr
: &Ipv6Addr
,
1393 ) -> io
::Result
<()> {
1394 let mreq
= to_ipv6mr(multiaddr
, interface
);
1395 setsockopt(fd
, c
::IPPROTO_IPV6
as _
, c
::IPV6_DROP_MEMBERSHIP
, mreq
)
1399 pub(crate) fn get_ipv6_unicast_hops(fd
: BorrowedFd
<'_
>) -> io
::Result
<u8> {
1400 getsockopt(fd
, c
::IPPROTO_IPV6
as _
, c
::IPV6_UNICAST_HOPS
).map(|hops
: c
::c_int
| hops
as u8)
1404 pub(crate) fn set_ipv6_unicast_hops(fd
: BorrowedFd
<'_
>, hops
: Option
<u8>) -> io
::Result
<()> {
1405 let hops
= match hops
{
1406 Some(hops
) => hops
.into(),
1409 setsockopt(fd
, c
::IPPROTO_IPV6
as _
, c
::IPV6_UNICAST_HOPS
, hops
)
1413 pub(crate) fn set_tcp_nodelay(fd
: BorrowedFd
<'_
>, nodelay
: bool
) -> io
::Result
<()> {
1414 setsockopt(fd
, c
::IPPROTO_TCP
as _
, c
::TCP_NODELAY
, from_bool(nodelay
))
1418 pub(crate) fn get_tcp_nodelay(fd
: BorrowedFd
<'_
>) -> io
::Result
<bool
> {
1419 getsockopt(fd
, c
::IPPROTO_TCP
as _
, c
::TCP_NODELAY
).map(to_bool
)
1423 fn to_imr(multiaddr
: &Ipv4Addr
, interface
: &Ipv4Addr
) -> c
::ip_mreq
{
1425 imr_multiaddr
: to_imr_addr(multiaddr
),
1426 imr_interface
: to_imr_addr(interface
),
1431 fn to_imr_addr(addr
: &Ipv4Addr
) -> c
::in_addr
{
1433 s_addr
: u32::from_ne_bytes(addr
.octets()),
1438 fn to_ipv6mr(multiaddr
: &Ipv6Addr
, interface
: u32) -> c
::ipv6_mreq
{
1440 ipv6mr_multiaddr
: to_ipv6mr_multiaddr(multiaddr
),
1441 ipv6mr_ifindex
: to_ipv6mr_interface(interface
),
1446 fn to_ipv6mr_multiaddr(multiaddr
: &Ipv6Addr
) -> c
::in6_addr
{
1448 in6_u
: linux_raw_sys
::net
::in6_addr__bindgen_ty_1
{
1449 u6_addr8
: multiaddr
.octets(),
1455 fn to_ipv6mr_interface(interface
: u32) -> c
::c_int
{
1456 interface
as c
::c_int
1460 fn from_bool(value
: bool
) -> c
::c_uint
{
1461 c
::c_uint
::from(value
)
1465 fn to_bool(value
: c
::c_uint
) -> bool
{