starnix_core/task/
abstract_socket_namespace.rs1use starnix_rcu::RcuReadScope;
6use starnix_rcu::rcu_hash_map::{Entry, RcuHashMap};
7use std::sync::{Arc, Weak};
8
9use crate::task::CurrentTask;
10use crate::vfs::FsString;
11use crate::vfs::socket::{Socket, SocketAddress, SocketHandle};
12use starnix_sync::{FileOpsCore, LockEqualOrBefore, Locked};
13use starnix_uapi::errors::Errno;
14use starnix_uapi::{errno, error};
15
16pub struct AbstractSocketNamespace<K>
24where
25 K: std::cmp::Eq + std::hash::Hash + Clone + Send + Sync + 'static,
26{
27 table: RcuHashMap<K, Weak<Socket>>,
28 address_maker: Box<dyn Fn(K) -> SocketAddress + Send + Sync>,
29}
30
31pub type AbstractUnixSocketNamespace = AbstractSocketNamespace<FsString>;
32pub type AbstractVsockSocketNamespace = AbstractSocketNamespace<u32>;
33
34impl<K> AbstractSocketNamespace<K>
35where
36 K: std::cmp::Eq + std::hash::Hash + Clone + Send + Sync + 'static,
37{
38 pub fn new(
39 address_maker: Box<dyn Fn(K) -> SocketAddress + Send + Sync>,
40 ) -> Arc<AbstractSocketNamespace<K>> {
41 Arc::new(AbstractSocketNamespace::<K> { table: RcuHashMap::default(), address_maker })
42 }
43
44 pub fn bind<L>(
45 &self,
46 locked: &mut Locked<L>,
47 current_task: &CurrentTask,
48 address: K,
49 socket: &SocketHandle,
50 ) -> Result<(), Errno>
51 where
52 L: LockEqualOrBefore<FileOpsCore>,
53 {
54 let locked = locked.cast_locked::<FileOpsCore>();
55 let mut table = self.table.lock();
56 match table.entry(address.clone()) {
57 Entry::Vacant(entry) => {
58 socket.bind(locked, current_task, (self.address_maker)(address))?;
59 entry.insert(Arc::downgrade(socket));
60 }
61 Entry::Occupied(mut entry) => {
62 let occupant = entry.get().upgrade();
63 if occupant.is_some() {
64 return error!(EADDRINUSE);
65 }
66 socket.bind(locked, current_task, (self.address_maker)(address))?;
67 entry.insert(Arc::downgrade(socket));
68 }
69 }
70 Ok(())
71 }
72
73 pub fn lookup<Q: ?Sized>(&self, address: &Q) -> Result<SocketHandle, Errno>
74 where
75 K: std::borrow::Borrow<Q>,
76 Q: std::hash::Hash + Eq,
77 {
78 let scope = RcuReadScope::new();
79 self.table
80 .get(&scope, address)
81 .and_then(|weak| weak.upgrade())
82 .ok_or_else(|| errno!(ECONNREFUSED))
83 }
84}