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_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
17/// A registry of abstract sockets.
18///
19/// AF_UNIX sockets can be bound either to nodes in the file system or to
20/// abstract addresses that are independent of the file system. This object
21/// holds the bindings to abstract addresses.
22///
23/// See "abstract" in https://man7.org/linux/man-pages/man7/unix.7.html
24pub 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}