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 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
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 + 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}