1 | use crate::io::{Interest, PollEvented}; |
2 | use crate::net::unix::{SocketAddr, UnixStream}; |
3 | |
4 | use std::fmt; |
5 | use std::io; |
6 | #[cfg (not(tokio_no_as_fd))] |
7 | use std::os::unix::io::{AsFd, BorrowedFd}; |
8 | use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; |
9 | use std::os::unix::net; |
10 | use std::path::Path; |
11 | use std::task::{Context, Poll}; |
12 | |
13 | cfg_net_unix! { |
14 | /// A Unix socket which can accept connections from other Unix sockets. |
15 | /// |
16 | /// You can accept a new connection by using the [`accept`](`UnixListener::accept`) method. |
17 | /// |
18 | /// A `UnixListener` can be turned into a `Stream` with [`UnixListenerStream`]. |
19 | /// |
20 | /// [`UnixListenerStream`]: https://docs.rs/tokio-stream/0.1/tokio_stream/wrappers/struct.UnixListenerStream.html |
21 | /// |
22 | /// # Errors |
23 | /// |
24 | /// Note that accepting a connection can lead to various errors and not all |
25 | /// of them are necessarily fatal ‒ for example having too many open file |
26 | /// descriptors or the other side closing the connection while it waits in |
27 | /// an accept queue. These would terminate the stream if not handled in any |
28 | /// way. |
29 | /// |
30 | /// # Examples |
31 | /// |
32 | /// ```no_run |
33 | /// use tokio::net::UnixListener; |
34 | /// |
35 | /// #[tokio::main] |
36 | /// async fn main() { |
37 | /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); |
38 | /// loop { |
39 | /// match listener.accept().await { |
40 | /// Ok((stream, _addr)) => { |
41 | /// println!("new client!"); |
42 | /// } |
43 | /// Err(e) => { /* connection failed */ } |
44 | /// } |
45 | /// } |
46 | /// } |
47 | /// ``` |
48 | #[cfg_attr (docsrs, doc(alias = "uds" ))] |
49 | pub struct UnixListener { |
50 | io: PollEvented<mio::net::UnixListener>, |
51 | } |
52 | } |
53 | |
54 | impl UnixListener { |
55 | /// Creates a new `UnixListener` bound to the specified path. |
56 | /// |
57 | /// # Panics |
58 | /// |
59 | /// This function panics if it is not called from within a runtime with |
60 | /// IO enabled. |
61 | /// |
62 | /// The runtime is usually set implicitly when this function is called |
63 | /// from a future driven by a tokio runtime, otherwise runtime can be set |
64 | /// explicitly with [`Runtime::enter`](crate::runtime::Runtime::enter) function. |
65 | #[track_caller ] |
66 | pub fn bind<P>(path: P) -> io::Result<UnixListener> |
67 | where |
68 | P: AsRef<Path>, |
69 | { |
70 | let listener = mio::net::UnixListener::bind(path)?; |
71 | let io = PollEvented::new(listener)?; |
72 | Ok(UnixListener { io }) |
73 | } |
74 | |
75 | /// Creates new `UnixListener` from a `std::os::unix::net::UnixListener `. |
76 | /// |
77 | /// This function is intended to be used to wrap a UnixListener from the |
78 | /// standard library in the Tokio equivalent. |
79 | /// |
80 | /// # Notes |
81 | /// |
82 | /// The caller is responsible for ensuring that the listener is in |
83 | /// non-blocking mode. Otherwise all I/O operations on the listener |
84 | /// will block the thread, which will cause unexpected behavior. |
85 | /// Non-blocking mode can be set using [`set_nonblocking`]. |
86 | /// |
87 | /// [`set_nonblocking`]: std::os::unix::net::UnixListener::set_nonblocking |
88 | /// |
89 | /// # Examples |
90 | /// |
91 | /// ```no_run |
92 | /// use tokio::net::UnixListener; |
93 | /// use std::os::unix::net::UnixListener as StdUnixListener; |
94 | /// # use std::error::Error; |
95 | /// |
96 | /// # async fn dox() -> Result<(), Box<dyn Error>> { |
97 | /// let std_listener = StdUnixListener::bind("/path/to/the/socket" )?; |
98 | /// std_listener.set_nonblocking(true)?; |
99 | /// let listener = UnixListener::from_std(std_listener)?; |
100 | /// # Ok(()) |
101 | /// # } |
102 | /// ``` |
103 | /// |
104 | /// # Panics |
105 | /// |
106 | /// This function panics if it is not called from within a runtime with |
107 | /// IO enabled. |
108 | /// |
109 | /// The runtime is usually set implicitly when this function is called |
110 | /// from a future driven by a tokio runtime, otherwise runtime can be set |
111 | /// explicitly with [`Runtime::enter`](crate::runtime::Runtime::enter) function. |
112 | #[track_caller ] |
113 | pub fn from_std(listener: net::UnixListener) -> io::Result<UnixListener> { |
114 | let listener = mio::net::UnixListener::from_std(listener); |
115 | let io = PollEvented::new(listener)?; |
116 | Ok(UnixListener { io }) |
117 | } |
118 | |
119 | /// Turns a [`tokio::net::UnixListener`] into a [`std::os::unix::net::UnixListener`]. |
120 | /// |
121 | /// The returned [`std::os::unix::net::UnixListener`] will have nonblocking mode |
122 | /// set as `true`. Use [`set_nonblocking`] to change the blocking mode if needed. |
123 | /// |
124 | /// # Examples |
125 | /// |
126 | /// ```rust,no_run |
127 | /// # use std::error::Error; |
128 | /// # async fn dox() -> Result<(), Box<dyn Error>> { |
129 | /// let tokio_listener = tokio::net::UnixListener::bind("/path/to/the/socket" )?; |
130 | /// let std_listener = tokio_listener.into_std()?; |
131 | /// std_listener.set_nonblocking(false)?; |
132 | /// # Ok(()) |
133 | /// # } |
134 | /// ``` |
135 | /// |
136 | /// [`tokio::net::UnixListener`]: UnixListener |
137 | /// [`std::os::unix::net::UnixListener`]: std::os::unix::net::UnixListener |
138 | /// [`set_nonblocking`]: fn@std::os::unix::net::UnixListener::set_nonblocking |
139 | pub fn into_std(self) -> io::Result<std::os::unix::net::UnixListener> { |
140 | self.io |
141 | .into_inner() |
142 | .map(|io| io.into_raw_fd()) |
143 | .map(|raw_fd| unsafe { net::UnixListener::from_raw_fd(raw_fd) }) |
144 | } |
145 | |
146 | /// Returns the local socket address of this listener. |
147 | pub fn local_addr(&self) -> io::Result<SocketAddr> { |
148 | self.io.local_addr().map(SocketAddr) |
149 | } |
150 | |
151 | /// Returns the value of the `SO_ERROR` option. |
152 | pub fn take_error(&self) -> io::Result<Option<io::Error>> { |
153 | self.io.take_error() |
154 | } |
155 | |
156 | /// Accepts a new incoming connection to this listener. |
157 | /// |
158 | /// # Cancel safety |
159 | /// |
160 | /// This method is cancel safe. If the method is used as the event in a |
161 | /// [`tokio::select!`](crate::select) statement and some other branch |
162 | /// completes first, then it is guaranteed that no new connections were |
163 | /// accepted by this method. |
164 | pub async fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { |
165 | let (mio, addr) = self |
166 | .io |
167 | .registration() |
168 | .async_io(Interest::READABLE, || self.io.accept()) |
169 | .await?; |
170 | |
171 | let addr = SocketAddr(addr); |
172 | let stream = UnixStream::new(mio)?; |
173 | Ok((stream, addr)) |
174 | } |
175 | |
176 | /// Polls to accept a new incoming connection to this listener. |
177 | /// |
178 | /// If there is no connection to accept, `Poll::Pending` is returned and the |
179 | /// current task will be notified by a waker. Note that on multiple calls |
180 | /// to `poll_accept`, only the `Waker` from the `Context` passed to the most |
181 | /// recent call is scheduled to receive a wakeup. |
182 | pub fn poll_accept(&self, cx: &mut Context<'_>) -> Poll<io::Result<(UnixStream, SocketAddr)>> { |
183 | let (sock, addr) = ready!(self.io.registration().poll_read_io(cx, || self.io.accept()))?; |
184 | let addr = SocketAddr(addr); |
185 | let sock = UnixStream::new(sock)?; |
186 | Poll::Ready(Ok((sock, addr))) |
187 | } |
188 | } |
189 | |
190 | impl TryFrom<std::os::unix::net::UnixListener> for UnixListener { |
191 | type Error = io::Error; |
192 | |
193 | /// Consumes stream, returning the tokio I/O object. |
194 | /// |
195 | /// This is equivalent to |
196 | /// [`UnixListener::from_std(stream)`](UnixListener::from_std). |
197 | fn try_from(stream: std::os::unix::net::UnixListener) -> io::Result<Self> { |
198 | Self::from_std(listener:stream) |
199 | } |
200 | } |
201 | |
202 | impl fmt::Debug for UnixListener { |
203 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
204 | self.io.fmt(f) |
205 | } |
206 | } |
207 | |
208 | impl AsRawFd for UnixListener { |
209 | fn as_raw_fd(&self) -> RawFd { |
210 | self.io.as_raw_fd() |
211 | } |
212 | } |
213 | |
214 | #[cfg (not(tokio_no_as_fd))] |
215 | impl AsFd for UnixListener { |
216 | fn as_fd(&self) -> BorrowedFd<'_> { |
217 | unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) } |
218 | } |
219 | } |
220 | |