1 | use std::convert::TryInto; |
2 | use std::io; |
3 | use std::mem::{size_of, MaybeUninit}; |
4 | use std::net::{self, SocketAddr}; |
5 | #[cfg (not(target_os = "hermit" ))] |
6 | use std::os::fd::{AsRawFd, FromRawFd}; |
7 | // TODO: once <https://github.com/rust-lang/rust/issues/126198> is fixed this |
8 | // can use `std::os::fd` and be merged with the above. |
9 | #[cfg (target_os = "hermit" )] |
10 | use std::os::hermit::io::{AsRawFd, FromRawFd}; |
11 | |
12 | use crate::sys::unix::net::{new_socket, socket_addr, to_socket_addr}; |
13 | |
14 | pub(crate) fn new_for_addr(address: SocketAddr) -> io::Result<libc::c_int> { |
15 | let domain: i32 = match address { |
16 | SocketAddr::V4(_) => libc::AF_INET, |
17 | SocketAddr::V6(_) => libc::AF_INET6, |
18 | }; |
19 | new_socket(domain, socket_type:libc::SOCK_STREAM) |
20 | } |
21 | |
22 | pub(crate) fn bind(socket: &net::TcpListener, addr: SocketAddr) -> io::Result<()> { |
23 | let (raw_addr: SocketAddrCRepr, raw_addr_length: u32) = socket_addr(&addr); |
24 | syscall!(bind(socket.as_raw_fd(), raw_addr.as_ptr(), raw_addr_length))?; |
25 | Ok(()) |
26 | } |
27 | |
28 | pub(crate) fn connect(socket: &net::TcpStream, addr: SocketAddr) -> io::Result<()> { |
29 | let (raw_addr: SocketAddrCRepr, raw_addr_length: u32) = socket_addr(&addr); |
30 | |
31 | match syscall!(connect( |
32 | socket.as_raw_fd(), |
33 | raw_addr.as_ptr(), |
34 | raw_addr_length |
35 | )) { |
36 | Err(err: Error) if err.raw_os_error() != Some(libc::EINPROGRESS) => Err(err), |
37 | _ => Ok(()), |
38 | } |
39 | } |
40 | |
41 | pub(crate) fn listen(socket: &net::TcpListener, backlog: u32) -> io::Result<()> { |
42 | let backlog: i32 = backlog.try_into().unwrap_or(default:i32::MAX); |
43 | syscall!(listen(socket.as_raw_fd(), backlog))?; |
44 | Ok(()) |
45 | } |
46 | |
47 | pub(crate) fn set_reuseaddr(socket: &net::TcpListener, reuseaddr: bool) -> io::Result<()> { |
48 | let val: libc::c_int = i32::from(reuseaddr); |
49 | syscall!(setsockopt( |
50 | socket.as_raw_fd(), |
51 | libc::SOL_SOCKET, |
52 | libc::SO_REUSEADDR, |
53 | &val as *const libc::c_int as *const libc::c_void, |
54 | size_of::<libc::c_int>() as libc::socklen_t, |
55 | ))?; |
56 | Ok(()) |
57 | } |
58 | |
59 | pub(crate) fn accept(listener: &net::TcpListener) -> io::Result<(net::TcpStream, SocketAddr)> { |
60 | let mut addr: MaybeUninit<libc::sockaddr_storage> = MaybeUninit::uninit(); |
61 | let mut length = size_of::<libc::sockaddr_storage>() as libc::socklen_t; |
62 | |
63 | // On platforms that support it we can use `accept4(2)` to set `NONBLOCK` |
64 | // and `CLOEXEC` in the call to accept the connection. |
65 | #[cfg (any( |
66 | // Android x86's seccomp profile forbids calls to `accept4(2)` |
67 | // See https://github.com/tokio-rs/mio/issues/1445 for details |
68 | all(not(target_arch="x86" ), target_os = "android" ), |
69 | target_os = "dragonfly" , |
70 | target_os = "freebsd" , |
71 | target_os = "fuchsia" , |
72 | target_os = "hurd" , |
73 | target_os = "illumos" , |
74 | target_os = "linux" , |
75 | target_os = "netbsd" , |
76 | target_os = "openbsd" , |
77 | target_os = "solaris" , |
78 | ))] |
79 | let stream = { |
80 | syscall!(accept4( |
81 | listener.as_raw_fd(), |
82 | addr.as_mut_ptr() as *mut _, |
83 | &mut length, |
84 | libc::SOCK_CLOEXEC | libc::SOCK_NONBLOCK, |
85 | )) |
86 | .map(|socket| unsafe { net::TcpStream::from_raw_fd(socket) }) |
87 | }?; |
88 | |
89 | // But not all platforms have the `accept4(2)` call. Luckily BSD (derived) |
90 | // OSs inherit the non-blocking flag from the listener, so we just have to |
91 | // set `CLOEXEC`. |
92 | #[cfg (any( |
93 | target_os = "aix" , |
94 | target_os = "haiku" , |
95 | target_os = "ios" , |
96 | target_os = "macos" , |
97 | target_os = "redox" , |
98 | target_os = "tvos" , |
99 | target_os = "visionos" , |
100 | target_os = "watchos" , |
101 | target_os = "espidf" , |
102 | target_os = "vita" , |
103 | target_os = "hermit" , |
104 | target_os = "nto" , |
105 | all(target_arch = "x86" , target_os = "android" ), |
106 | ))] |
107 | let stream = { |
108 | syscall!(accept( |
109 | listener.as_raw_fd(), |
110 | addr.as_mut_ptr() as *mut _, |
111 | &mut length |
112 | )) |
113 | .map(|socket| unsafe { net::TcpStream::from_raw_fd(socket) }) |
114 | .and_then(|s| { |
115 | #[cfg (not(any(target_os = "espidf" , target_os = "vita" )))] |
116 | syscall!(fcntl(s.as_raw_fd(), libc::F_SETFD, libc::FD_CLOEXEC))?; |
117 | |
118 | // See https://github.com/tokio-rs/mio/issues/1450 |
119 | #[cfg (any( |
120 | all(target_arch = "x86" , target_os = "android" ), |
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 | // This is safe because `accept` calls above ensures the address |
133 | // initialised. |
134 | unsafe { to_socket_addr(addr.as_ptr()) }.map(|addr| (stream, addr)) |
135 | } |
136 | |