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 | |
12 | pub(crate) fn bind_addr(address: &SocketAddr) -> io::Result<net::UnixListener> { |
13 | let fd: i32 = new_socket(domain:libc::AF_UNIX, socket_type:libc::SOCK_STREAM)?; |
14 | let socket: UnixListener = unsafe { net::UnixListener::from_raw_fd(fd) }; |
15 | |
16 | let (unix_address: sockaddr_un, addrlen: u32) = unix_addr(address); |
17 | let sockaddr: *const 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 | |
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 | |