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