1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 use std::io;
15 use std::os::fd::{AsRawFd, FromRawFd};
16 use std::os::unix::net;
17 use std::path::Path;
18 
19 use libc::AF_UNIX;
20 
21 use super::socket_addr::socket_addr_trans_un;
22 #[cfg(target_os = "macos")]
23 use crate::sys::socket::set_non_block;
24 use crate::sys::socket::socket_new;
25 
bind(path: &Path) -> io::Result<net::UnixListener>26 pub(crate) fn bind(path: &Path) -> io::Result<net::UnixListener> {
27     let (socket_addr, addr_length) = socket_addr_trans_un(path)?;
28     let socket_addr = (&socket_addr as *const libc::sockaddr_un).cast::<libc::sockaddr>();
29 
30     let socket = socket_new(AF_UNIX, libc::SOCK_STREAM)?;
31     let net = unsafe { net::UnixListener::from_raw_fd(socket) };
32 
33     syscall!(bind(socket, socket_addr, addr_length))?;
34     // set backlog
35     syscall!(listen(socket, 1024))?;
36 
37     Ok(net)
38 }
39 
connect(path: &Path) -> io::Result<net::UnixStream>40 pub(crate) fn connect(path: &Path) -> io::Result<net::UnixStream> {
41     let (sockaddr, addr_length) = socket_addr_trans_un(path)?;
42     let sockaddr = (&sockaddr as *const libc::sockaddr_un).cast::<libc::sockaddr>();
43 
44     let socket = socket_new(AF_UNIX, libc::SOCK_STREAM)?;
45     let net = unsafe { net::UnixStream::from_raw_fd(socket) };
46     match syscall!(connect(socket, sockaddr, addr_length)) {
47         Err(err) if err.raw_os_error() != Some(libc::EINPROGRESS) => Err(err),
48         _ => Ok(net),
49     }
50 }
51 
unbound() -> io::Result<net::UnixDatagram>52 pub(crate) fn unbound() -> io::Result<net::UnixDatagram> {
53     let socket = socket_new(AF_UNIX, libc::SOCK_DGRAM)?;
54     let net = unsafe { net::UnixDatagram::from_raw_fd(socket) };
55     Ok(net)
56 }
57 
data_gram_bind(path: &Path) -> io::Result<net::UnixDatagram>58 pub(crate) fn data_gram_bind(path: &Path) -> io::Result<net::UnixDatagram> {
59     let (socket_addr, addr_length) = socket_addr_trans_un(path)?;
60     let socket_addr = (&socket_addr as *const libc::sockaddr_un).cast::<libc::sockaddr>();
61 
62     let socket = unbound()?;
63     match syscall!(bind(socket.as_raw_fd(), socket_addr, addr_length)) {
64         Err(err) => Err(err),
65         Ok(_) => Ok(socket),
66     }
67 }
68 
stream_pair() -> io::Result<(net::UnixStream, net::UnixStream)>69 pub(crate) fn stream_pair() -> io::Result<(net::UnixStream, net::UnixStream)> {
70     pair(libc::SOCK_STREAM)
71 }
72 
datagram_pair() -> io::Result<(net::UnixDatagram, net::UnixDatagram)>73 pub(crate) fn datagram_pair() -> io::Result<(net::UnixDatagram, net::UnixDatagram)> {
74     pair(libc::SOCK_DGRAM)
75 }
76 
pair<T: FromRawFd>(socket_type: libc::c_int) -> io::Result<(T, T)>77 fn pair<T: FromRawFd>(socket_type: libc::c_int) -> io::Result<(T, T)> {
78     #[cfg(target_os = "linux")]
79     let socket_type = socket_type | libc::SOCK_NONBLOCK | libc::SOCK_CLOEXEC;
80 
81     // uninitialized fd
82     let mut fds = [-1; 2];
83     syscall!(socketpair(AF_UNIX, socket_type, 0, fds.as_mut_ptr()))?;
84 
85     #[cfg(target_os = "macos")]
86     {
87         set_non_block(fds[0])?;
88         set_non_block(fds[1])?;
89     }
90 
91     Ok(unsafe { (T::from_raw_fd(fds[0]), T::from_raw_fd(fds[1])) })
92 }
93