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}