]> git.proxmox.com Git - rustc.git/blob - vendor/mio/src/sys/unix/uds.rs
New upstream version 1.46.0~beta.2+dfsg1
[rustc.git] / vendor / mio / src / sys / unix / uds.rs
1 use std::io::{Read, Write};
2 use std::mem;
3 use std::net::Shutdown;
4 use std::os::unix::prelude::*;
5 use std::path::Path;
6 use std::ptr;
7
8 use libc;
9
10 use {io, Ready, Poll, PollOpt, Token};
11 use event::Evented;
12 use sys::unix::{cvt, Io};
13 use sys::unix::io::{set_nonblock, set_cloexec};
14
15 trait MyInto<T> {
16 fn my_into(self) -> T;
17 }
18
19 impl MyInto<u32> for usize {
20 fn my_into(self) -> u32 { self as u32 }
21 }
22
23 impl MyInto<usize> for usize {
24 fn my_into(self) -> usize { self }
25 }
26
27 unsafe fn sockaddr_un(path: &Path)
28 -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
29 let mut addr: libc::sockaddr_un = mem::zeroed();
30 addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
31
32 let bytes = path.as_os_str().as_bytes();
33
34 if bytes.len() >= addr.sun_path.len() {
35 return Err(io::Error::new(io::ErrorKind::InvalidInput,
36 "path must be shorter than SUN_LEN"))
37 }
38 for (dst, src) in addr.sun_path.iter_mut().zip(bytes.iter()) {
39 *dst = *src as libc::c_char;
40 }
41 // null byte for pathname addresses is already there because we zeroed the
42 // struct
43
44 let mut len = sun_path_offset() + bytes.len();
45 match bytes.get(0) {
46 Some(&0) | None => {}
47 Some(_) => len += 1,
48 }
49 Ok((addr, len as libc::socklen_t))
50 }
51
52 fn sun_path_offset() -> usize {
53 unsafe {
54 // Work with an actual instance of the type since using a null pointer is UB
55 let addr: libc::sockaddr_un = mem::uninitialized();
56 let base = &addr as *const _ as usize;
57 let path = &addr.sun_path as *const _ as usize;
58 path - base
59 }
60 }
61
62 #[derive(Debug)]
63 pub struct UnixSocket {
64 io: Io,
65 }
66
67 impl UnixSocket {
68 /// Returns a new, unbound, non-blocking Unix domain socket
69 pub fn stream() -> io::Result<UnixSocket> {
70 #[cfg(target_os = "linux")]
71 use libc::{SOCK_CLOEXEC, SOCK_NONBLOCK};
72 #[cfg(not(target_os = "linux"))]
73 const SOCK_CLOEXEC: libc::c_int = 0;
74 #[cfg(not(target_os = "linux"))]
75 const SOCK_NONBLOCK: libc::c_int = 0;
76
77 unsafe {
78 if cfg!(target_os = "linux") {
79 let flags = libc::SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK;
80 match cvt(libc::socket(libc::AF_UNIX, flags, 0)) {
81 Ok(fd) => return Ok(UnixSocket::from_raw_fd(fd)),
82 Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {}
83 Err(e) => return Err(e),
84 }
85 }
86
87 let fd = cvt(libc::socket(libc::AF_UNIX, libc::SOCK_STREAM, 0))?;
88 let fd = UnixSocket::from_raw_fd(fd);
89 set_cloexec(fd.as_raw_fd())?;
90 set_nonblock(fd.as_raw_fd())?;
91 Ok(fd)
92 }
93 }
94
95 /// Connect the socket to the specified address
96 pub fn connect<P: AsRef<Path> + ?Sized>(&self, addr: &P) -> io::Result<()> {
97 unsafe {
98 let (addr, len) = sockaddr_un(addr.as_ref())?;
99 cvt(libc::connect(self.as_raw_fd(),
100 &addr as *const _ as *const _,
101 len))?;
102 Ok(())
103 }
104 }
105
106 /// Listen for incoming requests
107 pub fn listen(&self, backlog: usize) -> io::Result<()> {
108 unsafe {
109 cvt(libc::listen(self.as_raw_fd(), backlog as i32))?;
110 Ok(())
111 }
112 }
113
114 pub fn accept(&self) -> io::Result<UnixSocket> {
115 unsafe {
116 let fd = cvt(libc::accept(self.as_raw_fd(),
117 ptr::null_mut(),
118 ptr::null_mut()))?;
119 let fd = Io::from_raw_fd(fd);
120 set_cloexec(fd.as_raw_fd())?;
121 set_nonblock(fd.as_raw_fd())?;
122 Ok(UnixSocket { io: fd })
123 }
124 }
125
126 /// Bind the socket to the specified address
127 pub fn bind<P: AsRef<Path> + ?Sized>(&self, addr: &P) -> io::Result<()> {
128 unsafe {
129 let (addr, len) = sockaddr_un(addr.as_ref())?;
130 cvt(libc::bind(self.as_raw_fd(),
131 &addr as *const _ as *const _,
132 len))?;
133 Ok(())
134 }
135 }
136
137 pub fn try_clone(&self) -> io::Result<UnixSocket> {
138 Ok(UnixSocket { io: self.io.try_clone()? })
139 }
140
141 pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
142 let how = match how {
143 Shutdown::Read => libc::SHUT_RD,
144 Shutdown::Write => libc::SHUT_WR,
145 Shutdown::Both => libc::SHUT_RDWR,
146 };
147 unsafe {
148 cvt(libc::shutdown(self.as_raw_fd(), how))?;
149 Ok(())
150 }
151 }
152
153 pub fn read_recv_fd(&mut self, buf: &mut [u8]) -> io::Result<(usize, Option<RawFd>)> {
154 unsafe {
155 let mut iov = libc::iovec {
156 iov_base: buf.as_mut_ptr() as *mut _,
157 iov_len: buf.len(),
158 };
159 struct Cmsg {
160 hdr: libc::cmsghdr,
161 data: [libc::c_int; 1],
162 }
163 let mut cmsg: Cmsg = mem::zeroed();
164 let mut msg: libc::msghdr = mem::zeroed();
165 msg.msg_iov = &mut iov;
166 msg.msg_iovlen = 1;
167 msg.msg_control = &mut cmsg as *mut _ as *mut _;
168 msg.msg_controllen = mem::size_of_val(&cmsg).my_into();
169 let bytes = cvt(libc::recvmsg(self.as_raw_fd(), &mut msg, 0))?;
170
171 const SCM_RIGHTS: libc::c_int = 1;
172
173 let fd = if cmsg.hdr.cmsg_level == libc::SOL_SOCKET &&
174 cmsg.hdr.cmsg_type == SCM_RIGHTS {
175 Some(cmsg.data[0])
176 } else {
177 None
178 };
179 Ok((bytes as usize, fd))
180 }
181 }
182
183 pub fn write_send_fd(&mut self, buf: &[u8], fd: RawFd) -> io::Result<usize> {
184 unsafe {
185 let mut iov = libc::iovec {
186 iov_base: buf.as_ptr() as *mut _,
187 iov_len: buf.len(),
188 };
189 struct Cmsg {
190 hdr: libc::cmsghdr,
191 data: [libc::c_int; 1],
192 }
193 let mut cmsg: Cmsg = mem::zeroed();
194 cmsg.hdr.cmsg_len = mem::size_of_val(&cmsg).my_into();
195 cmsg.hdr.cmsg_level = libc::SOL_SOCKET;
196 cmsg.hdr.cmsg_type = 1; // SCM_RIGHTS
197 cmsg.data[0] = fd;
198 let mut msg: libc::msghdr = mem::zeroed();
199 msg.msg_iov = &mut iov;
200 msg.msg_iovlen = 1;
201 msg.msg_control = &mut cmsg as *mut _ as *mut _;
202 msg.msg_controllen = mem::size_of_val(&cmsg).my_into();
203 let bytes = cvt(libc::sendmsg(self.as_raw_fd(), &msg, 0))?;
204 Ok(bytes as usize)
205 }
206 }
207 }
208
209 impl Read for UnixSocket {
210 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
211 self.io.read(buf)
212 }
213 }
214
215 impl Write for UnixSocket {
216 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
217 self.io.write(buf)
218 }
219
220 fn flush(&mut self) -> io::Result<()> {
221 self.io.flush()
222 }
223 }
224
225 impl Evented for UnixSocket {
226 fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
227 self.io.register(poll, token, interest, opts)
228 }
229
230 fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
231 self.io.reregister(poll, token, interest, opts)
232 }
233
234 fn deregister(&self, poll: &Poll) -> io::Result<()> {
235 self.io.deregister(poll)
236 }
237 }
238
239
240 impl From<Io> for UnixSocket {
241 fn from(io: Io) -> UnixSocket {
242 UnixSocket { io }
243 }
244 }
245
246 impl FromRawFd for UnixSocket {
247 unsafe fn from_raw_fd(fd: RawFd) -> UnixSocket {
248 UnixSocket { io: Io::from_raw_fd(fd) }
249 }
250 }
251
252 impl IntoRawFd for UnixSocket {
253 fn into_raw_fd(self) -> RawFd {
254 self.io.into_raw_fd()
255 }
256 }
257
258 impl AsRawFd for UnixSocket {
259 fn as_raw_fd(&self) -> RawFd {
260 self.io.as_raw_fd()
261 }
262 }