1pub(crate) mod dgram;
21pub mod namespace;
22pub(crate) mod stream;
23
24use alloc::sync::Arc;
25
26use ax_io::{IoBuf, Read, Write};
27use ax_lazyinit::LazyLock;
28use ax_sync::SpinLock;
29use axpoll::{ExclusiveRegistrationSink, IoEvents, Pollable, SharedRegistrationSink};
30use axpoll_set::PollSet;
31use enum_dispatch::enum_dispatch;
32use hashbrown::HashMap;
33
34pub use self::{
35 dgram::DgramTransport,
36 namespace::{UnixNamespace, register_unix_namespace},
37 stream::StreamTransport,
38};
39use crate::{
40 ConnectStatus, NetError, NetResult, RecvOptions, SendOptions, Shutdown, Socket, SocketAddrEx,
41 SocketOps,
42 options::{Configurable, GetSocketOption, SetSocketOption},
43};
44
45#[derive(Default, Clone, Debug)]
47pub enum UnixSocketAddr {
48 #[default]
50 Unnamed,
51 Abstract(Arc<[u8]>),
53 Path(Arc<str>),
55}
56
57#[enum_dispatch]
59pub trait TransportOps: Configurable + Pollable + Send + Sync {
60 fn bind(&self, slot: &BindSlot, local_addr: &UnixSocketAddr) -> NetResult;
62 fn connect(
65 &self,
66 slot: &BindSlot,
67 local_addr: &UnixSocketAddr,
68 ) -> NetResult<Option<Arc<PollSet>>>;
69
70 fn listen(&self) -> NetResult {
72 Err(NetError::OperationNotSupported)
73 }
74
75 fn is_listening(&self) -> bool {
77 false
78 }
79
80 fn try_accept(&self) -> NetResult<(Transport, UnixSocketAddr)> {
82 Err(NetError::WouldBlock)
83 }
84
85 fn try_send(&self, src: impl Read + IoBuf, options: &mut SendOptions) -> NetResult<usize>;
87 fn try_recv(&self, dst: impl Write, options: &mut RecvOptions<'_>) -> NetResult<usize>;
89
90 fn shutdown(&self, _how: Shutdown) -> NetResult {
92 Ok(())
93 }
94}
95
96#[enum_dispatch(Configurable, TransportOps)]
98pub enum Transport {
99 Stream(StreamTransport),
101 Dgram(DgramTransport),
103}
104impl Transport {
105 fn finish_connect(&self, accept_poll: Option<Arc<PollSet>>) {
106 if let Some(poll) = accept_poll {
107 unsafe { poll.wake(IoEvents::IN) };
110 }
111 match self {
112 Transport::Stream(stream) => stream.wake_connected(),
113 Transport::Dgram(dgram) => dgram.wake_connected(),
114 }
115 }
116}
117impl Pollable for Transport {
118 fn poll(&self) -> IoEvents {
119 match self {
120 Transport::Stream(stream) => stream.poll(),
121 Transport::Dgram(dgram) => dgram.poll(),
122 }
123 }
124
125 unsafe fn register_shared(&self, sink: &mut dyn SharedRegistrationSink, events: IoEvents) {
126 match self {
127 Transport::Stream(stream) => unsafe { stream.register_shared(sink, events) },
128 Transport::Dgram(dgram) => unsafe { dgram.register_shared(sink, events) },
129 }
130 }
131
132 unsafe fn register_exclusive(
133 &self,
134 sink: &mut dyn ExclusiveRegistrationSink,
135 events: IoEvents,
136 ) {
137 match self {
138 Transport::Stream(stream) => unsafe { stream.register_exclusive(sink, events) },
139 Transport::Dgram(dgram) => unsafe { dgram.register_exclusive(sink, events) },
140 }
141 }
142}
143
144#[derive(Default)]
146pub struct BindSlot {
147 stream: SpinLock<Option<stream::Bind>>,
149 dgram: SpinLock<Option<dgram::Bind>>,
151 seqpacket: SpinLock<Option<dgram::SeqBind>>,
155}
156
157static ABSTRACT_BINDS: LazyLock<SpinLock<HashMap<Arc<[u8]>, BindSlot>>> =
158 LazyLock::new(|| SpinLock::new(HashMap::new()));
159
160pub(crate) fn with_slot<R>(
162 addr: &UnixSocketAddr,
163 f: impl FnOnce(&BindSlot) -> NetResult<R>,
164) -> NetResult<R> {
165 match addr {
166 UnixSocketAddr::Unnamed => Err(NetError::InvalidInput),
167 UnixSocketAddr::Abstract(name) => {
168 let binds = ABSTRACT_BINDS.lock();
169 if let Some(slot) = binds.get(name) {
170 f(slot)
171 } else {
172 Err(NetError::NotFound)
173 }
174 }
175 UnixSocketAddr::Path(path) => namespace::with_namespace(|ns| {
176 let slot = ns.resolve(path.as_ref())?;
177 f(slot.as_ref())
178 }),
179 }
180}
181fn with_slot_or_insert<R>(
183 addr: &UnixSocketAddr,
184 f: impl FnOnce(&BindSlot) -> NetResult<R>,
185) -> NetResult<R> {
186 match addr {
187 UnixSocketAddr::Unnamed => Err(NetError::InvalidInput),
188 UnixSocketAddr::Abstract(name) => {
189 let mut binds = ABSTRACT_BINDS.lock();
190 f(binds.entry(name.clone()).or_default())
191 }
192 UnixSocketAddr::Path(path) => namespace::with_namespace(|ns| {
193 let slot = ns.bind(path.as_ref())?;
194 f(slot.as_ref())
195 }),
196 }
197}
198
199pub struct UnixSocket {
201 transport: Transport,
203 local_addr: SpinLock<UnixSocketAddr>,
205 remote_addr: SpinLock<UnixSocketAddr>,
207}
208impl UnixSocket {
209 pub fn new(transport: impl Into<Transport>) -> Self {
211 Self {
212 transport: transport.into(),
213 local_addr: SpinLock::new(UnixSocketAddr::Unnamed),
214 remote_addr: SpinLock::new(UnixSocketAddr::Unnamed),
215 }
216 }
217}
218impl Configurable for UnixSocket {
219 fn get_option_inner(&self, opt: &mut GetSocketOption) -> NetResult<bool> {
220 self.transport.get_option_inner(opt)
221 }
222
223 fn set_option_inner(&self, opt: SetSocketOption) -> NetResult<bool> {
224 self.transport.set_option_inner(opt)
225 }
226}
227impl SocketOps for UnixSocket {
228 fn bind(&self, local_addr: SocketAddrEx) -> NetResult {
229 let local_addr = local_addr.into_unix()?;
230 let mut guard = self.local_addr.lock();
231 if matches!(&*guard, UnixSocketAddr::Unnamed) {
232 with_slot_or_insert(&local_addr, |slot| self.transport.bind(slot, &local_addr))?;
233 *guard = local_addr;
234 } else {
235 return Err(NetError::InvalidInput);
236 }
237 Ok(())
238 }
239
240 fn start_connect(&self, remote_addr: SocketAddrEx) -> NetResult<ConnectStatus> {
241 let remote_addr = remote_addr.into_unix()?;
242 let local_addr = self.local_addr.lock().clone();
243 let accept_poll = {
244 let mut guard = self.remote_addr.lock();
245 if !matches!(&*guard, UnixSocketAddr::Unnamed) {
246 return Err(NetError::InvalidInput);
247 }
248 let accept_poll = with_slot(&remote_addr, |slot| {
249 self.transport.connect(slot, &local_addr)
250 })?;
251 *guard = remote_addr;
252 accept_poll
253 };
254 self.transport.finish_connect(accept_poll);
255 Ok(ConnectStatus::Connected)
256 }
257
258 fn listen(&self, _backlog: usize) -> NetResult {
259 self.transport.listen()
260 }
261
262 fn is_listening(&self) -> bool {
263 self.transport.is_listening()
264 }
265
266 fn try_accept(&self) -> NetResult<Socket> {
267 let (transport, peer_addr) = self.transport.try_accept()?;
268 Ok(Self {
269 transport,
270 local_addr: SpinLock::new(self.local_addr.lock().clone()),
271 remote_addr: SpinLock::new(peer_addr),
272 }
273 .into())
274 }
275
276 fn try_send(&self, src: impl Read + IoBuf, options: &mut SendOptions) -> NetResult<usize> {
277 self.transport.try_send(src, options)
278 }
279
280 fn try_recv(&self, dst: impl Write, options: &mut RecvOptions<'_>) -> NetResult<usize> {
281 self.transport.try_recv(dst, options)
282 }
283
284 fn local_addr(&self) -> NetResult<SocketAddrEx> {
285 Ok(SocketAddrEx::Unix(self.local_addr.lock().clone()))
286 }
287
288 fn peer_addr(&self) -> NetResult<SocketAddrEx> {
289 Ok(SocketAddrEx::Unix(self.remote_addr.lock().clone()))
290 }
291
292 fn shutdown(&self, how: Shutdown) -> NetResult {
293 self.transport.shutdown(how)
294 }
295}
296
297impl Pollable for UnixSocket {
298 fn poll(&self) -> IoEvents {
299 self.transport.poll()
300 }
301
302 unsafe fn register_shared(&self, sink: &mut dyn SharedRegistrationSink, events: IoEvents) {
303 unsafe { self.transport.register_shared(sink, events) };
304 }
305
306 unsafe fn register_exclusive(
307 &self,
308 sink: &mut dyn ExclusiveRegistrationSink,
309 events: IoEvents,
310 ) {
311 unsafe { self.transport.register_exclusive(sink, events) };
312 }
313}