Skip to main content

starnix_core/task/
abstract_socket_namespace.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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_uapi::errors::Errno;
13use starnix_uapi::{errno, error};
14
15/// A registry of abstract sockets.
16///
17/// AF_UNIX sockets can be bound either to nodes in the file system or to
18/// abstract addresses that are independent of the file system. This object
19/// holds the bindings to abstract addresses.
20///
21/// See "abstract" in https://man7.org/linux/man-pages/man7/unix.7.html
22pub struct AbstractSocketNamespace<K>
23where
24    K: std::cmp::Eq + std::hash::Hash + Clone + Send + Sync + 'static,
25{
26    table: RcuHashMap<K, Weak<Socket>>,
27    address_maker: Box<dyn Fn(K) -> SocketAddress + Send + Sync>,
28}
29
30pub type AbstractUnixSocketNamespace = AbstractSocketNamespace<FsString>;
31pub type AbstractVsockSocketNamespace = AbstractSocketNamespace<u32>;
32
33impl<K> AbstractSocketNamespace<K>
34where
35    K: std::cmp::Eq + std::hash::Hash + Clone + Send + Sync + 'static,
36{
37    pub fn new(
38        address_maker: Box<dyn Fn(K) -> SocketAddress + Send + Sync>,
39    ) -> Arc<AbstractSocketNamespace<K>> {
40        Arc::new(AbstractSocketNamespace::<K> { table: RcuHashMap::default(), address_maker })
41    }
42
43    pub fn bind(
44        &self,
45        current_task: &CurrentTask,
46        address: K,
47        socket: &SocketHandle,
48    ) -> Result<(), Errno> {
49        let mut table = self.table.lock();
50        match table.entry(address.clone()) {
51            Entry::Vacant(entry) => {
52                socket.bind(current_task, (self.address_maker)(address))?;
53                entry.insert(Arc::downgrade(socket));
54            }
55            Entry::Occupied(mut entry) => {
56                let occupant = entry.get().upgrade();
57                if occupant.is_some() {
58                    return error!(EADDRINUSE);
59                }
60                socket.bind(current_task, (self.address_maker)(address))?;
61                entry.insert(Arc::downgrade(socket));
62            }
63        }
64        Ok(())
65    }
66
67    pub fn lookup<Q: ?Sized>(&self, address: &Q) -> Result<SocketHandle, Errno>
68    where
69        K: std::borrow::Borrow<Q>,
70        Q: std::hash::Hash + Eq,
71    {
72        let scope = RcuReadScope::new();
73        self.table
74            .get(&scope, address)
75            .and_then(|weak| weak.upgrade())
76            .ok_or_else(|| errno!(ECONNREFUSED))
77    }
78}