tokio_seqpacket/
listener.rs

1use filedesc::FileDesc;
2use std::os::raw::c_int;
3use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, IntoRawFd, OwnedFd};
4use std::path::{Path, PathBuf};
5use std::task::{Context, Poll};
6use tokio::io::unix::AsyncFd;
7
8use crate::{sys, UnixSeqpacket};
9
10/// Listener for Unix seqpacket sockets.
11pub struct UnixSeqpacketListener {
12	io: AsyncFd<FileDesc>,
13}
14
15impl std::fmt::Debug for UnixSeqpacketListener {
16	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
17		f.debug_struct("UnixSeqpacketListener")
18			.field("fd", &self.io.get_ref().as_raw_fd())
19			.finish()
20	}
21}
22
23impl AsFd for UnixSeqpacketListener {
24	fn as_fd(&self) -> BorrowedFd<'_> {
25		self.io.get_ref().as_fd()
26	}
27}
28
29impl TryFrom<OwnedFd> for UnixSeqpacketListener {
30	type Error = std::io::Error;
31
32	fn try_from(fd: OwnedFd) -> Result<Self, Self::Error> {
33		Self::new(FileDesc::new(fd))
34	}
35}
36
37impl From<UnixSeqpacketListener> for OwnedFd {
38	fn from(socket: UnixSeqpacketListener) -> Self {
39		socket.io.into_inner().into_fd()
40	}
41}
42
43impl UnixSeqpacketListener {
44	fn new(socket: FileDesc) -> std::io::Result<Self> {
45		let io = AsyncFd::new(socket)?;
46		Ok(Self { io })
47	}
48
49	/// Bind a new seqpacket listener to the given address.
50	///
51	/// The create listener will be ready to accept new connections.
52	pub fn bind<P: AsRef<Path>>(address: P) -> std::io::Result<Self> {
53		Self::bind_with_backlog(address, 128)
54	}
55
56	/// Bind a new seqpacket listener to the given address.
57	///
58	/// The create listener will be ready to accept new connections.
59	///
60	/// The `backlog` parameter is used to determine the size of connection queue.
61	/// See `man 3 listen` for more information.
62	pub fn bind_with_backlog<P: AsRef<Path>>(address: P, backlog: c_int) -> std::io::Result<Self> {
63		let socket = sys::local_seqpacket_socket()?;
64		sys::bind(&socket, address)?;
65		sys::listen(&socket, backlog)?;
66		Self::new(socket)
67	}
68
69	/// Wrap a raw file descriptor as [`UnixSeqpacket`].
70	///
71	/// Registration of the file descriptor with the tokio runtime may fail.
72	/// For that reason, this function returns a [`std::io::Result`].
73	///
74	/// # Safety
75	/// This function is unsafe because the socket assumes it is the sole owner of the file descriptor.
76	/// Usage of this function could accidentally allow violating this contract
77	/// which can cause memory unsafety in code that relies on it being true.
78	pub unsafe fn from_raw_fd(fd: std::os::unix::io::RawFd) -> std::io::Result<Self> {
79		Self::new(FileDesc::from_raw_fd(fd))
80	}
81
82	/// Get the raw file descriptor of the socket.
83	pub fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
84		self.io.as_raw_fd()
85	}
86
87	/// Deregister the socket from the tokio runtime and return the inner file descriptor.
88	pub fn into_raw_fd(self) -> std::os::unix::io::RawFd {
89		self.io.into_inner().into_raw_fd()
90	}
91
92	/// Get the socket address of the local half of this connection.
93	pub fn local_addr(&self) -> std::io::Result<PathBuf> {
94		sys::get_local_address(self.io.get_ref())
95	}
96
97	/// Get and clear the value of the `SO_ERROR` option.
98	pub fn take_error(&self) -> std::io::Result<Option<std::io::Error>> {
99		sys::take_socket_error(self.io.get_ref())
100	}
101
102	/// Check if there is a connection ready to accept.
103	///
104	/// Note that unlike [`Self::accept`], only the last task calling this function will be woken up.
105	/// For that reason, it is preferable to use the async functions rather than polling functions when possible.
106	///
107	/// Note that this function does not return a remote address for the accepted connection.
108	/// This is because connected Unix sockets are anonymous and have no meaningful address.
109	pub fn poll_accept(&mut self, cx: &mut Context) -> Poll<std::io::Result<UnixSeqpacket>> {
110		let socket = loop {
111			let mut ready_guard = ready!(self.io.poll_read_ready(cx)?);
112
113			match ready_guard.try_io(|inner| sys::accept(inner.get_ref())) {
114				Ok(x) => break x?,
115				Err(_would_block) => continue,
116			}
117		};
118
119		Poll::Ready(Ok(UnixSeqpacket::new(socket)?))
120	}
121
122	/// Accept a new incoming connection on the listener.
123	///
124	/// This function is safe to call concurrently from different tasks.
125	/// Although no order is guaranteed, all calling tasks will try to complete the asynchronous action.
126	///
127	/// Note that this function does not return a remote address for the accepted connection.
128	/// This is because connected Unix sockets are anonymous and have no meaningful address.
129	pub async fn accept(&mut self) -> std::io::Result<UnixSeqpacket> {
130		let socket = loop {
131			let mut ready_guard = self.io.readable().await?;
132
133			match ready_guard.try_io(|inner| sys::accept(inner.get_ref())) {
134				Ok(x) => break x?,
135				Err(_would_block) => continue,
136			}
137		};
138
139		UnixSeqpacket::new(socket)
140	}
141}
142
143impl AsRawFd for UnixSeqpacketListener {
144	fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
145		self.as_raw_fd()
146	}
147}
148
149impl IntoRawFd for UnixSeqpacketListener {
150	fn into_raw_fd(self) -> std::os::unix::io::RawFd {
151		self.into_raw_fd()
152	}
153}