Skip to main content

std/os/unix/net/
listener.rs

1use super::{SocketAddr, UnixStream, sockaddr_un};
2use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
3use crate::path::Path;
4use crate::sys::net::Socket;
5use crate::sys::{AsInner, FromInner, IntoInner, cvt};
6use crate::{fmt, io, mem};
7
8/// A structure representing a Unix domain socket server.
9///
10/// # Examples
11///
12#[cfg_attr(target_family = "unix", doc = "```no_run")]
13#[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
14/// use std::thread;
15/// use std::os::unix::net::{UnixStream, UnixListener};
16///
17/// fn handle_client(stream: UnixStream) {
18///     // ...
19/// }
20///
21/// fn main() -> std::io::Result<()> {
22///     let listener = UnixListener::bind("/path/to/the/socket")?;
23///
24///     // accept connections and process them, spawning a new thread for each one
25///     for stream in listener.incoming() {
26///         match stream {
27///             Ok(stream) => {
28///                 /* connection succeeded */
29///                 thread::spawn(|| handle_client(stream));
30///             }
31///             Err(err) => {
32///                 /* connection failed */
33///                 break;
34///             }
35///         }
36///     }
37///     Ok(())
38/// }
39/// ```
40#[stable(feature = "unix_socket", since = "1.10.0")]
41pub struct UnixListener(Socket);
42
43#[stable(feature = "unix_socket", since = "1.10.0")]
44impl fmt::Debug for UnixListener {
45    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
46        let mut builder = fmt.debug_struct("UnixListener");
47        builder.field("fd", self.0.as_inner());
48        if let Ok(addr) = self.local_addr() {
49            builder.field("local", &addr);
50        }
51        builder.finish()
52    }
53}
54
55impl UnixListener {
56    /// Creates a new `UnixListener` bound to the specified socket.
57    ///
58    /// # Examples
59    ///
60    #[cfg_attr(target_family = "unix", doc = "```no_run")]
61    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
62    /// use std::os::unix::net::UnixListener;
63    ///
64    /// let listener = match UnixListener::bind("/path/to/the/socket") {
65    ///     Ok(sock) => sock,
66    ///     Err(e) => {
67    ///         println!("Couldn't connect: {e:?}");
68    ///         return
69    ///     }
70    /// };
71    /// ```
72    #[stable(feature = "unix_socket", since = "1.10.0")]
73    pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> {
74        unsafe {
75            let inner = Socket::new(libc::AF_UNIX, libc::SOCK_STREAM)?;
76            let (addr, len) = sockaddr_un(path.as_ref())?;
77            #[cfg(any(
78                target_os = "windows",
79                target_os = "redox",
80                target_os = "espidf",
81                target_os = "horizon"
82            ))]
83            const backlog: core::ffi::c_int = 128;
84            #[cfg(any(
85                // Silently capped to `/proc/sys/net/core/somaxconn`.
86                target_os = "linux",
87                // Silently capped to `kern.ipc.soacceptqueue`.
88                target_os = "freebsd",
89                // Silently capped to `kern.somaxconn sysctl`.
90                target_os = "openbsd",
91                // Silently capped to the default 128.
92                target_vendor = "apple",
93            ))]
94            const backlog: core::ffi::c_int = -1;
95            #[cfg(not(any(
96                target_os = "windows",
97                target_os = "redox",
98                target_os = "espidf",
99                target_os = "horizon",
100                target_os = "linux",
101                target_os = "freebsd",
102                target_os = "openbsd",
103                target_vendor = "apple",
104            )))]
105            const backlog: libc::c_int = libc::SOMAXCONN;
106
107            cvt(libc::bind(inner.as_inner().as_raw_fd(), (&raw const addr) as *const _, len as _))?;
108            cvt(libc::listen(inner.as_inner().as_raw_fd(), backlog))?;
109
110            Ok(UnixListener(inner))
111        }
112    }
113
114    /// Creates a new `UnixListener` bound to the specified [`socket address`].
115    ///
116    /// [`socket address`]: crate::os::unix::net::SocketAddr
117    ///
118    /// # Examples
119    ///
120    #[cfg_attr(target_family = "unix", doc = "```no_run")]
121    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
122    /// use std::os::unix::net::{UnixListener};
123    ///
124    /// fn main() -> std::io::Result<()> {
125    ///     let listener1 = UnixListener::bind("path/to/socket")?;
126    ///     let addr = listener1.local_addr()?;
127    ///
128    ///     let listener2 = match UnixListener::bind_addr(&addr) {
129    ///         Ok(sock) => sock,
130    ///         Err(err) => {
131    ///             println!("Couldn't bind: {err:?}");
132    ///             return Err(err);
133    ///         }
134    ///     };
135    ///     Ok(())
136    /// }
137    /// ```
138    #[stable(feature = "unix_socket_abstract", since = "1.70.0")]
139    pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result<UnixListener> {
140        unsafe {
141            let inner = Socket::new(libc::AF_UNIX, libc::SOCK_STREAM)?;
142            #[cfg(target_os = "linux")]
143            const backlog: core::ffi::c_int = -1;
144            #[cfg(not(target_os = "linux"))]
145            const backlog: core::ffi::c_int = 128;
146            cvt(libc::bind(
147                inner.as_raw_fd(),
148                (&raw const socket_addr.addr) as *const _,
149                socket_addr.len as _,
150            ))?;
151            cvt(libc::listen(inner.as_raw_fd(), backlog))?;
152            Ok(UnixListener(inner))
153        }
154    }
155
156    /// Accepts a new incoming connection to this listener.
157    ///
158    /// This function will block the calling thread until a new Unix connection
159    /// is established. When established, the corresponding [`UnixStream`] and
160    /// the remote peer's address will be returned.
161    ///
162    /// [`UnixStream`]: crate::os::unix::net::UnixStream
163    ///
164    /// # Examples
165    ///
166    #[cfg_attr(target_family = "unix", doc = "```no_run")]
167    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
168    /// use std::os::unix::net::UnixListener;
169    ///
170    /// fn main() -> std::io::Result<()> {
171    ///     let listener = UnixListener::bind("/path/to/the/socket")?;
172    ///
173    ///     match listener.accept() {
174    ///         Ok((socket, addr)) => println!("Got a client: {addr:?}"),
175    ///         Err(e) => println!("accept function failed: {e:?}"),
176    ///     }
177    ///     Ok(())
178    /// }
179    /// ```
180    #[stable(feature = "unix_socket", since = "1.10.0")]
181    pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> {
182        let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() };
183        let mut len = size_of_val(&storage) as libc::socklen_t;
184        let sock = self.0.accept((&raw mut storage) as *mut _, &mut len)?;
185        let addr = SocketAddr::from_parts(storage, len)?;
186        Ok((UnixStream(sock), addr))
187    }
188
189    /// Creates a new independently owned handle to the underlying socket.
190    ///
191    /// The returned `UnixListener` is a reference to the same socket that this
192    /// object references. Both handles can be used to accept incoming
193    /// connections and options set on one listener will affect the other.
194    ///
195    /// # Examples
196    ///
197    #[cfg_attr(target_family = "unix", doc = "```no_run")]
198    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
199    /// use std::os::unix::net::UnixListener;
200    ///
201    /// fn main() -> std::io::Result<()> {
202    ///     let listener = UnixListener::bind("/path/to/the/socket")?;
203    ///     let listener_copy = listener.try_clone().expect("try_clone failed");
204    ///     Ok(())
205    /// }
206    /// ```
207    #[stable(feature = "unix_socket", since = "1.10.0")]
208    pub fn try_clone(&self) -> io::Result<UnixListener> {
209        self.0.duplicate().map(UnixListener)
210    }
211
212    /// Returns the local socket address of this listener.
213    ///
214    /// # Examples
215    ///
216    #[cfg_attr(target_family = "unix", doc = "```no_run")]
217    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
218    /// use std::os::unix::net::UnixListener;
219    ///
220    /// fn main() -> std::io::Result<()> {
221    ///     let listener = UnixListener::bind("/path/to/the/socket")?;
222    ///     let addr = listener.local_addr().expect("Couldn't get local address");
223    ///     Ok(())
224    /// }
225    /// ```
226    #[stable(feature = "unix_socket", since = "1.10.0")]
227    pub fn local_addr(&self) -> io::Result<SocketAddr> {
228        SocketAddr::new(|addr, len| unsafe { libc::getsockname(self.as_raw_fd(), addr, len) })
229    }
230
231    /// Moves the socket into or out of nonblocking mode.
232    ///
233    /// This will result in the `accept` operation becoming nonblocking,
234    /// i.e., immediately returning from their calls. If the IO operation is
235    /// successful, `Ok` is returned and no further action is required. If the
236    /// IO operation could not be completed and needs to be retried, an error
237    /// with kind [`io::ErrorKind::WouldBlock`] is returned.
238    ///
239    /// # Examples
240    ///
241    #[cfg_attr(target_family = "unix", doc = "```no_run")]
242    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
243    /// use std::os::unix::net::UnixListener;
244    ///
245    /// fn main() -> std::io::Result<()> {
246    ///     let listener = UnixListener::bind("/path/to/the/socket")?;
247    ///     listener.set_nonblocking(true).expect("Couldn't set non blocking");
248    ///     Ok(())
249    /// }
250    /// ```
251    #[stable(feature = "unix_socket", since = "1.10.0")]
252    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
253        self.0.set_nonblocking(nonblocking)
254    }
255
256    /// Returns the value of the `SO_ERROR` option.
257    ///
258    /// # Examples
259    ///
260    #[cfg_attr(target_family = "unix", doc = "```no_run")]
261    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
262    /// use std::os::unix::net::UnixListener;
263    ///
264    /// fn main() -> std::io::Result<()> {
265    ///     let listener = UnixListener::bind("/tmp/sock")?;
266    ///
267    ///     if let Ok(Some(err)) = listener.take_error() {
268    ///         println!("Got error: {err:?}");
269    ///     }
270    ///     Ok(())
271    /// }
272    /// ```
273    ///
274    /// # Platform specific
275    /// On Redox this always returns `None`.
276    #[stable(feature = "unix_socket", since = "1.10.0")]
277    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
278        self.0.take_error()
279    }
280
281    /// Returns an iterator over incoming connections.
282    ///
283    /// The iterator will never return [`None`] and will also not yield the
284    /// peer's [`SocketAddr`] structure.
285    ///
286    /// # Examples
287    ///
288    #[cfg_attr(target_family = "unix", doc = "```no_run")]
289    #[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
290    /// use std::thread;
291    /// use std::os::unix::net::{UnixStream, UnixListener};
292    ///
293    /// fn handle_client(stream: UnixStream) {
294    ///     // ...
295    /// }
296    ///
297    /// fn main() -> std::io::Result<()> {
298    ///     let listener = UnixListener::bind("/path/to/the/socket")?;
299    ///
300    ///     for stream in listener.incoming() {
301    ///         match stream {
302    ///             Ok(stream) => {
303    ///                 thread::spawn(|| handle_client(stream));
304    ///             }
305    ///             Err(err) => {
306    ///                 break;
307    ///             }
308    ///         }
309    ///     }
310    ///     Ok(())
311    /// }
312    /// ```
313    #[stable(feature = "unix_socket", since = "1.10.0")]
314    pub fn incoming(&self) -> Incoming<'_> {
315        Incoming { listener: self }
316    }
317}
318
319#[stable(feature = "unix_socket", since = "1.10.0")]
320impl AsRawFd for UnixListener {
321    #[inline]
322    fn as_raw_fd(&self) -> RawFd {
323        self.0.as_inner().as_raw_fd()
324    }
325}
326
327#[stable(feature = "unix_socket", since = "1.10.0")]
328impl FromRawFd for UnixListener {
329    #[inline]
330    unsafe fn from_raw_fd(fd: RawFd) -> UnixListener {
331        UnixListener(Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd))))
332    }
333}
334
335#[stable(feature = "unix_socket", since = "1.10.0")]
336impl IntoRawFd for UnixListener {
337    #[inline]
338    fn into_raw_fd(self) -> RawFd {
339        self.0.into_inner().into_inner().into_raw_fd()
340    }
341}
342
343#[stable(feature = "io_safety", since = "1.63.0")]
344impl AsFd for UnixListener {
345    #[inline]
346    fn as_fd(&self) -> BorrowedFd<'_> {
347        self.0.as_inner().as_fd()
348    }
349}
350
351#[stable(feature = "io_safety", since = "1.63.0")]
352impl From<OwnedFd> for UnixListener {
353    #[inline]
354    fn from(fd: OwnedFd) -> UnixListener {
355        UnixListener(Socket::from_inner(FromInner::from_inner(fd)))
356    }
357}
358
359#[stable(feature = "io_safety", since = "1.63.0")]
360impl From<UnixListener> for OwnedFd {
361    /// Takes ownership of a [`UnixListener`]'s socket file descriptor.
362    #[inline]
363    fn from(listener: UnixListener) -> OwnedFd {
364        listener.0.into_inner().into_inner()
365    }
366}
367
368#[stable(feature = "unix_socket", since = "1.10.0")]
369impl<'a> IntoIterator for &'a UnixListener {
370    type Item = io::Result<UnixStream>;
371    type IntoIter = Incoming<'a>;
372
373    fn into_iter(self) -> Incoming<'a> {
374        self.incoming()
375    }
376}
377
378/// An iterator over incoming connections to a [`UnixListener`].
379///
380/// It will never return [`None`].
381///
382/// # Examples
383///
384#[cfg_attr(target_family = "unix", doc = "```no_run")]
385#[cfg_attr(not(target_family = "unix"), doc = "```ignore (needs unix)")]
386/// use std::thread;
387/// use std::os::unix::net::{UnixStream, UnixListener};
388///
389/// fn handle_client(stream: UnixStream) {
390///     // ...
391/// }
392///
393/// fn main() -> std::io::Result<()> {
394///     let listener = UnixListener::bind("/path/to/the/socket")?;
395///
396///     for stream in listener.incoming() {
397///         match stream {
398///             Ok(stream) => {
399///                 thread::spawn(|| handle_client(stream));
400///             }
401///             Err(err) => {
402///                 break;
403///             }
404///         }
405///     }
406///     Ok(())
407/// }
408/// ```
409#[derive(Debug)]
410#[must_use = "iterators are lazy and do nothing unless consumed"]
411#[stable(feature = "unix_socket", since = "1.10.0")]
412pub struct Incoming<'a> {
413    listener: &'a UnixListener,
414}
415
416#[stable(feature = "unix_socket", since = "1.10.0")]
417impl<'a> Iterator for Incoming<'a> {
418    type Item = io::Result<UnixStream>;
419
420    fn next(&mut self) -> Option<io::Result<UnixStream>> {
421        Some(self.listener.accept().map(|s| s.0))
422    }
423
424    fn size_hint(&self) -> (usize, Option<usize>) {
425        (usize::MAX, None)
426    }
427}