1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
mod socketaddr;
pub use self::socketaddr::SocketAddr;
pub(in crate::sys) fn path_offset(sockaddr: &libc::sockaddr_un) -> usize {
let base = sockaddr as *const _ as usize;
let path = &sockaddr.sun_path as *const _ as usize;
path - base
}
cfg_os_poll! {
use std::cmp::Ordering;
use std::os::unix::ffi::OsStrExt;
use std::os::unix::io::{RawFd, FromRawFd};
use std::path::Path;
use std::{io, mem};
pub(crate) mod datagram;
pub(crate) mod listener;
pub(crate) mod stream;
pub(in crate::sys) fn socket_addr(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
let sockaddr = mem::MaybeUninit::<libc::sockaddr_un>::zeroed();
let mut sockaddr = unsafe { sockaddr.assume_init() };
sockaddr.sun_family = libc::AF_UNIX as libc::sa_family_t;
let bytes = path.as_os_str().as_bytes();
match (bytes.first(), bytes.len().cmp(&sockaddr.sun_path.len())) {
(Some(&0), Ordering::Greater) => {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"path must be no longer than libc::sockaddr_un.sun_path",
));
}
(_, Ordering::Greater) | (_, Ordering::Equal) => {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"path must be shorter than libc::sockaddr_un.sun_path",
));
}
_ => {}
}
for (dst, src) in sockaddr.sun_path.iter_mut().zip(bytes.iter()) {
*dst = *src as libc::c_char;
}
let offset = path_offset(&sockaddr);
let mut socklen = offset + bytes.len();
match bytes.first() {
Some(&0) | None => {}
Some(_) => socklen += 1,
}
Ok((sockaddr, socklen as libc::socklen_t))
}
fn pair<T>(flags: libc::c_int) -> io::Result<(T, T)>
where T: FromRawFd,
{
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
let flags = flags | libc::SOCK_NONBLOCK | libc::SOCK_CLOEXEC;
let mut fds = [-1; 2];
syscall!(socketpair(libc::AF_UNIX, flags, 0, fds.as_mut_ptr()))?;
let pair = unsafe { (T::from_raw_fd(fds[0]), T::from_raw_fd(fds[1])) };
#[cfg(any(target_os = "ios", target_os = "macos"))]
{
syscall!(fcntl(fds[0], libc::F_SETFL, libc::O_NONBLOCK))?;
syscall!(fcntl(fds[0], libc::F_SETFD, libc::FD_CLOEXEC))?;
syscall!(fcntl(fds[1], libc::F_SETFL, libc::O_NONBLOCK))?;
syscall!(fcntl(fds[1], libc::F_SETFD, libc::FD_CLOEXEC))?;
}
Ok(pair)
}
fn local_addr(socket: RawFd) -> io::Result<SocketAddr> {
SocketAddr::new(|sockaddr, socklen| syscall!(getsockname(socket, sockaddr, socklen)))
}
fn peer_addr(socket: RawFd) -> io::Result<SocketAddr> {
SocketAddr::new(|sockaddr, socklen| syscall!(getpeername(socket, sockaddr, socklen)))
}
#[cfg(test)]
mod tests {
use super::{path_offset, socket_addr};
use std::path::Path;
use std::str;
#[test]
fn pathname_address() {
const PATH: &str = "./foo/bar.txt";
const PATH_LEN: usize = 13;
let path = Path::new(PATH);
let (sockaddr, actual) = socket_addr(path).unwrap();
let offset = path_offset(&sockaddr);
let expected = PATH_LEN + offset + 1;
assert_eq!(expected as libc::socklen_t, actual)
}
#[test]
fn abstract_address() {
const PATH: &[u8] = &[0, 116, 111, 107, 105, 111];
const PATH_LEN: usize = 6;
let abstract_path = str::from_utf8(PATH).unwrap();
let path = Path::new(abstract_path);
let (sockaddr, actual) = socket_addr(path).unwrap();
let offset = path_offset(&sockaddr);
let expected = PATH_LEN + offset;
assert_eq!(expected as libc::socklen_t, actual)
}
}
}