mio/sys/unix/uds/
listener.rs1use std::ffi::OsStr;
2use std::os::fd::{AsRawFd, FromRawFd};
3use std::os::unix::ffi::OsStrExt;
4use std::os::unix::net::{self, SocketAddr};
5use std::path::Path;
6use std::{io, mem};
7
8use crate::net::UnixStream;
9use crate::sys::unix::net::new_socket;
10use crate::sys::unix::uds::{path_offset, unix_addr};
11use crate::sys::LISTEN_BACKLOG_SIZE;
12
13pub(crate) fn bind_addr(address: &SocketAddr) -> io::Result<net::UnixListener> {
14    let fd = new_socket(libc::AF_UNIX, libc::SOCK_STREAM)?;
15    let socket = unsafe { net::UnixListener::from_raw_fd(fd) };
16
17    let (unix_address, addrlen) = unix_addr(address);
18    let sockaddr = &unix_address as *const libc::sockaddr_un as *const libc::sockaddr;
19    syscall!(bind(fd, sockaddr, addrlen))?;
20    syscall!(listen(fd, LISTEN_BACKLOG_SIZE))?;
21
22    Ok(socket)
23}
24
25pub(crate) fn accept(listener: &net::UnixListener) -> io::Result<(UnixStream, SocketAddr)> {
26    let mut sockaddr = unsafe { mem::zeroed::<libc::sockaddr_un>() };
34
35    let mut socklen = mem::size_of_val(&sockaddr) as libc::socklen_t;
36
37    #[cfg(not(any(
38        target_os = "aix",
39        target_os = "haiku",
40        target_os = "ios",
41        target_os = "macos",
42        target_os = "netbsd",
43        target_os = "redox",
44        target_os = "tvos",
45        target_os = "visionos",
46        target_os = "watchos",
47        target_os = "espidf",
48        target_os = "vita",
49        target_os = "nto",
50        all(target_arch = "x86", target_os = "android"),
53    )))]
54    let socket = {
55        let flags = libc::SOCK_NONBLOCK | libc::SOCK_CLOEXEC;
56        syscall!(accept4(
57            listener.as_raw_fd(),
58            &mut sockaddr as *mut libc::sockaddr_un as *mut libc::sockaddr,
59            &mut socklen,
60            flags
61        ))
62        .map(|socket| unsafe { net::UnixStream::from_raw_fd(socket) })
63    };
64
65    #[cfg(any(
66        target_os = "aix",
67        target_os = "haiku",
68        target_os = "ios",
69        target_os = "macos",
70        target_os = "netbsd",
71        target_os = "redox",
72        target_os = "tvos",
73        target_os = "visionos",
74        target_os = "watchos",
75        target_os = "espidf",
76        target_os = "vita",
77        target_os = "nto",
78        all(target_arch = "x86", target_os = "android")
79    ))]
80    let socket = syscall!(accept(
81        listener.as_raw_fd(),
82        &mut sockaddr as *mut libc::sockaddr_un as *mut libc::sockaddr,
83        &mut socklen,
84    ))
85    .and_then(|socket| {
86        let s = unsafe { net::UnixStream::from_raw_fd(socket) };
89        #[cfg(not(any(target_os = "espidf", target_os = "vita")))]
90        syscall!(fcntl(socket, libc::F_SETFD, libc::FD_CLOEXEC))?;
91
92        #[cfg(any(
94            all(target_arch = "x86", target_os = "android"),
95            target_os = "espidf",
96            target_os = "vita",
97            target_os = "nto",
98        ))]
99        syscall!(fcntl(socket, libc::F_SETFL, libc::O_NONBLOCK))?;
100
101        Ok(s)
102    });
103
104    let socket = socket.map(UnixStream::from_std)?;
105
106    #[allow(unused_mut)] let mut path_len = socklen as usize - path_offset(&sockaddr);
108    if sockaddr.sun_path[0] == 0 {
111        path_len = 0;
112    }
113    let mut path =
115        unsafe { &*(&sockaddr.sun_path[..path_len] as *const [libc::c_char] as *const [u8]) };
116    if let Some(0) = path.last() {
118        path = &path[..path.len() - 1];
119    }
120    let address = SocketAddr::from_pathname(Path::new(OsStr::from_bytes(path)))?;
121    Ok((socket, address))
122}