1use std::io;
2use std::mem::{size_of, MaybeUninit};
3use std::net::{self, SocketAddr};
4#[cfg(not(target_os = "hermit"))]
5use std::os::fd::{AsRawFd, FromRawFd};
6#[cfg(target_os = "hermit")]
9use std::os::hermit::io::{AsRawFd, FromRawFd};
10
11use crate::sys::unix::net::{new_socket, socket_addr, to_socket_addr};
12
13pub(crate) fn new_for_addr(address: SocketAddr) -> io::Result<libc::c_int> {
14 let domain = match address {
15 SocketAddr::V4(_) => libc::AF_INET,
16 SocketAddr::V6(_) => libc::AF_INET6,
17 };
18 new_socket(domain, libc::SOCK_STREAM)
19}
20
21pub(crate) fn bind(socket: &net::TcpListener, addr: SocketAddr) -> io::Result<()> {
22 let (raw_addr, raw_addr_length) = socket_addr(&addr);
23 syscall!(bind(socket.as_raw_fd(), raw_addr.as_ptr(), raw_addr_length))?;
24 Ok(())
25}
26
27pub(crate) fn connect(socket: &net::TcpStream, addr: SocketAddr) -> io::Result<()> {
28 let (raw_addr, raw_addr_length) = socket_addr(&addr);
29
30 match syscall!(connect(
31 socket.as_raw_fd(),
32 raw_addr.as_ptr(),
33 raw_addr_length
34 )) {
35 Err(err) if err.raw_os_error() != Some(libc::EINPROGRESS) => Err(err),
36 _ => Ok(()),
37 }
38}
39
40pub(crate) fn listen(socket: &net::TcpListener, backlog: i32) -> io::Result<()> {
41 syscall!(listen(socket.as_raw_fd(), backlog))?;
42 Ok(())
43}
44
45pub(crate) fn set_reuseaddr(socket: &net::TcpListener, reuseaddr: bool) -> io::Result<()> {
46 let val: libc::c_int = i32::from(reuseaddr);
47 syscall!(setsockopt(
48 socket.as_raw_fd(),
49 libc::SOL_SOCKET,
50 libc::SO_REUSEADDR,
51 &val as *const libc::c_int as *const libc::c_void,
52 size_of::<libc::c_int>() as libc::socklen_t,
53 ))?;
54 Ok(())
55}
56
57pub(crate) fn accept(listener: &net::TcpListener) -> io::Result<(net::TcpStream, SocketAddr)> {
58 let mut addr: MaybeUninit<libc::sockaddr_storage> = MaybeUninit::uninit();
59 let mut length = size_of::<libc::sockaddr_storage>() as libc::socklen_t;
60
61 #[cfg(any(
64 all(not(target_arch="x86"), target_os = "android"),
67 target_os = "dragonfly",
68 target_os = "freebsd",
69 target_os = "fuchsia",
70 target_os = "hurd",
71 target_os = "illumos",
72 target_os = "linux",
73 target_os = "netbsd",
74 target_os = "openbsd",
75 target_os = "solaris",
76 target_os = "cygwin",
77 ))]
78 let stream = {
79 syscall!(accept4(
80 listener.as_raw_fd(),
81 addr.as_mut_ptr() as *mut _,
82 &mut length,
83 libc::SOCK_CLOEXEC | libc::SOCK_NONBLOCK,
84 ))
85 .map(|socket| unsafe { net::TcpStream::from_raw_fd(socket) })
86 }?;
87
88 #[cfg(any(
92 target_os = "aix",
93 target_os = "haiku",
94 target_os = "ios",
95 target_os = "macos",
96 target_os = "redox",
97 target_os = "tvos",
98 target_os = "visionos",
99 target_os = "watchos",
100 target_os = "espidf",
101 target_os = "vita",
102 target_os = "hermit",
103 target_os = "nto",
104 all(target_arch = "x86", target_os = "android"),
105 ))]
106 let stream = {
107 syscall!(accept(
108 listener.as_raw_fd(),
109 addr.as_mut_ptr() as *mut _,
110 &mut length
111 ))
112 .map(|socket| unsafe { net::TcpStream::from_raw_fd(socket) })
113 .and_then(|s| {
114 #[cfg(not(any(target_os = "espidf", target_os = "vita")))]
115 syscall!(fcntl(s.as_raw_fd(), libc::F_SETFD, libc::FD_CLOEXEC))?;
116
117 #[cfg(any(
119 all(target_arch = "x86", target_os = "android"),
120 target_os = "aix",
121 target_os = "espidf",
122 target_os = "vita",
123 target_os = "hermit",
124 target_os = "nto",
125 ))]
126 syscall!(fcntl(s.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK))?;
127
128 Ok(s)
129 })
130 }?;
131
132 unsafe { to_socket_addr(addr.as_ptr()) }.map(|addr| (stream, addr))
135}