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_sync::{FileOpsCore, LockEqualOrBefore, Locked};
13use starnix_uapi::errors::Errno;
14use starnix_uapi::{errno, error};
15
16/// A registry of abstract sockets.
17///
18/// AF_UNIX sockets can be bound either to nodes in the file system or to
19/// abstract addresses that are independent of the file system. This object
20/// holds the bindings to abstract addresses.
21///
22/// See "abstract" in https://man7.org/linux/man-pages/man7/unix.7.html
23pub 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}