1use super::socket_addr;
2use crate::net::{SocketAddr, UnixStream};
3use crate::sys::unix::net::new_socket;
4use std::os::unix::ffi::OsStrExt;
5use std::os::unix::io::{AsRawFd, FromRawFd};
6use std::os::unix::net;
7use std::path::Path;
8use std::{io, mem};
9
10pub(crate) fn bind(path: &Path) -> io::Result<net::UnixListener> {
11 let socket_address: SocketAddr = {
12 let (sockaddr: sockaddr_un, socklen: u32) = socket_addr(path.as_os_str().as_bytes())?;
13 SocketAddr::from_parts(sockaddr, socklen)
14 };
15
16 bind_addr(&socket_address)
17}
18
19pub(crate) fn bind_addr(address: &SocketAddr) -> io::Result<net::UnixListener> {
20 let fd: i32 = new_socket(domain:libc::AF_UNIX, socket_type:libc::SOCK_STREAM)?;
21 let socket: UnixListener = unsafe { net::UnixListener::from_raw_fd(fd) };
22 let sockaddr: *const sockaddr = address.raw_sockaddr() as *const libc::sockaddr_un as *const libc::sockaddr;
23
24 syscall!(bind(fd, sockaddr, *address.raw_socklen()))?;
25 syscall!(listen(fd, 1024))?;
26
27 Ok(socket)
28}
29
30pub(crate) fn accept(listener: &net::UnixListener) -> io::Result<(UnixStream, SocketAddr)> {
31 let sockaddr = mem::MaybeUninit::<libc::sockaddr_un>::zeroed();
32
33 // This is safe to assume because a `libc::sockaddr_un` filled with `0`
34 // bytes is properly initialized.
35 //
36 // `0` is a valid value for `sockaddr_un::sun_family`; it is
37 // `libc::AF_UNSPEC`.
38 //
39 // `[0; 108]` is a valid value for `sockaddr_un::sun_path`; it begins an
40 // abstract path.
41 let mut sockaddr = unsafe { sockaddr.assume_init() };
42
43 sockaddr.sun_family = libc::AF_UNIX as libc::sa_family_t;
44 let mut socklen = mem::size_of_val(&sockaddr) as libc::socklen_t;
45
46 #[cfg(not(any(
47 target_os = "aix",
48 target_os = "ios",
49 target_os = "macos",
50 target_os = "netbsd",
51 target_os = "redox",
52 target_os = "tvos",
53 target_os = "watchos",
54 target_os = "espidf",
55 target_os = "vita",
56 // Android x86's seccomp profile forbids calls to `accept4(2)`
57 // See https://github.com/tokio-rs/mio/issues/1445 for details
58 all(target_arch = "x86", target_os = "android"),
59 )))]
60 let socket = {
61 let flags = libc::SOCK_NONBLOCK | libc::SOCK_CLOEXEC;
62 syscall!(accept4(
63 listener.as_raw_fd(),
64 &mut sockaddr as *mut libc::sockaddr_un as *mut libc::sockaddr,
65 &mut socklen,
66 flags
67 ))
68 .map(|socket| unsafe { net::UnixStream::from_raw_fd(socket) })
69 };
70
71 #[cfg(any(
72 target_os = "aix",
73 target_os = "ios",
74 target_os = "macos",
75 target_os = "netbsd",
76 target_os = "redox",
77 target_os = "tvos",
78 target_os = "watchos",
79 target_os = "espidf",
80 target_os = "vita",
81 all(target_arch = "x86", target_os = "android")
82 ))]
83 let socket = syscall!(accept(
84 listener.as_raw_fd(),
85 &mut sockaddr as *mut libc::sockaddr_un as *mut libc::sockaddr,
86 &mut socklen,
87 ))
88 .and_then(|socket| {
89 // Ensure the socket is closed if either of the `fcntl` calls
90 // error below.
91 let s = unsafe { net::UnixStream::from_raw_fd(socket) };
92 #[cfg(not(any(target_os = "espidf", target_os = "vita")))]
93 syscall!(fcntl(socket, libc::F_SETFD, libc::FD_CLOEXEC))?;
94
95 // See https://github.com/tokio-rs/mio/issues/1450
96 #[cfg(any(
97 all(target_arch = "x86", target_os = "android"),
98 target_os = "espidf",
99 target_os = "vita",
100 ))]
101 syscall!(fcntl(socket, libc::F_SETFL, libc::O_NONBLOCK))?;
102
103 Ok(s)
104 });
105
106 socket
107 .map(UnixStream::from_std)
108 .map(|stream| (stream, SocketAddr::from_parts(sockaddr, socklen)))
109}
110
111pub(crate) fn local_addr(listener: &net::UnixListener) -> io::Result<SocketAddr> {
112 super::local_addr(socket:listener.as_raw_fd())
113}
114