1 use std::ffi::OsStr;
2 use std::os::fd::{AsRawFd, FromRawFd};
3 use std::os::unix::ffi::OsStrExt;
4 use std::os::unix::net::{self, SocketAddr};
5 use std::path::Path;
6 use std::{io, mem};
7 
8 use crate::net::UnixStream;
9 use crate::sys::unix::net::new_socket;
10 use crate::sys::unix::uds::{path_offset, unix_addr};
11 
bind_addr(address: &SocketAddr) -> io::Result<net::UnixListener>12 pub(crate) fn bind_addr(address: &SocketAddr) -> io::Result<net::UnixListener> {
13     let fd = new_socket(libc::AF_UNIX, libc::SOCK_STREAM)?;
14     let socket = unsafe { net::UnixListener::from_raw_fd(fd) };
15 
16     let (unix_address, addrlen) = unix_addr(address);
17     let sockaddr = &unix_address as *const libc::sockaddr_un as *const libc::sockaddr;
18     syscall!(bind(fd, sockaddr, addrlen))?;
19     syscall!(listen(fd, 1024))?;
20 
21     Ok(socket)
22 }
23 
accept(listener: &net::UnixListener) -> io::Result<(UnixStream, SocketAddr)>24 pub(crate) fn accept(listener: &net::UnixListener) -> io::Result<(UnixStream, SocketAddr)> {
25     // SAFETY: `libc::sockaddr_un` zero filled is properly initialized.
26     //
27     // `0` is a valid value for `sockaddr_un::sun_family`; it is
28     // `libc::AF_UNSPEC`.
29     //
30     // `[0; 108]` is a valid value for `sockaddr_un::sun_path`; it begins an
31     // abstract path.
32     let mut sockaddr = unsafe { mem::zeroed::<libc::sockaddr_un>() };
33 
34     let mut socklen = mem::size_of_val(&sockaddr) as libc::socklen_t;
35 
36     #[cfg(not(any(
37         target_os = "aix",
38         target_os = "haiku",
39         target_os = "ios",
40         target_os = "macos",
41         target_os = "netbsd",
42         target_os = "redox",
43         target_os = "tvos",
44         target_os = "visionos",
45         target_os = "watchos",
46         target_os = "espidf",
47         target_os = "vita",
48         target_os = "nto",
49         // Android x86's seccomp profile forbids calls to `accept4(2)`
50         // See https://github.com/tokio-rs/mio/issues/1445 for details
51         all(target_arch = "x86", target_os = "android"),
52     )))]
53     let socket = {
54         let flags = libc::SOCK_NONBLOCK | libc::SOCK_CLOEXEC;
55         syscall!(accept4(
56             listener.as_raw_fd(),
57             &mut sockaddr as *mut libc::sockaddr_un as *mut libc::sockaddr,
58             &mut socklen,
59             flags
60         ))
61         .map(|socket| unsafe { net::UnixStream::from_raw_fd(socket) })
62     };
63 
64     #[cfg(any(
65         target_os = "aix",
66         target_os = "haiku",
67         target_os = "ios",
68         target_os = "macos",
69         target_os = "netbsd",
70         target_os = "redox",
71         target_os = "tvos",
72         target_os = "visionos",
73         target_os = "watchos",
74         target_os = "espidf",
75         target_os = "vita",
76         target_os = "nto",
77         all(target_arch = "x86", target_os = "android")
78     ))]
79     let socket = syscall!(accept(
80         listener.as_raw_fd(),
81         &mut sockaddr as *mut libc::sockaddr_un as *mut libc::sockaddr,
82         &mut socklen,
83     ))
84     .and_then(|socket| {
85         // Ensure the socket is closed if either of the `fcntl` calls
86         // error below.
87         let s = unsafe { net::UnixStream::from_raw_fd(socket) };
88         #[cfg(not(any(target_os = "espidf", target_os = "vita")))]
89         syscall!(fcntl(socket, libc::F_SETFD, libc::FD_CLOEXEC))?;
90 
91         // See https://github.com/tokio-rs/mio/issues/1450
92         #[cfg(any(
93             all(target_arch = "x86", target_os = "android"),
94             target_os = "espidf",
95             target_os = "vita",
96             target_os = "nto",
97         ))]
98         syscall!(fcntl(socket, libc::F_SETFL, libc::O_NONBLOCK))?;
99 
100         Ok(s)
101     });
102 
103     let socket = socket.map(UnixStream::from_std)?;
104 
105     #[allow(unused_mut)] // See below.
106     let mut path_len = socklen as usize - path_offset(&sockaddr);
107     // On FreeBSD and Darwin, it returns a length of 14/16, but an unnamed (all
108     // zero) address. Map that to a length of 0 to match other OS.
109     if sockaddr.sun_path[0] == 0 {
110         path_len = 0;
111     }
112     // SAFETY: going from i8 to u8 is fine in this context.
113     let mut path =
114         unsafe { &*(&sockaddr.sun_path[..path_len] as *const [libc::c_char] as *const [u8]) };
115     // Remove last null as `SocketAddr::from_pathname` doesn't accept it.
116     if let Some(0) = path.last() {
117         path = &path[..path.len() - 1];
118     }
119     let address = SocketAddr::from_pathname(Path::new(OsStr::from_bytes(path)))?;
120     Ok((socket, address))
121 }
122