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