| 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 | |