1 use std::io;
2 use std::path::Path;
3 
4 use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
5 
6 use crate::net::{UnixDatagram, UnixListener, UnixStream};
7 
8 cfg_net_unix! {
9     /// A Unix socket that has not yet been converted to a [`UnixStream`], [`UnixDatagram`], or
10     /// [`UnixListener`].
11     ///
12     /// `UnixSocket` wraps an operating system socket and enables the caller to
13     /// configure the socket before establishing a connection or accepting
14     /// inbound connections. The caller is able to set socket option and explicitly
15     /// bind the socket with a socket address.
16     ///
17     /// The underlying socket is closed when the `UnixSocket` value is dropped.
18     ///
19     /// `UnixSocket` should only be used directly if the default configuration used
20     /// by [`UnixStream::connect`], [`UnixDatagram::bind`], and [`UnixListener::bind`]
21     /// does not meet the required use case.
22     ///
23     /// Calling `UnixStream::connect(path)` effectively performs the same function as:
24     ///
25     /// ```no_run
26     /// use tokio::net::UnixSocket;
27     /// use std::error::Error;
28     ///
29     /// #[tokio::main]
30     /// async fn main() -> Result<(), Box<dyn Error>> {
31     ///     let dir = tempfile::tempdir().unwrap();
32     ///     let path = dir.path().join("bind_path");
33     ///     let socket = UnixSocket::new_stream()?;
34     ///
35     ///     let stream = socket.connect(path).await?;
36     ///
37     ///     Ok(())
38     /// }
39     /// ```
40     ///
41     /// Calling `UnixDatagram::bind(path)` effectively performs the same function as:
42     ///
43     /// ```no_run
44     /// use tokio::net::UnixSocket;
45     /// use std::error::Error;
46     ///
47     /// #[tokio::main]
48     /// async fn main() -> Result<(), Box<dyn Error>> {
49     ///     let dir = tempfile::tempdir().unwrap();
50     ///     let path = dir.path().join("bind_path");
51     ///     let socket = UnixSocket::new_datagram()?;
52     ///     socket.bind(path)?;
53     ///
54     ///     let datagram = socket.datagram()?;
55     ///
56     ///     Ok(())
57     /// }
58     /// ```
59     ///
60     /// Calling `UnixListener::bind(path)` effectively performs the same function as:
61     ///
62     /// ```no_run
63     /// use tokio::net::UnixSocket;
64     /// use std::error::Error;
65     ///
66     /// #[tokio::main]
67     /// async fn main() -> Result<(), Box<dyn Error>> {
68     ///     let dir = tempfile::tempdir().unwrap();
69     ///     let path = dir.path().join("bind_path");
70     ///     let socket = UnixSocket::new_stream()?;
71     ///     socket.bind(path)?;
72     ///
73     ///     let listener = socket.listen(1024)?;
74     ///
75     ///     Ok(())
76     /// }
77     /// ```
78     ///
79     /// Setting socket options not explicitly provided by `UnixSocket` may be done by
80     /// accessing the [`RawFd`]/[`RawSocket`] using [`AsRawFd`]/[`AsRawSocket`] and
81     /// setting the option with a crate like [`socket2`].
82     ///
83     /// [`RawFd`]: std::os::fd::RawFd
84     /// [`RawSocket`]: https://doc.rust-lang.org/std/os/windows/io/type.RawSocket.html
85     /// [`AsRawFd`]: std::os::fd::AsRawFd
86     /// [`AsRawSocket`]: https://doc.rust-lang.org/std/os/windows/io/trait.AsRawSocket.html
87     /// [`socket2`]: https://docs.rs/socket2/
88     #[derive(Debug)]
89     pub struct UnixSocket {
90         inner: socket2::Socket,
91     }
92 }
93 
94 impl UnixSocket {
ty(&self) -> socket2::Type95     fn ty(&self) -> socket2::Type {
96         self.inner.r#type().unwrap()
97     }
98 
99     /// Creates a new Unix datagram socket.
100     ///
101     /// Calls `socket(2)` with `AF_UNIX` and `SOCK_DGRAM`.
102     ///
103     /// # Returns
104     ///
105     /// On success, the newly created [`UnixSocket`] is returned. If an error is
106     /// encountered, it is returned instead.
new_datagram() -> io::Result<UnixSocket>107     pub fn new_datagram() -> io::Result<UnixSocket> {
108         UnixSocket::new(socket2::Type::DGRAM)
109     }
110 
111     /// Creates a new Unix stream socket.
112     ///
113     /// Calls `socket(2)` with `AF_UNIX` and `SOCK_STREAM`.
114     ///
115     /// # Returns
116     ///
117     /// On success, the newly created [`UnixSocket`] is returned. If an error is
118     /// encountered, it is returned instead.
new_stream() -> io::Result<UnixSocket>119     pub fn new_stream() -> io::Result<UnixSocket> {
120         UnixSocket::new(socket2::Type::STREAM)
121     }
122 
new(ty: socket2::Type) -> io::Result<UnixSocket>123     fn new(ty: socket2::Type) -> io::Result<UnixSocket> {
124         #[cfg(any(
125             target_os = "android",
126             target_os = "dragonfly",
127             target_os = "freebsd",
128             target_os = "fuchsia",
129             target_os = "illumos",
130             target_os = "linux",
131             target_os = "netbsd",
132             target_os = "openbsd"
133         ))]
134         let ty = ty.nonblocking();
135         let inner = socket2::Socket::new(socket2::Domain::UNIX, ty, None)?;
136         #[cfg(not(any(
137             target_os = "android",
138             target_os = "dragonfly",
139             target_os = "freebsd",
140             target_os = "fuchsia",
141             target_os = "illumos",
142             target_os = "linux",
143             target_os = "netbsd",
144             target_os = "openbsd"
145         )))]
146         inner.set_nonblocking(true)?;
147         Ok(UnixSocket { inner })
148     }
149 
150     /// Binds the socket to the given address.
151     ///
152     /// This calls the `bind(2)` operating-system function.
bind(&self, path: impl AsRef<Path>) -> io::Result<()>153     pub fn bind(&self, path: impl AsRef<Path>) -> io::Result<()> {
154         let addr = socket2::SockAddr::unix(path)?;
155         self.inner.bind(&addr)
156     }
157 
158     /// Converts the socket into a `UnixListener`.
159     ///
160     /// `backlog` defines the maximum number of pending connections are queued
161     /// by the operating system at any given time. Connection are removed from
162     /// the queue with [`UnixListener::accept`]. When the queue is full, the
163     /// operating-system will start rejecting connections.
164     ///
165     /// Calling this function on a socket created by [`new_datagram`] will return an error.
166     ///
167     /// This calls the `listen(2)` operating-system function, marking the socket
168     /// as a passive socket.
169     ///
170     /// [`new_datagram`]: `UnixSocket::new_datagram`
listen(self, backlog: u32) -> io::Result<UnixListener>171     pub fn listen(self, backlog: u32) -> io::Result<UnixListener> {
172         if self.ty() == socket2::Type::DGRAM {
173             return Err(io::Error::new(
174                 io::ErrorKind::Other,
175                 "listen cannot be called on a datagram socket",
176             ));
177         }
178 
179         self.inner.listen(backlog as i32)?;
180         let mio = {
181             use std::os::unix::io::{FromRawFd, IntoRawFd};
182 
183             let raw_fd = self.inner.into_raw_fd();
184             unsafe { mio::net::UnixListener::from_raw_fd(raw_fd) }
185         };
186 
187         UnixListener::new(mio)
188     }
189 
190     /// Establishes a Unix connection with a peer at the specified socket address.
191     ///
192     /// The `UnixSocket` is consumed. Once the connection is established, a
193     /// connected [`UnixStream`] is returned. If the connection fails, the
194     /// encountered error is returned.
195     ///
196     /// Calling this function on a socket created by [`new_datagram`] will return an error.
197     ///
198     /// This calls the `connect(2)` operating-system function.
199     ///
200     /// [`new_datagram`]: `UnixSocket::new_datagram`
connect(self, path: impl AsRef<Path>) -> io::Result<UnixStream>201     pub async fn connect(self, path: impl AsRef<Path>) -> io::Result<UnixStream> {
202         if self.ty() == socket2::Type::DGRAM {
203             return Err(io::Error::new(
204                 io::ErrorKind::Other,
205                 "connect cannot be called on a datagram socket",
206             ));
207         }
208 
209         let addr = socket2::SockAddr::unix(path)?;
210         if let Err(err) = self.inner.connect(&addr) {
211             if err.raw_os_error() != Some(libc::EINPROGRESS) {
212                 return Err(err);
213             }
214         }
215         let mio = {
216             use std::os::unix::io::{FromRawFd, IntoRawFd};
217 
218             let raw_fd = self.inner.into_raw_fd();
219             unsafe { mio::net::UnixStream::from_raw_fd(raw_fd) }
220         };
221 
222         UnixStream::connect_mio(mio).await
223     }
224 
225     /// Converts the socket into a [`UnixDatagram`].
226     ///
227     /// Calling this function on a socket created by [`new_stream`] will return an error.
228     ///
229     /// [`new_stream`]: `UnixSocket::new_stream`
datagram(self) -> io::Result<UnixDatagram>230     pub fn datagram(self) -> io::Result<UnixDatagram> {
231         if self.ty() == socket2::Type::STREAM {
232             return Err(io::Error::new(
233                 io::ErrorKind::Other,
234                 "datagram cannot be called on a stream socket",
235             ));
236         }
237         let mio = {
238             use std::os::unix::io::{FromRawFd, IntoRawFd};
239 
240             let raw_fd = self.inner.into_raw_fd();
241             unsafe { mio::net::UnixDatagram::from_raw_fd(raw_fd) }
242         };
243 
244         UnixDatagram::from_mio(mio)
245     }
246 }
247 
248 impl AsRawFd for UnixSocket {
as_raw_fd(&self) -> RawFd249     fn as_raw_fd(&self) -> RawFd {
250         self.inner.as_raw_fd()
251     }
252 }
253 
254 impl AsFd for UnixSocket {
as_fd(&self) -> BorrowedFd<'_>255     fn as_fd(&self) -> BorrowedFd<'_> {
256         unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
257     }
258 }
259 
260 impl FromRawFd for UnixSocket {
from_raw_fd(fd: RawFd) -> UnixSocket261     unsafe fn from_raw_fd(fd: RawFd) -> UnixSocket {
262         let inner = socket2::Socket::from_raw_fd(fd);
263         UnixSocket { inner }
264     }
265 }
266 
267 impl IntoRawFd for UnixSocket {
into_raw_fd(self) -> RawFd268     fn into_raw_fd(self) -> RawFd {
269         self.inner.into_raw_fd()
270     }
271 }
272