tokio_uring/net/unix/
listener.rs

1use super::UnixStream;
2use crate::io::Socket;
3use std::{io, path::Path};
4
5/// A Unix socket server, listening for connections.
6///
7/// You can accept a new connection by using the [`accept`](`UnixListener::accept`)
8/// method.
9///
10/// # Examples
11///
12/// ```
13/// use tokio_uring::net::UnixListener;
14/// use tokio_uring::net::UnixStream;
15///
16/// let sock_file = "/tmp/tokio-uring-unix-test.sock";
17/// let listener = UnixListener::bind(&sock_file).unwrap();
18///
19/// tokio_uring::start(async move {
20///     let (tx_ch, rx_ch) = tokio::sync::oneshot::channel();
21///
22///     tokio_uring::spawn(async move {
23///         let rx = listener.accept().await.unwrap();
24///         if let Err(_) = tx_ch.send(rx) {
25///             panic!("The receiver dropped");
26///         }
27///     });
28///     tokio::task::yield_now().await; // Ensure the listener.accept().await has been kicked off.
29///
30///     let tx = UnixStream::connect(&sock_file).await.unwrap();
31///     let rx = rx_ch.await.expect("The spawned task expected to send a UnixStream");
32///
33///     tx.write(b"test" as &'static [u8]).submit().await.0.unwrap();
34///
35///     let (_, buf) = rx.read(vec![0; 4]).await;
36///
37///     assert_eq!(buf, b"test");
38/// });
39///
40/// std::fs::remove_file(&sock_file).unwrap();
41/// ```
42pub struct UnixListener {
43    inner: Socket,
44}
45
46impl UnixListener {
47    /// Creates a new UnixListener, which will be bound to the specified file path.
48    /// The file path cannnot yet exist, and will be cleaned up upon dropping `UnixListener`
49    pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> {
50        let socket = Socket::bind_unix(path, libc::SOCK_STREAM)?;
51        socket.listen(1024)?;
52        Ok(UnixListener { inner: socket })
53    }
54
55    /// Returns the local address that this listener is bound to.
56    ///
57    /// # Examples
58    ///
59    /// ```
60    /// use tokio_uring::net::UnixListener;
61    /// use std::path::Path;
62    ///
63    /// let sock_file = "/tmp/tokio-uring-unix-test.sock";
64    /// let listener = UnixListener::bind(&sock_file).unwrap();
65    ///
66    /// let addr = listener.local_addr().expect("Couldn't get local address");
67    /// assert_eq!(addr.as_pathname(), Some(Path::new(sock_file)));
68    ///
69    /// std::fs::remove_file(&sock_file).unwrap();
70    /// ```
71    pub fn local_addr(&self) -> io::Result<std::os::unix::net::SocketAddr> {
72        use std::os::unix::io::{AsRawFd, FromRawFd};
73
74        let fd = self.inner.as_raw_fd();
75        // SAFETY: Our fd is the handle the kernel has given us for a UnixListener.
76        // Create a std::net::UnixListener long enough to call its local_addr method
77        // and then forget it so the socket is not closed here.
78        let l = unsafe { std::os::unix::net::UnixListener::from_raw_fd(fd) };
79        let local_addr = l.local_addr();
80        std::mem::forget(l);
81        local_addr
82    }
83
84    /// Accepts a new incoming connection from this listener.
85    ///
86    /// This function will yield once a new Unix domain socket connection
87    /// is established. When established, the corresponding [`UnixStream`] and
88    /// will be returned.
89    ///
90    /// [`UnixStream`]: struct@crate::net::UnixStream
91    pub async fn accept(&self) -> io::Result<UnixStream> {
92        let (socket, _) = self.inner.accept().await?;
93        let stream = UnixStream { inner: socket };
94        Ok(stream)
95    }
96}