1#[cfg(target_os = "android")]
2use std::os::android::net::SocketAddrExt;
3#[cfg(target_os = "linux")]
4use std::os::linux::net::SocketAddrExt;
5use std::os::unix::ffi::OsStrExt;
6use std::os::unix::io::FromRawFd;
7use std::os::unix::net::SocketAddr;
8use std::{io, mem, ptr};
9
10pub(crate) mod datagram;
11pub(crate) mod listener;
12pub(crate) mod stream;
13
14const UNNAMED_ADDRESS: &[u8] = &[];
15
16fn path_offset(sockaddr: &libc::sockaddr_un) -> usize {
23 let base = sockaddr as *const _ as usize;
24 let path = &sockaddr.sun_path as *const _ as usize;
25 path - base
26}
27
28fn unix_addr(address: &SocketAddr) -> (libc::sockaddr_un, libc::socklen_t) {
30 let mut sockaddr = unsafe { mem::zeroed::<libc::sockaddr_un>() };
38
39 sockaddr.sun_family = libc::AF_UNIX as libc::sa_family_t;
40
41 #[allow(unused_mut)] let mut offset = 0;
43 let addr = match address.as_pathname() {
44 Some(path) => path.as_os_str().as_bytes(),
45 #[cfg(any(target_os = "android", target_os = "linux"))]
46 None => match address.as_abstract_name() {
47 Some(name) => {
48 offset += 1;
49 name
50 }
51 None => UNNAMED_ADDRESS,
52 },
53 #[cfg(not(any(target_os = "android", target_os = "linux")))]
54 None => UNNAMED_ADDRESS,
55 };
56
57 debug_assert!(offset + addr.len() <= sockaddr.sun_path.len());
63 unsafe {
64 ptr::copy_nonoverlapping(
65 addr.as_ptr(),
66 sockaddr.sun_path.as_mut_ptr().add(offset).cast(),
67 addr.len(),
68 )
69 };
70
71 let mut addrlen = path_offset(&sockaddr) + addr.len();
72 match addr.first() {
75 Some(&0) | None => {}
76 Some(_) => addrlen += 1,
77 }
78
79 (sockaddr, addrlen as _)
82}
83
84fn pair<T>(flags: libc::c_int) -> io::Result<(T, T)>
85where
86 T: FromRawFd,
87{
88 #[cfg(not(any(
89 target_os = "aix",
90 target_os = "haiku",
91 target_os = "ios",
92 target_os = "macos",
93 target_os = "nto",
94 target_os = "tvos",
95 target_os = "visionos",
96 target_os = "watchos",
97 target_os = "espidf",
98 target_os = "vita",
99 target_os = "horizon",
100 )))]
101 let flags = flags | libc::SOCK_NONBLOCK | libc::SOCK_CLOEXEC;
102
103 let mut fds = [-1; 2];
104 syscall!(socketpair(libc::AF_UNIX, flags, 0, fds.as_mut_ptr()))?;
105 let pair = unsafe { (T::from_raw_fd(fds[0]), T::from_raw_fd(fds[1])) };
106
107 #[cfg(any(
114 target_os = "aix",
115 target_os = "haiku",
116 target_os = "ios",
117 target_os = "macos",
118 target_os = "nto",
119 target_os = "tvos",
120 target_os = "visionos",
121 target_os = "watchos",
122 target_os = "espidf",
123 target_os = "vita",
124 target_os = "horizon"
125 ))]
126 {
127 syscall!(fcntl(fds[0], libc::F_SETFL, libc::O_NONBLOCK))?;
128 #[cfg(not(any(target_os = "espidf", target_os = "vita", target_os = "nto")))]
129 syscall!(fcntl(fds[0], libc::F_SETFD, libc::FD_CLOEXEC))?;
130 syscall!(fcntl(fds[1], libc::F_SETFL, libc::O_NONBLOCK))?;
131 #[cfg(not(any(target_os = "espidf", target_os = "vita", target_os = "nto")))]
132 syscall!(fcntl(fds[1], libc::F_SETFD, libc::FD_CLOEXEC))?;
133 }
134
135 Ok(pair)
136}
137
138#[cfg(test)]
139mod tests {
140 use std::os::unix::net::SocketAddr;
141 use std::path::Path;
142 use std::str;
143
144 use super::{path_offset, unix_addr};
145
146 #[test]
147 fn pathname_address() {
148 const PATH: &str = "./foo/bar.txt";
149 const PATH_LEN: usize = 13;
150
151 let address = SocketAddr::from_pathname(Path::new(PATH)).unwrap();
154 let (sockaddr, actual) = unix_addr(&address);
155 let offset = path_offset(&sockaddr);
156 let expected = PATH_LEN + offset + 1;
157 assert_eq!(expected as libc::socklen_t, actual)
158 }
159
160 #[test]
161 #[cfg(any(target_os = "android", target_os = "linux"))]
162 fn abstract_address() {
163 #[cfg(target_os = "android")]
164 use std::os::android::net::SocketAddrExt;
165 #[cfg(target_os = "linux")]
166 use std::os::linux::net::SocketAddrExt;
167
168 const PATH: &[u8] = &[0, 116, 111, 107, 105, 111];
169 const PATH_LEN: usize = 6;
170
171 let address = SocketAddr::from_abstract_name(PATH).unwrap();
174 let (sockaddr, actual) = unix_addr(&address);
175 let offset = path_offset(&sockaddr);
176 let expected = PATH_LEN + offset;
177 assert_eq!(expected as libc::socklen_t, actual)
178 }
179}