Skip to main content

interprocess/local_socket/listener/
enum.rs

1#[cfg(unix)]
2use crate::os::unix::uds_local_socket as uds_impl;
3#[cfg(windows)]
4use crate::os::windows::named_pipe::local_socket as np_impl;
5use {
6    super::{options::ListenerOptions, r#trait},
7    crate::local_socket::{ListenerNonblockingMode, Stream},
8    std::{io, iter::FusedIterator},
9};
10
11impmod! {local_socket::dispatch_sync as dispatch}
12
13mkenum!(
14/// Local socket server, listening for connections.
15///
16/// This struct is created by [`ListenerOptions`](super::options::ListenerOptions).
17///
18/// See the [module-level documentation](crate::local_socket) for more details.
19///
20/// # Name reclamation
21/// *This section only applies to Unix domain sockets.*
22///
23/// When a Unix domain socket listener is closed, its associated socket file is not automatically
24/// deleted. Instead, it remains on the filesystem in a zombie state, neither accepting connections
25/// nor allowing a new listener to reuse it – [`create_sync()`] will return
26/// [`AddrInUse`](io::ErrorKind::AddrInUse) on some platforms unless the detached socket file is
27/// deleted manually.
28///
29/// Interprocess implements *automatic name reclamation*: when the local socket listener is
30/// dropped, it performs [`std::fs::remove_file()`] (i.e. `unlink()`) with the path that was
31/// originally passed to [`create_sync()`], allowing for subsequent reuse of the local socket name.
32///
33/// If the program crashes in a way that doesn't unwind the stack, the deletion will not occur and
34/// the socket file will linger on the filesystem, in which case manual deletion will be necessary.
35/// Identially, the automatic name reclamation mechanism can be opted out of via
36/// [`.do_not_reclaim_name_on_drop()`](trait::Listener::do_not_reclaim_name_on_drop) on the listener
37/// or [`.reclaim_name(false)`](super::options::ListenerOptions::reclaim_name) on the builder.
38///
39/// Note that the socket file can be unlinked by other programs at any time, retaining the inode the
40/// listener is bound to but making it inaccessible to peers if it was at its last hardlink. If that
41/// happens and another listener takes the same path before the first one performs name reclamation,
42/// the socket file deletion wouldn't correspond to the listener being closed, instead deleting the
43/// socket file of the second listener. If the second listener also performs name reclamation, the
44/// ensuing deletion will silently fail. Due to the awful design of Unix, this issue cannot be
45/// mitigated.
46///
47/// [`create_sync()`]: super::options::ListenerOptions::create_sync
48///
49/// # Examples
50///
51/// ## Basic server
52/// ```no_run
53#[cfg_attr(doc, doc = doctest_file::include_doctest!("examples/local_socket/sync/listener.rs"))]
54/// ```
55Listener);
56
57impl r#trait::Listener for Listener {
58    type Stream = Stream;
59
60    #[inline]
61    fn from_options(options: ListenerOptions<'_>) -> io::Result<Self> {
62        dispatch::listen(options)
63    }
64    #[inline]
65    fn accept(&self) -> io::Result<Stream> {
66        dispatch!(Self: x in self => x.accept()).map(Stream::from)
67    }
68    #[inline]
69    fn set_nonblocking(&self, nonblocking: ListenerNonblockingMode) -> io::Result<()> {
70        dispatch!(Self: x in self => x.set_nonblocking(nonblocking))
71    }
72    #[inline]
73    fn do_not_reclaim_name_on_drop(&mut self) {
74        dispatch!(Self: x in self => x.do_not_reclaim_name_on_drop())
75    }
76}
77impl Iterator for Listener {
78    type Item = io::Result<Stream>;
79    #[inline(always)]
80    fn next(&mut self) -> Option<Self::Item> { Some(r#trait::Listener::accept(self)) }
81}
82impl FusedIterator for Listener {}