starnix_core/task/
abstract_socket_namespace.rs1use crate::task::CurrentTask;
6use crate::vfs::FsString;
7use crate::vfs::socket::{Socket, SocketAddress, SocketHandle};
8use fuchsia_rcu::RcuDroppable;
9use starnix_rcu::RcuReadScope;
10use starnix_rcu::rcu_hash_map::{Entry, RcuHashMap};
11use starnix_sync::AbstractSocketNamespaceLock;
12use starnix_uapi::errors::Errno;
13use starnix_uapi::{errno, error};
14use std::sync::{Arc, Weak};
15
16pub struct AbstractSocketNamespace<K>
24where
25 K: std::cmp::Eq + std::hash::Hash + Clone + RcuDroppable + Sync,
26{
27 table: RcuHashMap<K, Weak<Socket>, AbstractSocketNamespaceLock>,
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 + RcuDroppable + Sync,
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::new(), address_maker })
42 }
43
44 pub fn bind(
45 &self,
46 current_task: &CurrentTask,
47 address: K,
48 socket: &SocketHandle,
49 ) -> Result<(), Errno> {
50 let mut table = self.table.lock();
51 match table.entry(address.clone()) {
52 Entry::Vacant(entry) => {
53 socket.bind(current_task, (self.address_maker)(address))?;
54 entry.insert(Arc::downgrade(socket));
55 }
56 Entry::Occupied(mut entry) => {
57 let occupant = entry.get().upgrade();
58 if occupant.is_some() {
59 return error!(EADDRINUSE);
60 }
61 socket.bind(current_task, (self.address_maker)(address))?;
62 entry.insert(Arc::downgrade(socket));
63 }
64 }
65 Ok(())
66 }
67
68 pub fn lookup<Q: ?Sized>(&self, address: &Q) -> Result<SocketHandle, Errno>
69 where
70 K: std::borrow::Borrow<Q>,
71 Q: std::hash::Hash + Eq,
72 {
73 let scope = RcuReadScope::new();
74 self.table
75 .get(&scope, address)
76 .and_then(|weak| weak.upgrade())
77 .ok_or_else(|| errno!(ECONNREFUSED))
78 }
79}